Generation resets on reboot on Raspberry Pi 5

Hi,

I managed to install NixOS on my Raspberry Pi 5, with the help of this comment: https://github.com/NixOS/nixpkgs/issues/260754#issuecomment-2322817130.

this is the flake i used to generated the image i flashed:

{
  description = "NixOS RPi5";
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.11";
    raspberry-pi-nix.url = "github:nix-community/raspberry-pi-nix";
  };

  outputs = { self, nixpkgs, raspberry-pi-nix }:
    let
      inherit (nixpkgs.lib) nixosSystem;
      basic-config = { pkgs, lib, ... }: {
        # bcm2711 for rpi 3, 3+, 4, zero 2 w
        # bcm2712 for rpi 5
        # See the docs at:
        # https://www.raspberrypi.com/documentation/computers/linux_kernel.html#native-build-configuration
        raspberry-pi-nix.board = "bcm2712";
        time.timeZone = "Europe/Prague";
        users.users.root = {
          initialPassword = "REDACTED";
        };
        # Define a user account. Don't forget to set a password with ‘passwd’.
        users.users.evest = {
          isNormalUser = true;
          extraGroups = [ "wheel" ]; # Enable ‘sudo’ for the user.
          initialPassword = "REDACTED";
        };

        networking = {
          hostName = "evest";
        };
        environment.systemPackages = with pkgs; [
          git
          wget
          vim
        ];
        services.openssh = {
          enable = true;
        };
        system.stateVersion = "24.11";
      };

    in
    {
      nixosConfigurations = {
        evest = nixosSystem {
          system = "aarch64-linux";
          modules = [ raspberry-pi-nix.nixosModules.raspberry-pi raspberry-pi-nix.nixosModules.sd-image basic-config ];
        };
      };
    };
}

i managed to make some changes to the configuration with flakes, i generated the configuration.nix and hardware-configuration.nix with sudo nixos-generate-config and copied the flake from https://nixos-and-flakes.thiscute.world/nixos-with-flakes/nixos-with-flakes-enabled#switch-to-flake-nix. mine looks like this:

{
  description = "A simple NixOS flake";

  inputs = {
    # NixOS official package source, using the nixos-24.11 branch here
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.11";
  };

  outputs = { self, nixpkgs, ... }@inputs: {
    # Please replace my-nixos with your hostname
    nixosConfigurations.evest = nixpkgs.lib.nixosSystem {
      system = "aarch64-linux";
      modules = [
        # Import the previous configuration.nix we used,
        # so the old configuration file still takes effect
        ./configuration.nix
      ];
    };
  };
}

my configuration.nix:

{ config, lib, pkgs, ... }:

{
  imports =
    [ # Include the results of the hardware scan.
      ./hardware-configuration.nix
    ];

  # Use the GRUB 2 boot loader.
  boot.loader.grub.enable = false;
  boot.loader.generic-extlinux-compatible.enable = true;
  # boot.loader.grub.efiSupport = true;
  # boot.loader.grub.efiInstallAsRemovable = true;
  # boot.loader.efi.efiSysMountPoint = "/boot/efi";
  # Define on which hard drive you want to install Grub.
  # boot.loader.grub.device = "/dev/sda"; # or "nodev" for efi only

  # networking.hostName = "nixos"; # Define your hostname.
  # Pick only one of the below networking options.
  # networking.wireless.enable = true;  # Enables wireless support via wpa_supplicant.
  # networking.networkmanager.enable = true;  # Easiest to use and most distros use this by default.

  # Set your time zone.
  # time.timeZone = "Europe/Amsterdam";

  # Configure network proxy if necessary
  # networking.proxy.default = "http://user:password@proxy:port/";
  # networking.proxy.noProxy = "127.0.0.1,localhost,internal.domain";

  # Select internationalisation properties.
  # i18n.defaultLocale = "en_US.UTF-8";
   console = {
     keyMap = lib.mkForce "cz-qwertz";
     useXkbConfig = true; # use xkb.options in tty.
   };

  # Enable the X11 windowing system.
  # services.xserver.enable = true;




  # Configure keymap in X11
  # services.xserver.xkb.layout = "us";
  # services.xserver.xkb.options = "eurosign:e,caps:escape";

  # Enable CUPS to print documents.
  # services.printing.enable = true;

  # Enable sound.
  # hardware.pulseaudio.enable = true;
  # OR
  # services.pipewire = {
  #   enable = true;
  #   pulse.enable = true;
  # };

  # Enable touchpad support (enabled default in most desktopManager).
  # services.libinput.enable = true;

  # Define a user account. Don't forget to set a password with ‘passwd’.
   users.users.evest = {
     isNormalUser = true;
     extraGroups = [ "wheel" ]; # Enable ‘sudo’ for the user.
     packages = with pkgs; [
       neovim
     ];
   };

  # programs.firefox.enable = true;

  # List packages installed in system profile. To search, run:
  # $ nix search wget
  # environment.systemPackages = with pkgs; [
  #   vim # Do not forget to add an editor to edit configuration.nix! The Nano editor is also installed by default.
  #   wget
  # ];

  # Some programs need SUID wrappers, can be configured further or are
  # started in user sessions.
  # programs.mtr.enable = true;
  # programs.gnupg.agent = {
  #   enable = true;
  #   enableSSHSupport = true;
  # };

  # List services that you want to enable:

  # Enable the OpenSSH daemon.
  # services.openssh.enable = true;

  # Open ports in the firewall.
  # networking.firewall.allowedTCPPorts = [ ... ];
  # networking.firewall.allowedUDPPorts = [ ... ];
  # Or disable the firewall altogether.
  # networking.firewall.enable = false;

  # Copy the NixOS configuration file and link it from the resulting system
  # (/run/current-system/configuration.nix). This is useful in case you
  # accidentally delete configuration.nix.
  # system.copySystemConfiguration = true;

  # This option defines the first version of NixOS you have installed on this particular machine,
  # and is used to maintain compatibility with application data (e.g. databases) created on older NixOS versions.
  #
  # Most users should NEVER change this value after the initial install, for any reason,
  # even if you've upgraded your system to a new NixOS release.
  #
  # This value does NOT affect the Nixpkgs version your packages and OS are pulled from,
  # so changing it will NOT upgrade your system - see https://nixos.org/manual/nixos/stable/#sec-upgrading for how
  # to actually do that.
  #
  # This value being lower than the current NixOS release does NOT mean your system is
  # out of date, out of support, or vulnerable.
  #
  # Do NOT change this value unless you have manually inspected all the changes it would make to your configuration,
  # and migrated your data accordingly.
  #
  # For more information, see `man configuration.nix` or https://nixos.org/manual/nixos/stable/options#opt-system.stateVersion .
  system.stateVersion = "24.11"; # Did you read the comment?

}

and my hardware-configuration.nix:

{ config, lib, pkgs, modulesPath, ... }:

{
  imports =
    [ (modulesPath + "/installer/scan/not-detected.nix")
    ];

  boot.initrd.availableKernelModules = [ ];
  boot.initrd.kernelModules = [ ];
  boot.kernelModules = [ ];
  boot.extraModulePackages = [ ];

  fileSystems."/" =
    { device = "/dev/disk/by-uuid/44444444-4444-4444-8888-888888888888";
      fsType = "ext4";
    };

  fileSystems."/boot/firmware" =
    { device = "/dev/disk/by-uuid/2178-694E";
      fsType = "vfat";
      options = [ "fmask=0022" "dmask=0022" ];
    };

  swapDevices = [ ];

  # Enables DHCP on each ethernet and wireless interface. In case of scripted networking
  # (the default) this is the recommended approach. When using systemd-networkd it's
  # still possible to use this option, but it's recommended to use it in conjunction
  # with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
  networking.useDHCP = lib.mkDefault true;
  # networking.interfaces.end0.useDHCP = lib.mkDefault true;
  # networking.interfaces.wlan0.useDHCP = lib.mkDefault true;

  nixpkgs.hostPlatform = lib.mkDefault "aarch64-linux";
}

my issue is, that when i reboot my pi it resets to the initial configuration:

[evest@evest:~]$ readlink /run/current-system
/nix/store/m4rdvs0gms24gs98fsq1whhkrb12gg6i-nixos-system-evest-24.11.20250128.2b4230b

[evest@evest:~]$ nixos-rebuild list-generations
Generation  Build-date           NixOS version           Kernel  Configuration Revision  Specialisation
16 current  2025-02-02 12:12:56  24.11.20250130.666e1b3  6.13.0                          *
15          2025-02-02 12:04:33  24.11.20250130.666e1b3  6.13.0                          *
14          2025-02-02 00:53:10  24.11.20250130.666e1b3  6.13.0                          *
13          2025-02-01 22:38:52  24.11.20250130.666e1b3  6.6.74                          *
12          2025-02-01 22:35:58  24.11.20250130.666e1b3  6.6.74                          *
11          2025-02-01 22:12:40  24.11.20250130.666e1b3  6.6.74                          *
10          2025-02-01 22:10:13  24.11.20250130.666e1b3  6.6.31                          *
9           2025-02-01 21:05:31  24.11.20250130.666e1b3  6.6.74                          *
8           2025-02-01 21:04:38  24.11.20250130.666e1b3  6.6.74                          *
7           2025-02-01 20:45:12  24.11.20250130.666e1b3  6.6.74                          *
6           2025-02-01 20:23:44  24.11.20250130.666e1b3  6.6.74                          *
5           2025-02-01 20:09:05  24.11.20250130.666e1b3  6.6.74                          *
4           2025-02-01 20:07:49  24.11.20250130.666e1b3  6.6.74                          *
3           2025-02-01 20:03:33  24.11.20250130.666e1b3  6.6.74                          *
2           2025-02-01 19:58:45  24.11.20250130.666e1b3  6.6.74                          *
1           1970-01-01 01:00:16  24.11.20250128.2b4230b  6.6.51                          *

[evest@evest:~]$

Could someone please help me

2 Likes

Hmmmm. To be honest, I built the SD image and dd-ed it to the SD card, and just booted that. I haven’t updated or change the config since. - I will try soon and let you know.

I guess you can just rebuild the SD image? Iteration cycle will be a bit slow, and if you want to keep your kernel up-to-date (which you really want to), this will suck. :frowning:

One thing I’ve been trying to wrap my head around with Nix is where do you build the target system?

e.g.
You can build the micoVM images, and then you could put nix inside it, and then try to rebuild the microVM from within the microVM. Or you can just continue to build the entire microVM from the outside. I think the general approach is to build from the outside.

Hiiii, thx u sooo much for the reply, i builded the image on my arch linux x86_64 GNU/Linux with the qemu binfmt thing. I added this to my /etc/nix/nix.conf:

extra-platforms = aarch64-linux
extra-sandbox-paths = /usr/bin/qemu-aarch64-static

I also managed to install NixOS (25.05) on a Raspberry Pi 5 using your flake pretty much as-is. I did add the cachix cache as recommended on GitHub since I didn’t want to wait 8+ hours to build everything.

The generated SD card image seems to work just fine. But then when trying to add my own configuration.nix and switch configurations from within NixOS, I run into the same issue as you: it resets back to the original one on reboot.

I don’t really know what I’m doing here and am not sure how to debug it further. Did you ever manage to make the new configuration stick?

Sadly no. I’m currently waiting for an official NixOS image for Raspberry Pi 5, who knows when :disappointed_relieved:.

1 Like

I have tried this too, but same issue, it doesnt get the new generation on boot…

Links above mentioned that support for Pi’s has been dropped

As an update I seem to be having success with the repository linked further down in the GitHb comments:

which seems to be a much more thorough attempt to support Raspberry Pi well, though I barely understand any of what it’s doing.

The SD card image generation worked great, then adding a package to the right place (environment.systemPackages) and running the suggested deploy command installed it:

nixos-rebuild switch --flake .#rpi5-installer --target-host root@host

The new configuration did survive a reboot. I suppose that the key is using the same flake for initial installation and later deployment, since somewhere in there is a part that updates the boot manager to boot into the current configuration. Like I said, I don’t understand much of it.

1 Like

Thx u so much, i’ll try this and let u know how it went on my side :DD

1 Like

i’m planning to look at it probably next week when i’ll get my new framework laptop :DD

1 Like

I put together complete instructions starting from scratch here:

I’d be very happy for any feedback.

1 Like

I managed to get it working, thx u sooooooo muuuch, now i just have to spend countless hours cleaning the code and migrating my debian setup over to nix for no reason haha. For the feedback, i think i would prefer building the image with the root user using an ssh key instead of giving privileges to the user. But thx u really much, i wished for configurating my pi using nix for a long time now, you helped me solve the issue i was stuck on.

Excellent. I would be interested to see whatever you can share about your configuration. Did you manage to get services.xserver.enable working, for example? (It hasn’t worked for me.)

I think i’ll put it on my public repo once i get the configuration to a sort of state that works. I’m planning to use my pi just as a server so i don’t think i can really help you sadly.

ok, i polished it a bit, i changed it a bit for general use, i hope it worked i didn’t test it. I will have my own config on my github in future if someone wants to see it. Also this is specifically for the pi5.

{
  description = "NixOS configuration for Raspberry Pi 5";

  nixConfig = {
    extra-substituters = [
      "https://nixos-raspberrypi.cachix.org"
    ];
    extra-trusted-public-keys = [
      "nixos-raspberrypi.cachix.org-1:4iMO9LXa8BqhU+Rpg6LQKiGa2lsNh/j2oiYLNOQ5sPI="
    ];
  };

  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
    nixos-raspberrypi.url = "github:nvmd/nixos-raspberrypi/main";
  };

  outputs = { self, nixos-raspberrypi, ... }@inputs:
    {
      nixosConfigurations = {
        "your-hostname" = nixos-raspberrypi.lib.nixosSystem {
          specialArgs = { inherit nixos-raspberrypi inputs; };
          modules = [
            ({ nixos-raspberrypi, ... }: {
              imports = [
                nixos-raspberrypi.nixosModules.raspberry-pi-5.base
                nixos-raspberrypi.nixosModules.sd-image
              ];
            })
            ({ config, pkgs, ... }: {
              system.stateVersion = config.system.nixos.release;
              networking.hostName = "your-hostname";
              time.timeZone = "your-timezone";

              services.openssh.enable = true;

              users.users = {
                "your-username" = {
                  isNormalUser = true;
                  extraGroups = [ "wheel" "networkmanager" ];
                  initialPassword = "your-initial-password-that-needs-to-changed";
                };
                "root" = {
                  openssh.authorizedKeys.keys = [
                    "your-ssh-public-key"
                  ];
                };
              };

              environment.systemPackages = with pkgs; [
                vim
              ];

              networking.networkmanager.enable = true;

              system.nixos.tags =
                let
                  cfg = config.boot.loader.raspberryPi;
                in
                [
                  "raspberry-pi-${cfg.variant}"
                  cfg.bootloader
                  config.boot.kernelPackages.kernel.version
                ];
            })
          ];
        };
      };

      installerImages =
        let
          nixos = self.nixosConfigurations;
          mkImage = nixosConfig: nixosConfig.config.system.build.sdImage;
        in
        {
          raspberrypi = mkImage nixos."your-hostname";
        };
    };
}

to build the image:

  • Be sure that the cache applied correctly!
nix build .#installerImages.raspberrypi

to update the image:

eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
nixos-rebuild switch --flake .#your-hostname --target-host root@your-pi-ip

its not perfect but for a ± starting point its enough if someone wants to use it.

1 Like

You might want to avoid that. If anyone somehow retrieves your ssh key, they’ll be able to do whatever they want as root.
Same applies to setting password for root user.

As long as your main user is in the wheel group, there’s no reason to set set anything for root.

If it’s meant for testing purpose and to be run in a closed, controlled environment, that should be fine though.

e.g suggested ssh config:

{
  users = {
    users."my-user" = {
      openssh.authorizedKeys.keys = [
        "ssh-ed25519 ..."
      ];
    };
  };

  services.openssh = {
    enable = true;

    ports = [ 
      1234 # anything but 22 default port
    ];

    settings = {
      PasswordAuthentication = lib.mkForce false; # only use ssh keys
      KbdInteractiveAuthentication = lib.mkForce false;
      PermitRootLogin = lib.mkForce "no"; # root auth not allowed
      KexAlgorithms = [
        # ssh-ed25519 keys only
        "curve25519-sha256"
        "curve25519-sha256@libssh.org"
      ];
    };
  };
}

Well my problem is that i could not update the config remotely as a regular user and i saw i need to specify the root user for that i have tried some things but they didn’t work, so this was the best solution at the time i could come up with. Also someone created a wiki for pi 5 :DD NixOS on ARM/Raspberry Pi 5 - NixOS Wiki i would reccomend that for anyone.

check this maybe: Nixos-rebuild remote target with non-root user

1 Like

Thx but i managed to fixed it by allowing root password login, i think its a good solution for me.