From 8964e6218f3257aeaf0c184e4895e2f8bf317c9f Mon Sep 17 00:00:00 2001 From: Collin Williams <96917990+bluedragon1221@users.noreply.github.com> Date: Sat, 22 Aug 2026 17:17:49 -0500 Subject: update css, rename article, move assets to selfhosted --- Logo.svg | 18 ---- article.js | 20 ++--- fonts.css | 37 --------- fonts/FiraCode-VF.woff2 | Bin 113088 -> 0 bytes fonts/FiraMath-Regular.woff2 | Bin 99332 -> 0 bytes fonts/gelasio-latin-italic.woff2 | Bin 40068 -> 0 bytes fonts/gelasio-latin.woff2 | Bin 34832 -> 0 bytes index.html | 2 +- minimalnetworkinglaptop.html | 173 --------------------------------------- net.html | 173 +++++++++++++++++++++++++++++++++++++++ prose.css | 79 ++++++++++++------ style.css | 2 +- writing.html | 12 +-- 13 files changed, 242 insertions(+), 274 deletions(-) delete mode 100644 Logo.svg delete mode 100644 fonts.css delete mode 100644 fonts/FiraCode-VF.woff2 delete mode 100644 fonts/FiraMath-Regular.woff2 delete mode 100644 fonts/gelasio-latin-italic.woff2 delete mode 100644 fonts/gelasio-latin.woff2 delete mode 100644 minimalnetworkinglaptop.html create mode 100644 net.html diff --git a/Logo.svg b/Logo.svg deleted file mode 100644 index 77eb306..0000000 --- a/Logo.svg +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/article.js b/article.js index 292d61c..2a495c4 100644 --- a/article.js +++ b/article.js @@ -2,7 +2,7 @@ function addMetadata() { // Favicon const favicon = document.createElement("link"); favicon.rel = "icon"; - favicon.href = "/Logo.svg"; + favicon.href = "https://static.williamsfam.us.com/Logo.svg"; favicon.type = "image/svg+xml"; document.head.appendChild(favicon); @@ -27,20 +27,19 @@ function addMetadata() { function addHeader() { const header = document.querySelector("header"); - // Logo + const headerTop = document.createElement("div"); + headerTop.classList.add("header-top"); + const logoLink = document.createElement("a"); - logoLink.href = "/writing.html"; + logoLink.href = "writing"; logoLink.classList.add("header-logo-link"); - header.appendChild(logoLink); + headerTop.appendChild(logoLink); - // Right-side content const info = document.createElement("div"); info.classList.add("header-info"); - const h1 = document.createElement("h1"); h1.textContent = document.title; info.appendChild(h1); - const time = document.createElement("time"); const metaDate = document.querySelector('meta[property="article:published_time"]'); const dateString = metaDate.getAttribute("content"); @@ -50,12 +49,11 @@ function addHeader() { year: "numeric", timeZone: "UTC" }); - time.setAttribute("datetime", dateString); time.textContent = `Published ${displayDate}`; info.appendChild(time); - - header.appendChild(info); + headerTop.appendChild(info); + header.appendChild(headerTop); const hr = document.createElement("hr"); header.appendChild(hr); @@ -89,4 +87,4 @@ document.addEventListener("DOMContentLoaded", () => { addMetadata() addHeader() addTOC() -}) \ No newline at end of file +}) diff --git a/fonts.css b/fonts.css deleted file mode 100644 index 7ce76d4..0000000 --- a/fonts.css +++ /dev/null @@ -1,37 +0,0 @@ -@font-face { - font-family: "Gelasio"; - font-style: normal; - font-weight: 400 700; - font-display: swap; - src: url("/fonts/gelasio-latin.woff2") format("woff2"); -} - -@font-face { - font-family: "Gelasio"; - font-style: italic; - font-weight: 400 700; - font-display: swap; - src: url("/fonts/gelasio-latin-italic.woff2") format("woff2"); -} - -@font-face { - font-family: "Fira Math"; - src: url("/fonts/FiraMath-Regular.woff2") format("woff2"); - font-weight: 400; - font-style: normal; - font-display: swap; -} - -@font-face { - font-family: "Fira Code"; - src: url("/fonts/FiraCode-VF.woff2") format("woff2"); - font-style: normal; - font-weight: 300 700; - font-display: swap; -} - -:root { - --fontSerif: 'Gelasio', serif; - --fontMono: 'Fira Code', monospace; - --fontMath: 'Fira Math', serif; -} \ No newline at end of file diff --git a/fonts/FiraCode-VF.woff2 b/fonts/FiraCode-VF.woff2 deleted file mode 100644 index e755a9d..0000000 Binary files a/fonts/FiraCode-VF.woff2 and /dev/null differ diff --git a/fonts/FiraMath-Regular.woff2 b/fonts/FiraMath-Regular.woff2 deleted file mode 100644 index fd08e65..0000000 Binary files a/fonts/FiraMath-Regular.woff2 and /dev/null differ diff --git a/fonts/gelasio-latin-italic.woff2 b/fonts/gelasio-latin-italic.woff2 deleted file mode 100644 index 7f95e1d..0000000 Binary files a/fonts/gelasio-latin-italic.woff2 and /dev/null differ diff --git a/fonts/gelasio-latin.woff2 b/fonts/gelasio-latin.woff2 deleted file mode 100644 index fe18998..0000000 Binary files a/fonts/gelasio-latin.woff2 and /dev/null differ diff --git a/index.html b/index.html index f12f9fd..b3836ad 100644 --- a/index.html +++ b/index.html @@ -43,7 +43,7 @@
Bluesky Tangled - Writing + Writing
diff --git a/minimalnetworkinglaptop.html b/minimalnetworkinglaptop.html deleted file mode 100644 index bc07c9b..0000000 --- a/minimalnetworkinglaptop.html +++ /dev/null @@ -1,173 +0,0 @@ - - - - Minimal Laptop Networking with NixOS - - - - -
-
- -

- The default networking stack on NixOS uses NetworkManager. - While it's a great choice for many users, I prefer a lighter setup built around systemd-networkd, systemd-resolved, and iwd. It integrates well with the rest of the systemd stack, has fewer moving pieces, and exposes powerful networking features without an additional network management daemon. -

- -

- This article focuses on laptops that connect to wifi. - If you're configuring a server, you probably don't need iwd at all; systemd-networkd and systemd-resolved are usually sufficient. -

- -
- -

The default stack

-

If not configured otherwise, NixOS uses the following stack:

- -

We'll be replacing it with:

- -

- This has a few benefits. - Firstly, switching to resolved allows you to enable features like encrypted DNS over TLS (DoT) and DNSSEC validation, which reduces the potential for DNS spoofing and man-in-the-middle attacks[2]. - Additionally, the default stack uses 3 extra packages (NM, dhcpcd, resolvconf) and some bash scripts, while this setup only uses one extra package (iwd). - Also, I'm kind of a systemd nerd, and this is a way to dig into systemd a bit more. -

- -

So the first thing we can do is disable all of the default stuff:

-
{
-  networking = {
-    networkmanager.enable = false;
-    dhcpcd.enable = false;
-    resolvconf.enable = false;
-    networking.useDHCP = false;
-  };
-}
- -

And let's get to configuring!

- -

iwd

-

- First up is iwd. - The important parts of the configuration are delegating network configuration to networkd, delegating name resolution (DNS) to resolved, and configuring MAC randomization for some extra privacy. -

-
{
-  networking.wireless.iwd = {
-    enable = true;
-    settings = {
-      General = {
-        EnableNetworkConfiguration = false; # delegated to networkd
-        AddressRandomization = "once";
-        AddressRandomizationRange = "full";
-      };
-      Network.NameResolvingService = "systemd"; # use systemd-resolved
-    };
-  };
-}
- -

- At this point, we don't have any network configuration yet, so internet access won't work. However, you can verify that iwd is functioning correctly: -

- - -

systemd-networkd

-

- Next up is systemd-networkd. - Networkd has lots of advanced options for things like static IP config, Wireguard tunnels, VLANs, domain-based DNS routing, and more. - However, here we'll just do a basic configuration to enable DHCP and deny DHCP-advertised DNS. -

-
- why disable DHCP-advertised DNS? - By default, most networks advertise their own DNS resolver via DHCP. - Since we'll configure our own encrypted upstream DNS servers in the next section, we tell networkd to ignore the ones provided by the network. -
- -
{
-  systemd.network = {
-    enable = true;
-
-    networks."11-default" = {
-      name = "wl*";
-      networkConfig.DHCP = "yes";
-
-      # never accept dhcp dns
-      dhcpV4Config.UseDNS = "no";
-      dhcpV6Config.UseDNS = "no";
-    };
-  };
-  networking.useNetworkd = true;
-}
- -

- The name = "wl*" - refers to the network interface name that this configuration applies to. - According to the systemd docs, wireless LAN devices should start with the two-character prefix "wl"[3]. - Here we use a glob (*) to match all wireless interfaces. -

- -

You can verify that your configuration worked with a few commands:

- - -

systemd-resolved

-

- Now all we have left is DNS configuration, then we're done. - This is probably the part where you can nerd out the hardest, but I try to keep it pretty minimal. - The important parts are selecting upstream DNS servers that support secure DNS protocols (like DNS over TLS and DNSSEC) and that respect your privacy. - For these reasons, I use quad9, but do your own research and find the best upstream DNS server for you! - Some other options include Cloudflare DNS, Google's DNS, or AdGuard Public DNS. -

-
{
-  networking.nameservers = [
-    "9.9.9.9#dns.quad9.net"
-    "149.112.112.112#dns.quad9.net"
-  ];
-
-  services.resolved = {
-    enable = true;
-    settings.Resolve = {
-      DNSOverTLS = true;
-      DNSSEC = "allow-downgrade";
-
-      LLMNR = false;
-      MulticastDNS = false;
-    };
-  };
-}
- -

You can verify your DNS configuration by using the resolvectl status - command or by just opening a website.

- -

P.S. Captive portals

-

- Captive portals are those wifi login pages that pop up when you connect to some public wifi networks. - Some captive portals don't behave correctly when you're using an encrypted third-party DNS server instead of the network's advertised resolver. - To get around this, I use Captive Browser - (nixpkgs), which launches an instance of Chromium through a SOCKS5 proxy, avoiding the system DNS configuration altogether. - This allows you to access a captive portal for long enough to log in and gain internet access. - Pretty neat! -

- -

P.P.S. I miss nm-applet

-

- Probably the biggest downside to this setup is the lack of desktop integration. - GNOME and Plasma only support NetworkManager in their network configuration menu, so you're kinda out of luck. - For tiling window manager people, I can recommend iwmenu, which is a launcher (dmenu, rofi, fuzzel)-based menu for connecting to wifi networks via iwd. -

-
- - diff --git a/net.html b/net.html new file mode 100644 index 0000000..bc07c9b --- /dev/null +++ b/net.html @@ -0,0 +1,173 @@ + + + + Minimal Laptop Networking with NixOS + + + + +
+
+ +

+ The default networking stack on NixOS uses NetworkManager. + While it's a great choice for many users, I prefer a lighter setup built around systemd-networkd, systemd-resolved, and iwd. It integrates well with the rest of the systemd stack, has fewer moving pieces, and exposes powerful networking features without an additional network management daemon. +

+ +

+ This article focuses on laptops that connect to wifi. + If you're configuring a server, you probably don't need iwd at all; systemd-networkd and systemd-resolved are usually sufficient. +

+ +
+ +

The default stack

+

If not configured otherwise, NixOS uses the following stack:

+ +

We'll be replacing it with:

+ +

+ This has a few benefits. + Firstly, switching to resolved allows you to enable features like encrypted DNS over TLS (DoT) and DNSSEC validation, which reduces the potential for DNS spoofing and man-in-the-middle attacks[2]. + Additionally, the default stack uses 3 extra packages (NM, dhcpcd, resolvconf) and some bash scripts, while this setup only uses one extra package (iwd). + Also, I'm kind of a systemd nerd, and this is a way to dig into systemd a bit more. +

+ +

So the first thing we can do is disable all of the default stuff:

+
{
+  networking = {
+    networkmanager.enable = false;
+    dhcpcd.enable = false;
+    resolvconf.enable = false;
+    networking.useDHCP = false;
+  };
+}
+ +

And let's get to configuring!

+ +

iwd

+

+ First up is iwd. + The important parts of the configuration are delegating network configuration to networkd, delegating name resolution (DNS) to resolved, and configuring MAC randomization for some extra privacy. +

+
{
+  networking.wireless.iwd = {
+    enable = true;
+    settings = {
+      General = {
+        EnableNetworkConfiguration = false; # delegated to networkd
+        AddressRandomization = "once";
+        AddressRandomizationRange = "full";
+      };
+      Network.NameResolvingService = "systemd"; # use systemd-resolved
+    };
+  };
+}
+ +

+ At this point, we don't have any network configuration yet, so internet access won't work. However, you can verify that iwd is functioning correctly: +

+ + +

systemd-networkd

+

+ Next up is systemd-networkd. + Networkd has lots of advanced options for things like static IP config, Wireguard tunnels, VLANs, domain-based DNS routing, and more. + However, here we'll just do a basic configuration to enable DHCP and deny DHCP-advertised DNS. +

+
+ why disable DHCP-advertised DNS? + By default, most networks advertise their own DNS resolver via DHCP. + Since we'll configure our own encrypted upstream DNS servers in the next section, we tell networkd to ignore the ones provided by the network. +
+ +
{
+  systemd.network = {
+    enable = true;
+
+    networks."11-default" = {
+      name = "wl*";
+      networkConfig.DHCP = "yes";
+
+      # never accept dhcp dns
+      dhcpV4Config.UseDNS = "no";
+      dhcpV6Config.UseDNS = "no";
+    };
+  };
+  networking.useNetworkd = true;
+}
+ +

+ The name = "wl*" + refers to the network interface name that this configuration applies to. + According to the systemd docs, wireless LAN devices should start with the two-character prefix "wl"[3]. + Here we use a glob (*) to match all wireless interfaces. +

+ +

You can verify that your configuration worked with a few commands:

+ + +

systemd-resolved

+

+ Now all we have left is DNS configuration, then we're done. + This is probably the part where you can nerd out the hardest, but I try to keep it pretty minimal. + The important parts are selecting upstream DNS servers that support secure DNS protocols (like DNS over TLS and DNSSEC) and that respect your privacy. + For these reasons, I use quad9, but do your own research and find the best upstream DNS server for you! + Some other options include Cloudflare DNS, Google's DNS, or AdGuard Public DNS. +

+
{
+  networking.nameservers = [
+    "9.9.9.9#dns.quad9.net"
+    "149.112.112.112#dns.quad9.net"
+  ];
+
+  services.resolved = {
+    enable = true;
+    settings.Resolve = {
+      DNSOverTLS = true;
+      DNSSEC = "allow-downgrade";
+
+      LLMNR = false;
+      MulticastDNS = false;
+    };
+  };
+}
+ +

You can verify your DNS configuration by using the resolvectl status + command or by just opening a website.

+ +

P.S. Captive portals

+

+ Captive portals are those wifi login pages that pop up when you connect to some public wifi networks. + Some captive portals don't behave correctly when you're using an encrypted third-party DNS server instead of the network's advertised resolver. + To get around this, I use Captive Browser + (nixpkgs), which launches an instance of Chromium through a SOCKS5 proxy, avoiding the system DNS configuration altogether. + This allows you to access a captive portal for long enough to log in and gain internet access. + Pretty neat! +

+ +

P.P.S. I miss nm-applet

+

+ Probably the biggest downside to this setup is the lack of desktop integration. + GNOME and Plasma only support NetworkManager in their network configuration menu, so you're kinda out of luck. + For tiling window manager people, I can recommend iwmenu, which is a launcher (dmenu, rofi, fuzzel)-based menu for connecting to wifi networks via iwd. +

+
+ + diff --git a/prose.css b/prose.css index 3a053c5..5e1819a 100644 --- a/prose.css +++ b/prose.css @@ -6,9 +6,14 @@ --lh: 1.5; } +body { + -webkit-font-smoothing: antialiased; + text-rendering: optimizeLegibility; +} + article { width: 100%; - max-width: 75ch; + max-width: 68ch; margin: 0 auto; position: relative; z-index: 1; @@ -20,6 +25,7 @@ p { line-height: var(--lh); font-size: 1.1rem; margin: var(--sx) 0; + text-wrap: pretty; } sup { @@ -37,6 +43,10 @@ a { &:hover { text-decoration: underline; } + &:focus-visible { + outline: 2px solid #49f; + outline-offset: 2px; + } } li { @@ -57,6 +67,19 @@ h1, h2, h3 { font-family: var(--fontSerif); line-height: var(--lh); font-weight: 600; + text-wrap: balance; +} + +h1 { + font-size: 2rem; +} + +h2 { + font-size: 1.5rem; +} + +h3 { + font-size: 1.25rem; } .comment { @@ -83,7 +106,6 @@ time { display: block; padding: 1rem 1rem 3rem; } - .content { padding: 0; } @@ -103,9 +125,9 @@ table { --tsx_y: calc(var(--sx) / 1.5); font-family: var(--fontSerif); - margin: var(--sx) 0; - + margin: var(--sx) auto; border-collapse: collapse; + th { color: #e6e6e6; text-align: center; @@ -117,16 +139,17 @@ table { border-width: 0 1px 0 0; } } + td { - color: #6e7; + color: #e6e6e6; text-align: center; padding: var(--tsx_x) var(--tsx_y); + font-variant-numeric: tabular-nums; } } - math { font-family: var(--fontMath); - font-size: 1.2rem; + font-size: 1em; transform: translateZ(0); msub > :nth-child(2) { @@ -134,7 +157,6 @@ math { font-size: 0.8rem; } } - /* CODEBLOCKS */ code { font-size: 0.95rem; @@ -153,32 +175,37 @@ code { mod { color: #bcd; } id { color: inherit; } } - pre { - max-width: 100%; - overflow-x: auto; - overflow-y: hidden; - box-sizing: border-box; - margin: var(--sx) 0; line-height: var(--lh); } -/* HEADER */ +@media (max-width: 1000px) { + pre { + max-width: 100%; + overflow-x: auto; + overflow-y: hidden; + box-sizing: border-box; + } +} + header { - display: grid; - grid-template-columns: auto minmax(0, 1fr); - grid-template-rows: auto auto; + display: flex; + flex-direction: column; gap: var(--sx); - .header-logo-link { - display: block; - height: 100%; - aspect-ratio: 1; + .header-top { + display: flex; + align-items: flex-start; + gap: var(--sx); + } + .header-logo-link { + width: 5.5rem; + height: 5.5rem; + flex-shrink: 0; background-color: #e6e6e6; - - mask-image: url("/Logo.svg"); + mask-image: url("https://static.williamsfam.us.com/Logo.svg"); mask-size: contain; mask-repeat: no-repeat; mask-position: center; @@ -190,7 +217,6 @@ header { .header-info { min-width: 0; - align-self: center; h1 { line-height: 1; @@ -205,7 +231,6 @@ header { hr { margin: 0; - grid-column: 1 / -1; width: 100%; } -} \ No newline at end of file +} diff --git a/style.css b/style.css index 23162b3..d815d65 100644 --- a/style.css +++ b/style.css @@ -1,4 +1,4 @@ -@import url('fonts.css'); +@import url('https://static.williamsfam.us.com/fonts.css'); *, *::before, *::after { box-sizing: border-box; diff --git a/writing.html b/writing.html index e04ebb3..126055c 100644 --- a/writing.html +++ b/writing.html @@ -18,12 +18,12 @@

My Writing

-- cgit v1.3.1