Networking and firewall
Networking and firewall
Goal: Configure lab networking deliberately—pick networkd or NetworkManager, know your address, and run a default-deny-ish firewall that still allows SSH.
Why this chapter matters
A flake host that “has SSH in config” but blocked by firewall, or random DHCP with no notes, is not operable. Networking is part of the system closure story.
Ops motivation: most “NixOS is down” tickets are network, DNS, or firewall mistakes. Declare them, test them, document them.
Theory 1 — Two common network stacks on NixOS
| Stack | Typical use | Module vibes |
|---|---|---|
| systemd-networkd | Servers, VMs, simple static | systemd.network, networking.useNetworkd |
| NetworkManager | Laptops, Wi-Fi, desktop | networking.networkmanager.enable |
Do not enable both casually without understanding conflicts. For a server-like VM, networkd or simple DHCP via networking.* is enough.
Classic DHCP simplicity
networking.useDHCP = false;
networking.interfaces.ens3.useDHCP = true; # interface name from `ip a`Or global patterns depending on release defaults—inspect generated hardware and ip a.
networkd file shape (server VM)
{
networking.useNetworkd = true;
networking.useDHCP = false;
systemd.network.networks."10-wan" = {
matchConfig.Name = "en*";
networkConfig.DHCP = "yes";
};
}Interface match patterns reduce rename pain vs hard-coding ens3 only—verify on your virt NIC names.
Theory 2 — Host identity
networking.hostName = "lab";
# networking.domain = "example.local";Hostname affects prompts, certificates later, and mental ops. Keep flake attr and hostname documented (flake hosts chapter).
Extra hosts
networking.extraHosts = ''
127.0.0.1 lab.local
10.0.0.5 sibling.lab
'';Useful for multi-VM labs; real DNS arrives with TLS/ACME later.
Theory 3 — Firewall model
NixOS firewall (iptables/nftables backend depending on config) is commonly:
networking.firewall = {
enable = true;
allowedTCPPorts = [ 22 ];
allowedUDPPorts = [ ];
# allowedTCPPortRanges = [ { from = 8000; to = 8010; } ];
};| Idea | Practice |
|---|---|
| Default deny inbound | Enable firewall |
| Open only needed ports | List explicitly |
| Per-interface rules | Advanced; later |
| Service modules open ports | Some set firewall rules when enabled |
Always ensure SSH port is allowed before testing remote-only access.
nftables awareness (26.05)
Modern NixOS often prefers nftables as the firewall backend. You rarely write raw rules by hand; you set module options and inspect:
sudo nft list ruleset | head -80
sudo iptables -L -n 2>/dev/null | head || true| Practice | Avoid |
|---|---|
| Module options + rebuild | Hand-editing live nft rules as SoT |
Document backend in docs/network.md |
Assuming iptables forever |
Theory 4 — Interface names
Predictable names (enp0s3, ens18, eth0) depend on virt hardware.
ip -br a
networkctl status # if networkd
nmcli device # if NMHard-coding the wrong interface → no network after switch. Prefer DHCP-on-all or verified names.
Theory 5 — Static addressing (optional lab)
networking.interfaces.ens3.ipv4.addresses = [{
address = "192.168.56.10";
prefixLength = 24;
}];
networking.defaultGateway = "192.168.56.1";
networking.nameservers = [ "1.1.1.1" "9.9.9.9" ];Use only when you understand the hypervisor network. Wrong gateway = silence.
Theory 6 — DNS and resolution
resolvectl status # systemd-resolved often in play
getent hosts cache.nixos.orgBroken DNS looks like “Nix is broken” during rebuilds (substituters).
| Failure | Symptom |
|---|---|
| No route | Timeouts |
| Bad DNS | NXDOMAIN / resolve fail mid-rebuild |
| Captive / filtered net | Partial substituter failures |
Theory 7 — Firewall vs service modules
Example: enabling services.openssh does not always mean you thought about firewall—on many configs you still list port 22 (or rely on module defaults). Verify:
sudo nft list ruleset | head
ss -ltnHardening deep-dives continue in the Services and security part; this chapter is correctness + minimal surface.
Theory 8 — Rebuild safety pattern for remote operators
sudo nixos-rebuild test --flake .#lab
# new shell: ssh still works?
sudo nixos-rebuild switch --flake .#labtest activates without making the generation the boot default—slightly safer while iterating firewall. Console access remains the real safety net.
Lockout drill ethics
Only lock yourself out on a VM with console + snapshot. Production requires out-of-band access plans.
Theory 9 — Port audit as continuous practice
| Listener | Firewall | Config source | Keep? |
|---|---|---|---|
:22 |
open | allowedTCPPorts / ssh |
yes |
| localhost-only | n/a | bind address | ok |
| mystery | ? | ? | investigate |
Any public listener without a story is a future ticket.
Theory 10 — Hypervisor port forwards
NAT mode often needs host port → guest 22 forward. Document:
host localhost:2222 → guest :22
ssh -p 2222 alice@127.0.0.1
Firewall on guest still applies to forwarded traffic.
Worked examples bank
Example A — Server-like DHCP + SSH
{
networking.hostName = "lab";
networking.firewall.enable = true;
networking.firewall.allowedTCPPorts = [ 22 ];
services.openssh.enable = true;
}Example B — Explicit interface DHCP
{
networking.useDHCP = false;
networking.interfaces.ens3.useDHCP = true;
}Example C — Temporary debug open (lab only)
# networking.firewall.allowedTCPPorts = [ 22 80 443 ];Remove ports you do not need.
Example D — networkd DHCP match
See Theory 1 networkd snippet.
Example E — DNS pin
networking.nameservers = [ "1.1.1.1" "9.9.9.9" ];Lab 1 — Discover ground truth
On the lab host:
ip -br a
ip route
cat /etc/hostname
resolvectl status 2>/dev/null | headRecord interface name(s), IPv4, default route.
Lab 2 — Declare firewall explicitly
In flake config:
networking.firewall.enable = true
- Allow SSH port only
- Rebuild (
testrecommended if remote)
sudo nixos-rebuild test --flake .#lab
# verify ssh still works
sudo nixos-rebuild switch --flake .#labLab 3 — Port audit
ss -ltnup
# map each listener to a reasonFill table in docs/network.md.
Lab 4 — Controlled break (console ready)
Snapshot.
- Remove 22 from
allowedTCPPortswhile SSH is your only remote path.
switch(expect lockout if no console).
- Fix via console; restore port.
If you are console-only already, simulate by checking nft counters and documenting the mistake.
Lab 5 — Network README snippet
Add to docs/network.md:
- Hypervisor network mode (NAT/bridge/host-only)
- How to find VM IP from host
- Firewall policy summary
- DNS notes
- Backend (nftables/iptables observation)
Lab 6 — Firewall rule ↔︎ listener map
Build a three-column table:
Listener (ss) |
Firewall open? | Config source |
|---|---|---|
:22 |
yes | allowedTCPPorts / ssh module |
Lab 7 — DNS failure drill (safe)
getent hosts cache.nixos.orgDocument: rebuilds that need substitutes fail hard when DNS dies mid-flight—order network fixes carefully.
Exercises
- Draw your hypervisor network path (host → NAT → guest).
- Switch from interface-hardcoded DHCP to a match pattern (if networkd).
- Add a second allowed port for a localhost service only if intentional.
- Compare
testvsswitchafter a firewall edit.
- Capture
nft list rulesetbefore/after enabling firewall.
- Break DNS with a bad nameserver in a snapshotted VM; recover.
- Document IPv6 status on your lab (on/off/partial).
- Map each
sslistener to a Nix option or “unknown.”
- Write a “no inbound except SSH” policy in one paragraph.
- Practice reconnect scripts from the workstation.
- Note whether openssh module opened ports for you automatically.
- Prepare for TLS chapter: pick a future lab hostname.
Common pitfalls
| Symptom | Theory |
|---|---|
| Rebuild can’t fetch | DNS/route broken mid-change |
| SSH timeout after firewall | Port not allowed |
| Interface rename after hardware change | Update config |
| Both NM and networkd fighting | Pick one model |
useDHCP defaults surprise |
Read options for 26.05 |
| Live nft edits as SoT | Lost on rebuild |
| NAT without port forward | “VM has no SSH” false alarm |
Checkpoint
- Interface + IP documented
- Firewall enabled with explicit SSH allow
- Port audit table written
- Recovery from firewall mistake understood
- Committed network docs
- Prefer
testfor risky net changes
Further depth (this book)
| Topic | Chapter / part |
|---|---|
| SSH users | Users and access |
| Service ports | systemd via Nix |
| Hardening / TLS | Services and security part |
| Firewall discipline deep | Services and security part |