Best practices for auto-upgrades of flake-enabled NixOS systems?

With NixOS, I’ve gotten used to checking in my entire system config to git.

Well, except it’s not the entire config, since I rely on Nix channels and system.autoUpgrade to automatically get security updates and the like.

All of that makes sense to me and doesn’t feel especially ugly.

Now that I’ve begun adopting flakes for some of my packages, I have gotten used to including everything in git, including the locked version of Nixpkgs. But I still want automatic updates of my machines!

Naively, I can imagine setting up CI somewhere to do a bunch of flake lock updates and auto-commits, but that all seems ugly. I assume there is a best practice for autoUpgrades of flake-based NixOS systems that avoids all that?

4 Likes

I do it like this:

system.autoUpgrade = {
    enable = true;
    flake = inputs.self.outPath;
    flags = [
      "--update-input"
      "nixpkgs"
      "--no-write-lock-file"
      "-L" # print build logs
    ];
    dates = "02:00";
    randomizedDelaySec = "45min";
  };

This results in the following call with a systemd.timer:

nixos-rebuild switch --update-input nixpkgs --no-write-lock-file -L --flake /nix/store/<flake-source> --upgrade
8 Likes

This ^ is what i do, but in addition i add the following to my direnv .envrc file to avoid accidentally downgrading my system during nixos-rebuild:

test -d .direnv || mkdir -p .direnv
now="$(date +%Y-%m-%d)"
if ! test -s .direnv/pull-date || test "$now" != "$(cat .direnv/pull-date)"; then
  git checkout -- flake.lock
  git pull --rebase --autostash
  nix flake lock \
    --update-input nixpkgs
  echo "$now" > .direnv/pull-date
fi

This effectively updates my lock file when i enter my nix config directory, at most once a day

3 Likes

I keep my flake in a GitHub repo and have an action that runs nightly to update the flake.

3 Likes

I’d say its suboptimal solution. Next time you manually switch your machine you will end up with older dependencies

ideally, you’d specify /etc/nixos string path for the flake argument without --no-write-lock-file and somehow add git commit

A better question is why do you need it? I update probably once every couple of months and its just fine

1 Like

That’s just because you (and hopefully nobody else) don’t look too closely at the security issues found in all packages on your system - which in turn is a good reason for auto updates, because then you don’t need to look too closely to stay safe.

Personally I don’t like automated updates, I prefer having some control, so I have a weekly CI job that also runs some basic tests whose commits I manually apply when convenient. It fails often enough due to upstream changes (nvidia…) that I think this is justified, too.

If a serious vulnerability pops up - I am sure that I’ll hear about it, and for minor vulnerabilities, it’s not worth risking my system stability. Especially since its not exposed anywhere

While issues after upgrade are rare, they do exist

1 Like

Some people choose one way or the other on the trade-off of automatic updates. My question was how to do them with flakes. Thanks for the answers so far. Feel free to add other workflows if you have them.

2 Likes

ideally, you’d specify /etc/nixos string path for the flake argument without --no-write-lock-file and somehow add git commit

This assumes the config lies in /etc/nixos, which it does not on my case, nor the many who deploy remotely

Is there the option of simply pulling the latest commit from a git repo on an hourly basis and rebuild if there was a change?

The system.autoUpgrade module with flakes will do that. It won’t make sure your git repo has been updated, though.

Yeah I was specifically asking for that. But perhaps it doesn’t even matter too much, eg it wouldn’t restart services that haven’t change afaict. Perhaps daily will be enough though.

It would, assuming those services don’t have the don’t-restart-on-update attribute set. There are some services you wouldn’t want to insta-update (login managers come to mind), and those have specific exceptions (which can be overridden if you are so inclined). I don’t think kexec for updating to a new kernel version is supported by NixOS yet either.

You can set the reboot settings, which will reboot the system during a specific window if there were updates.

But indeed, I think doing it more frequently than daily is a bit overzealous. I doubt nixpkgs will update most things at that frequency, so you’re not gaining much.

Yeah the automatic updates would just happen to rebuild a web service

So with Nix 2.19 deprecating --update-input and --recreate-lock-file (Release 2.19 (2023-11-17) - Nix Reference Manual) I guess the autoupgrade module will need some work at some point in the future?

3 Likes

I made some comments about how I use this here…

Basically (and as you were asking for) unlike the previous channel-based case, I don’t want the autoUpdate updating its own lock file; I now want it to pull the lock file with the rest of the config.