- 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:
--
-
- NetworkManager for wifi -
- dhcpcd for DHCP -
- resolvconf for DNS -
- a "legacy script based system" for network configuration[1] -
We'll be replacing it with:
--
-
- iwd for wifi -
- systemd-networkd for DHCP and network configuration -
- systemd-resolved for DNS -
- 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:
-{
+
+ 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:
+
+ - NetworkManager for wifi
+ - dhcpcd for DHCP
+ - resolvconf for DNS
+ - a "legacy script based system" for network configuration[1]
+
+ We'll be replacing it with:
+
+ - iwd for wifi
+ - systemd-networkd for DHCP and network configuration
+ - systemd-resolved for DNS
+
+
+ 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 ;
@@ -55,14 +52,14 @@
};
}
- And let's get to configuring!
+ 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.
-
- {
+ 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 = {
@@ -76,28 +73,28 @@
};
}
-
- 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:
-
-
- iwctl station wlan0 scan: Scans for new wifi networks
- iwctl station wlan0 get-networks: lists the networks that it found
- iwctl station wlan0 connect "<SSID>": connects to the network, prompting for a PSK if necessary
-
-
- 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.
-
- {
+
+ 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:
+
+
+ iwctl station wlan0 scan : Scans for new wifi networks
+ iwctl station wlan0 get-networks : lists the networks that it found
+ iwctl station wlan0 connect "<SSID>" : connects to the network, prompting for a PSK if necessary
+
+
+ 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 ;
@@ -113,27 +110,28 @@
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:
-
- ip addr: make sure that there's an IP address associated with your wireless interface. That means DHCP is working.
- networkctl status: make sure there's no significant errors in the logs.
-
-
- 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.
-
- {
+
+ 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:
+
+ ip addr : make sure that there's an IP address associated with your wireless interface. That means DHCP is working.
+ networkctl status : make sure there's no significant errors in the logs.
+
+
+ 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"
@@ -151,23 +149,25 @@
};
}
- 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.
-
-
-
-
\ No newline at end of file
+ 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.
+
+
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. -