Changing the default boot‑failure rollback policy for NixOS generations
0 reputation · 24 Nov 2022, 14:57 UTC
0 reputation · 24 Nov 2022, 14:57 UTC
NixOS creates a separate GRUB entry for each system generation, allowing a manual rollback to a known‑good state after a failed upgrade. However, the project has not defined a default policy for automatically booting the previous generation when the system fails to start. The decision must balance safety against the risk of repeatedly booting a broken generation, consider limited console access on remote machines, and account for the fact that mutable directories such as /etc and /var are not versioned.
Goal: determine whether NixOS should enable an automatic boot‑into‑previous‑generation mechanism on boot failure and, if so, under what conditions it should be triggered.
Questions:
Yes – NixOS should attempt an automatic rollback to the previous generation after a boot failure, but only when the failure is detected reliably and a small safety limit is respected.
nixos-rebuild switch --rollback which toggles the GRUB saved_entry variable.system.maxGenerations option limits how many generations are kept; older generations are garbage‑collected and cannot be booted./etc and /var are not versioned, so a rollback only rewinds the immutable Nix store.saved_entry; this can be scripted from an early‑boot service.multi-user.target within a configurable timeout (e.g., 90 s) or if the emergency shell is activated, set a flag /run/boot-failed./nix/var/nix/profiles/per-user/root/channels or a simple file /run/boot-success.gen) to find the most recent generation that booted successfully before the current one./nix/var/nix/profiles), write its GRUB entry number to saved_entry and clear the flag.system.maxGenerationsThe rollback service must skip generations that have been removed by the garbage collector. It can do this by checking whether the generation's profile directory still exists; if not, it continues searching older generations until either a valid one is found or the limit imposed by system.maxGenerations is reached.
/run/boot-failed-count. Increment it each time an automatic rollback is attempted.multi-user.target).# /etc/nixos/configuration.nix
{ config, lib, pkgs, ... }:
{
boot.loader.grub.enable = true;
# Enable the automatic rollback service
services.boot-failed-rollback.enable = true;
# Optional tuning
services.boot-failed-rollback.timeout = 90; # seconds to wait for multi-user.target
services.boot-failed-rollback.maxRetries = 2; # give up after N attempts
}
The corresponding module would:
/run/boot-failed if multi-user.target is not reached within the timeout (using systemd timeout logic or a simple watchdog script).local-fs.target) that reads the flag, consults /run/boot-failed-count, selects a valid previous generation, writes to GRUB's saved_entry via grub-reboot, and clears the flag on success.To finalize the recommendation we need to know: what maximum number of consecutive boot failures should trigger giving up on automatic rollback? If the environment prefers a more aggressive policy (e.g., only one failure) or a more conservative one (e.g., three failures), the suggested default of 2 can be adjusted.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.