Skip to content

Secure Boot and Lanzaboote

Overview

NixOS does not ship turnkey UEFI Secure Boot in core modules. Partitioning and bootloaders covers ordinary systemd-boot/GRUB and optional UKI/ukify wiring; signing a chain of trust for firmware enforcement is separate operator work.

Lanzaboote (nix-community) is the usual path: a custom UEFI stub, the lzbt installer, and a NixOS module for Secure Boot (and optional measured boot). It is advanced and sharp-edged—docs target experienced users, recommend backups and recovery comfort, and note uneven firmware support (ThinkPads and Framework machines are better tested; no guarantees). Pin a release tag; treat the stack as community tooling that still evolves.

Details

Prerequisites. Install NixOS in UEFI mode with systemd-boot as the current loader first, then switch to Lanzaboote. Confirm with bootctl status: Firmware should be UEFI; Current Boot Loader should be systemd-boot. ESP layout and generation pressure still matter—see Partitioning and bootloaders and Generations and boot.

Architecture. NixOS bootspec (enabled by default since NixOS 23.05) describes bootable generations. lzbt consumes bootspec, signs boot artifacts, and installs them to the ESP. Packing a full UKI per generation with systemd-stub (kernel + initrd inside each image) pressures small ESPs when many generations are retained. Lanzaboote’s stub keeps kernel and initrd as separate ESP files while preserving the chain of trust (signed stub/kernel; initrd integrity via hash embedded in the signed UKI).

Module pattern (flakes). Add a pinned input such as github:nix-community/lanzaboote/v1.1.0 (or another release tag—prefer tags over floating main). Import lanzaboote.nixosModules.lanzaboote. Force boot.loader.systemd-boot.enable = lib.mkForce false (Lanzaboote replaces that module). Enable boot.lanzaboote.enable = true and set boot.lanzaboote.pkiBundle to the key bundle path (docs use "/var/lib/sbctl"). Install pkgs.sbctl for key creation, enrollment helpers, and sbctl verify debugging.

Keys and firmware. After the module rebuilds a signed boot layout (“prepare your system”), enabling Secure Boot in firmware and enrolling keys is a separate step: create keys with sbctl (typically under /var/lib/sbctl), enroll into the platform (docs cover Setup Mode and enrollment), then turn enforcement on. Firmware menus and quirks vary by vendor—follow the Lanzaboote getting-started docs; do not invent board-specific steps here. Optional measured boot (TPM PCR policy for LUKS unlock) is a follow-on—see TPM and measured boot.

Operational caveats. Lanzaboote does not replace understanding ESP size, generation limits, or recovery when the machine will not boot. Keep a recovery plan (Troubleshooting). Pin the Lanzaboote release and re-read release notes when upgrading.

Boundaries (what this page is not)

Examples

Illustrative flake fragment (not a full host config). Follow current Lanzaboote docs for key creation, enrollment, and firmware setup after the first rebuild.

{
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
    lanzaboote = {
      url = "github:nix-community/lanzaboote/v1.1.0";
      inputs.nixpkgs.follows = "nixpkgs";
    };
  };

  outputs = { nixpkgs, lanzaboote, ... }: {
    nixosConfigurations.yourHost = nixpkgs.lib.nixosSystem {
      system = "x86_64-linux";
      modules = [
        lanzaboote.nixosModules.lanzaboote
        ({ pkgs, lib, ... }: {
          environment.systemPackages = [ pkgs.sbctl ];
          boot.loader.systemd-boot.enable = lib.mkForce false;
          boot.lanzaboote = {
            enable = true;
            pkiBundle = "/var/lib/sbctl";
          };
        })
        # …your normal configuration…
      ];
    };
  };
}

See also

References