~aumetra: Blog - CV
24/03/2025 7 min read

Neat NixOS stuff

Table of contents

Start?! (ToC plugin pls don’t swallow this)

I’ve been running NixOS for like a while now. For better or for worse, and it was a fine enough experience.

But there’s some tools I had to find over the years to make NixOS configurations more bearable. So this is me writing down some stuff.

Also for future me, in case I ever need a reference.

Flakes

By default NixOS gives you the traditional configuration. In your /etc/nixos folder using channels.

Well, fuck this! Flakes are the shit (for this task at least). I prefer how they actually make your stuff more reproducible.

What do I mean by more reproducible? Well.. the traditional NixOS setup has channels. And you update these channels each time you want to update packages.

Works fine enough until you realize “hmm.. what if I have the channel on version X on this machine, and the channel on version Y on the other?”

Well! Then you have a mismatch of packages running. Those packages can have different behaviours and everything. Not really reproducible unless you jot down the channel versions you’re on and configure them on each machine to the same revision.

Flakes solve that by having a lockfile and locking to a specific Git revision (yeah, flakes are heavily integrated into version control systems).

While flakes have issues with cross-compiling and stuff, this doesn’t matter if you use it as an encapsulation for NixOS configurations on your local machine because you’re not cross-compiling anything.

So for starters you just wanna take this NixOS config and slot it riiiiight into a flake. Like so:

Output in the example is called “framework” just because I have a Framework laptop. Change that to whatever you want.

{
  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
  };

  outputs =
    {
      self,
      nixpkgs,
      ...
    }:

    let
      system = "x86_64-linux";
      pkgs = import nixpkgs {
        inherit system;

        config = {
          allowUnfree = true;
        };
      };

      lib = nixpkgs.lib;
    in
    {
      formatter.x86_64-linux = pkgs.nixfmt-rfc-style;

      nixosConfigurations.framework = lib.nixosSystem {
        inherit pkgs system;

        modules = [
          ./configuration.nix
          ./hardware-configuration.nix
        ];
      };
    };
}

Aaaand.. this config is already opinionated. I allow unfree packages, and I add a formatter that formats the code according to the RFC code style.

If you disagree with any of that, you can just change the code. It’s just what I run on my systems <3

Wowowow, so flakey. And it doesn’t take a lot to change. You can leave your configuration.nix and hardware-configuration.nix unmodified.

Your rebuild command will change to sudo nixos-rebuild switch --flake path/to/flake#framework and your updates will be cd path/to/flake && nix flake update.

Actually, I lied about the “unchanged configuration.nix” part. You want to add a couple of lines:

nix.settings = {
  experimental-features = [
    "flakes"
    "nix-command"
  ];
};

This is because flakes are still “experimental” (note: experimental. Not unstable). So if you want to use Nix subcommands and flakes without having way too long commands, you need that config.

Also, I recommend just moving the config out of /etc/nixos into a Git-managed folder in your home directory. Just easier to edit that way.

Home Manager

A mainstay in the Nix community. Back when I first installed NixOS, even without flakes, I used Home Manager because.. well, I just preferred the way it configures packages on a user-level, not a system-level.

Another benefit is that it has just way superior types for things like sway, meaning no awkward “write a config in a string” (or split them into a different file and then read them in as a string). Just write plain ol’ Nix.

Even though I said I prefer user-level stuff, I’d recommend just installing it as a NixOS module. That way you have all your configs centralized in a single Git repo.

Just follow the installation guide for flakes and you’re good.

Stylix

This is a neat one. If you, like me, are just lazy and can’t stand writing 50 different configs to make your theme look just right in GTK-{2, 3, 4}, Qt, vim, waybar, etc. then Stylix is a godsent.

Basically, instead of having to figure out a theme and configure it globally, you just drop your background image in your NixOS config folder, give Stylix the path, and it automatically generates a theme at build time and generates theme configs for all kinds of different programs.

Just follow the installation guide.

And even though they support a Home Manager variant, I personally have it installed on the system-level. I know, I’m not really going through with one or the other. System-level or user-level. I should fix that.

Comma

Comma is really useful if you often need to execute commands but don’t want to add those tools to your config, then rebuild, yada yada..

This sounds like a job for nix-shell, right? Let’s take Redis for example: just nix shell nixpkgs#redis and then run redis-server. Boom.

Well yeah, it’s straight-forward if you know what package includes which commands. But what if you don’t know the package? You’d have to search, then open a Nix shell, and then run the command.

Also what a dumb roundtrip. Open a whole new shell just to immediately execute the command once and then exit the shell again. Bleh.

That’s where comma comes in. You just type , redis-server and comma figures out which package provides the command. If there are multiple candidates, it will ask you but remember your selection.

Seems weird, maybe redundant, but I had two friends so far that said “eh, I don’t see the benefit” who then tried it, and now use it all the time. So it’s worthwhile IMO.

The installation is, yet again, pretty straight forward. You just have to know where to look for a guide, because this time it’s not directly the comma repository you have to check, but instead the nix-index-database README.

Just uncomment the following line in the example and you’re golden:

{ programs.nix-index-database.comma.enable = true; }

agenix

It’s common in the Nix community to put your config publicly on GitHub. Makes it easier to restore in case of a total system failure (no authentication needed, just git clone), and other people can check your config to copy your cool tricks.

But sometimes you need some secrets in your config. For example, my hackerspace has a system called “airlock” where we can open doors by making an HTTP request to [whatever] hooked up to a door buzzer.

Of course I need a secret to prove that it’s me! But I can’t just put that in my config, otherwise everyone can access the space with my login and that’s no good..

If you come from the DevOps world, specifically with Kubernetes, you might know sealed secrets. It’s a package by Bitnami where the cluster has a private key and you can retrieve the public key from it.

You then use the public key to encrypt the secrets you need in your Kubernetes pods and commit those encrypted secrets into your version control.

When the cluster then pulls the newest version, it decrypts those secrets and makes them available to your pods.

See the benefit here? Even if the code happens to leak for some reason, the secrets are only there in an encrypted form. Still secret.

agenix is doing essentially the same but for Nix configs. It uses the age encryption tool to have public key cryptography. And the neat thing about age is that it uses bog-standard Ed25519 SSH keys.

If you administrate a server or use a Git forge, you most likely already have an Ed25519 SSH key.

And if you don’t and still use an RSA key, then you should seriously switch. It’s an outdated cryptosystem, is comparatively slow, and has gigantic key sizes compared to Ed25519.

So it’s just a matter of following the installation guide, and then the step-by-step instructions on how to encrypt your first secret.

Make sure to not use builtins.readFile. Yeah, aliases can get a bit hairy that way but if you use the readFile method, you’ll put the secret into /nix/store which anyone can read.

Wouldn’t want people to be able to read your secrets with a simple cat.

End?! (yeah. Actually the end)

I have nothing else to say anymore. That’s all the nice tooling I use to make my NixOS more bearable to work with.

<3