Is it possible to recover configuration.nix from an older generation?

Is there any way to print out what my configuration.nix was on a previous generation of the system? I just realized I deleted something I want to get back. I have a full system backup but I can’t browse the backup, only restore it, and I’d rather not do that. I’m guessing the configuration.nix itself isn’t actually saved anywhere though.

5 Likes

No, not in general, I’m afraid. The best practice seems to version-control your configuration.nix (and other custom files you include from it). EDIT: there’s a system.copySystemConfiguration option for the simple cases.

6 Likes

Thanks. Wish I knew about that config option before. I do have secondary files but they’re less important. Might be nice to have a second option to specify additional paths though.

Thanks. Wish I knew about that config option before. I do have secondary files but they’re less important. Might be nice to have a second option to specify additional paths though.

For full generality you could add to your systemPackages a runCommand package that copies whatever you care about to “$out/share/system-nix-configuration” or whatever you prefer…

3 Likes

It’s also not a post-hoc solution, but in addition to version-controlling my system config with git, my system runs on zfs and I have znapzend making periodic snapshots. That’s also saved my skin a couple of times when I’ve not been diligent enough about actually committing changes…

On a different-but-related topic, I’ve been meaning for a long time to wrap my nixos-rebuild so that it automatically makes a commit labelled with the system generation on a separate branch of my system config repo whenever updating the system profile. But we all know how those “one-day” projects are…

1 Like

I have something like that now it wasnt that big of a deal. so my /etc/nixos is part of my git dotfiles project and to run a nixos-rebuild I use this script.
https://github.com/mogorman/dotfiles/blob/a490976e51a0f9afbe4df52754d7ef3d4116566d/nixos/rebuild_and_switch.sh
and in my configuration.nix there is this

environment.etc."nixos/active".text = config.system.nixos.label;

that way i always know the git release of nixos as well as its config git version.

3 Likes

I like to copy my Nix expressions tree into the store, and then use that for my NIX_PATH. It lets me hack on my tree without breaking Nixpkgs for the rest of the system, and it means that I can always find the entire tree for a given system if I need it.

3 Likes

That’s pretty cool.

Because I rather use options/modules to toggle such things I’ve adapted it into a simple module.

Thanks a lot!

Personally I’d just keep my configuration Nix files in a git repo and put this somewhere in the config:

{
  environment.etc."dotfiles-rev".text =
    (builtins.fetchGit { url = ./.; ref = "HEAD"; }).rev;
}

builtins.fetchGit returns a set with a rev field, so you can use that to log the configuration’s revision in a file. It’s not perfect. I use ref = "HEAD" so that if I have uncommitted changes, the rev is the most recent revision instead of “000000…”, so a dirtywork tree always makes an inaccurate file since the rev doesn’t include uncommitted changes. Anyway you can do one further by actually putting the whole repo somewhere.

{
  environment.etc."dotfiles-src".source = builtins.fetchGit ./.;
}

Not specifying ref = "HEAD" makes it use a dirty worktree instead of the most recent commit, so you’ll get the exact source of the configuration this way.

Technically? No. Though there is a sort of hack-job way I managed to do it, which should work as long as you have access to load the previous configuration, for obvious reasons, and have the current configuration in the same folder it would be in before. The basic way to do it is to do the command “nix flake metadata” in the folder where the folder, which should give you the store path. Then if you travel there, you can use the cp command, as sudo with the -r flag so it copies the whole directory, to a separate directory. Do note, it still retains the read-only permissions, meaning you would then need to do a chown and chmod to get the files to the correct permissions. All-In-All, however, I find it much easier to just version control from the get-go, simply because it’s much easier than copying from the store and dealing with permissions.

For post-mortem reference and late-night debuggers, here’s how to find old /etc/nixos files for every flake generation not deleted by nix-collect-garbage:

ls /nix/store/*-source/configuration.nix

or if you only want the directories then

ls /nix/store/*-source/configuration.nix | awk -F ‘/’ ‘{print “/” $2 “/” $3 “/” $4}’

For unknowable reasons, post-build profiles in /nix/var/nix/profiles do not keep track of their configuration source. At best, you can use nix profile diff-closures --profile /nix/var/nix/profiles/system to examine app changes and diff configurations like so diff /…-source/configuration.nix /etc/nixos/configuration.nix.

I highly recommend using git for version control or adding comments to configuration.nix for each rebuild like # Configured ACME for Nginx SSL certificates to distinguish it.

How I used this new-found knowledge : nixos-rebuild switch -–flake /…-source with each configuration until my local NextCloud works, figure out the breaking change and revert it in /etc/nixos/configuration.nix. Now, I use git and don’t worry about it :slight_smile:

1 Like

That only works for flakes, since flakes are copied to the store before eval.

2 Likes

So, it’s impossible for non-configured-to-be-copied, non-flake and non-version-controlled setups. Otherwise, options are available.
Edit : Thanks for the precision waffle8946

I’m using flakes and this saved by butt after rsyncing my configs to /etc/nixos with a –delete flag present, nuking hardware-configuration.nix, which can also be recovered this way.

Thank you!

1 Like

For the sake of anyone running into these kinds of issues: Use git.

There is no reason not to use version control for text files. That way you avoid the need for things like rsync as well, and get much more granular, usable config syncing.

Using NixOS without git kind of defies the purpose of putting your system configuration in a centralized set of text files.

2 Likes

Update here! I dug a little deeper into man 1 nix-store-query:

–requisites / -R

      Prints out the set of requisites ⟨../../glossary.md#gloss-requisite⟩ (better known as the closure ⟨../../glossary.md#gloss-closure⟩)  of  the
      store path paths.

      This query has one option:

      •  --include-outputs  Also  include the existing output paths of store derivation ⟨../../glossary.md#gloss-store-derivation⟩s, and their clo‐
         sures.

      This query can be used to implement various kinds of deployment. A source deployment is obtained by distributing the closure of a  store  de‐
      rivation.  A  binary deployment is obtained by distributing the closure of an output path. A cache deployment (combined source/binary deploy‐
      ment, including binaries of build-time-only dependencies) is obtained by distributing the closure of a store derivation  and  specifying  the
      option --include-outputs.

I highly recommend looking up and understanding Nix closures for our purpose.

Regardless, this command finds flake system sources per-profile:

nix-store --query --requisites $(realpath /nix/var/nix/profiles/system-${NIXOS_PROFILE_ID}-link) | grep -- '-source$'

INFO: usually nixpkgs is listed alongside the /etc/nixos copy.

That /nix/var/nix/... would be best replaced by /run/current-system. Still, that query will list all paths with the name source, i.e. a lot of irrelevant paths.

Well, grep here returns paths finishing with ‘-source’, so I only get two source derivations: nixpkgs and the /etc/nixos flake copy. I have no idea how to limit this further, so any input is appreciated :slight_smile:

You’re right @waffle8946 that /run/current-system is simpler. However, the title of this thread is basically ‘how to recover configuration.nix from an older generation’. Thus, my reasoning.

EDIT:

I took a crack at better filtering.

Here’s my result : ls $(nix-store --query --requisites $(realpath /nix/var/nix/profiles/system-250-link) | grep -- '-source$') | awk 'BEGIN{ RS="" ; FS="\n\n" ; ORS="\n\n" } ; /configuration.nix/ { print }'

Basically, it lists the directory contents of the previous sub-command, separates the fields by an empty line and returns the field containing configuration.nix if it exists. Problem solved !