Okay! First time dipping my toes into making a blogpost, we'll see how this goes. Kind of sort of a test to see how I feel about doing this, ended up being way longer than I was expecting.
Some background: I've been using NixOS for around 3 years now, and have been a nixpkgs maintainer for only about a year less. Prior to that I've been distrohopping a lot, which took me to some interesting places - before NixOS I eventually settled into using Arch for desktops, and Proxmox VE w/ some basic Terraform + Ansible for servers.
I'll be talking about my experience with both the desktop and server sides of things, though what I say should be applicable to pretty much any usecase.
(credit to ntgn for the art!)
Declarative!
If you're reading this, you may have already heard the phrase "
Let's say you're someone using Arch Linux (with all the good and bad that entails) and one day something breaks after an update. Or you plug in new hardware that doesn't work right immediately, or some proton game is acting up. Whatever it is, you go through the ritual of checking wikis and forum posts, until you fix the issue by changing some file in /etc, telling grub to load an extra kernel module, adding some udev rules, whatever. It's fixed!
Now, if you encounter the same issue on another computer a month or year later,
In NixOS,
On the server side of things, especially in large-scale deployments, this is how things are already done with Terraform/Ansible. In this case there isn't much of a difference here, except for speed - I've found that a nixos-rebuild changing something is usually faster than an equivalent Ansible playbook.
Reproducible!
Let's pretend you're another hypothetical Arch user. You just made yourself a cool niri config which you'd like to reuse later, so you put your dotfiles in git. So far so good. A few weeks later you try installing them to another system, but oh no! Niri updated in the meantime, and now your dotfiles don't work anymore.
NixOS
A side effect of this is that NixOS is able to keep multiple "
Modular!
In nixpkgs, we have these things called modules. Modules are how
services.nginx = {enable = true;virtualHosts.localhost = {locations."/ " = {return = "200 '<html><body>yay!</body></html>' ";extraConfig = ''default_type text/html; '';};};};
There's a lot to talk about here, but for now I'd like to focus on how I use modules in my own configs. See, modules aren't just a nixpkgs-internal thing - if you want, you can define custom ones!
A small selection of what's possible:
- core/hardening.nix: How I harden
all of my systems, defined in 1 file and enabled with a single "." statement.enable = true; - core/mullvad: A module that sets up multipath, per-connection-loadbalanced routes through Mullvad VPN servers. If I continue with this whole blog thing, I'll make a writeup about this sometime.
- servers/cluster: A bunch of modules for enabling services in my RKE2 cluster. The website you're looking at right now is running on this!
- desktops/home: Modules defining my KDE/Niri/Hyprland configs, this is basically the Nix equivalent of dotfiles.
Closing thoughts
Of course, NixOS isn't flawless. There's the incredibly high learning curve of a functional programming language in the first place, Nix errors are still
If you actually read this far down, thank you so much! I hope it wasn't too boring. If you just scrolled down without reading, thanks anyway for taking the time to look at the entire page <3
|\__/,| (`\
_.|o o |_ ) ) <---- cat!
-(((---(((--------
PS: Feel free to contact me if you'd like to talk about this article or how I could improve the