My journey to a NixOS Router

About two years ago, I bought my first N100 Mini PC for little more than £100. At the time, the N100 was a brand-new chip - quad-core, all “E” (efficiency) cores borrowed from Intel’s Alder Lake architecture, with a mere 6W TDP. It competed with Raspberry Pis but delivered significantly more power, along with a surprisingly capable iGPU (Intel Xe Architecture). Paired with 16GB of DDR5 RAM, it felt like a steal. Just add an NVMe SSD and you’re away.
I originally planned to use it as a router to replace my aging first-generation Atom PC running OPNsense. But once I saw how performant it was, I couldn’t bring myself to waste it on routing alone. Ironically, that realisation led me to set it aside for months while I debated what to do with such an overpowered little machine.
For two decades, I’d been a distro-hopper - never sticking with one Linux distribution long enough to build a proper home lab. Why invest time configuring a system when I knew I’d tear it down and rebuild in a few months? The most I’d ever had was a HP MicroServer running TrueNAS with a few apps like Home Assistant and Plex. It worked, but it was inflexible. In a way, that lack of configurability was a feature: it let me treat the server like a black-box appliance, reducing the risk of breaking it. But it was also frustrating. Setting up VPNs, reverse proxies with automatic ACME/Let’s Encrypt certificates, or even custom firewall rules felt like wrestling with opaque GUIs and brittle scripts.
Then, in 2024, I discovered NixOS.
NixOS has a cult following, and for perhaps good reason. Until relatively recently, it didn’t even have a graphical installer. Its entire state (down to which packages are installed, what services are running, and even how disks are partitioned) is defined declaratively by a single configuration file (or group of files) written in Nix, a pure functional programming language inspired by Haskell.
As a developer, I wasn’t intimidated. I decided to try it on my second laptop as a full desktop environment. At first, I did little more than list the packages I wanted - simple enough once you know which file to edit. Soon, though, I wanted more: custom networking rules, VPN tunnels, systemd services. That’s when the real learning began.
The Nix language was frustrating at first. Coming from imperative languages like Python or JavaScript, the functional paradigm, lazy evaluation, and lack of side effects felt alien. But once I understood that everything is an expression (and that order doesn’t matter because evaluation is deferred until needed) it clicked. I could map my understanding of lambda functions, higher-order functions, and immutability directly into Nix. And suddenly, it made sense.
Then came the lightbulb moment.
Yes, configuration can be a pain in the beginning, but once it’s done, it’s done. NixOS takes infrastructure-as-code to an entirely new level. Your entire system is the result of evaluating the Nix source code and is entirely reproducible. The code that defined the system and the resulting disk image were one and same.
My system’s entire state is versionable, backupable, and shareable. I can commit my config to Git. If I break something? I roll back. If I don’t know how to do something? I borrow someone else’s configuration from GitHub. If I want to share my setup with a friend? I just hand them a repository.
This transformed my relationship with my machines. I stopped distro-hopping. Switching from GNOME to KDE? One line in configuration.nix. Trying Hyprland? Same. Changing VLANs, spinning up a Podman container, or defining a new firewall rule? All done in the same config file. No more juggling dozens of config formats across different tools. Everything lived in one place—under version control, in my user space, treated like any other codebase.
That’s when I decided: I wanted NixOS everywhere.
I wanted a unified configuration language that was worth the upfront investment - not just for convenience, but because it was reliable, reproducible, and shareable. For the first time, I was proud of my home lab. No more duct tape and hope. No more “it works, don’t touch it” hacks. Just clean, documented, versioned infrastructure.
The last piece? My router.
Don’t get me wrong - OPNsense is excellent. I still recommend it to anyone starting out. But I didn’t want my most critical piece of infrastructure to be configured via a GUI. The router is the heart of the home network. If it fails, everything fails. I needed to trust that my configuration wouldn’t vanish if I rebooted. I needed to know I could reproduce it from scratch. I needed NixOS.
The N100 Mini PC was perfect. It ran NixOS effortlessly. It had two NICs I could configure with systemd-networkd as WAN and LAN. Its CPU and Xe GPU could easily handle Home Assistant, Frigate NVR, and several other Podman containers without breaking a sweat. Firewall rules? Defined in nftables, managed via Nix.
After some tinkering, it all worked beautifully.
The final hurdle? Lockout risk.
A misconfigured network or firewall rule could cut me off from the machine entirely - requiring a physical monitor or laptop to roll back. Not ideal for a headless router in the cupboard.
Inspired by others in the Nix community, I implemented a safety net: a simple script that automatically reboots the system to the previous generation if I don’t confirm the new configuration is working within a five-minute window. It’s simple, elegant, and utterly game-changing.
Now, I can experiment fearlessly. I can tweak firewall rules, rewrite routing tables, or upgrade services without anxiety. If it breaks? The system just goes back to how it was, all by itself.
And so, here we are: a fully NixOS powered router, all configuration open-sourced on GitHub, ready for anyone to learn from, borrow from, or improve.
Happy Nixing.