Migrating a gateway's hardware
Replace a gateway computer without losing its configuration or data. The difference from a fresh install boils down to one sentence : the machine is new, the state is not.
That is where almost all the pitfalls on this page come from.
What carries over on its own, what does not
Section titled “What carries over on its own, what does not”| Repris automatiquement | À reprendre à la main |
|---|---|
| DNS and DHCP for the zone | Service data |
| Service registry, portal, reverse proxy | Backup repository |
| Monitoring targets, deployment tags | VPN identity |
| sops secret recipients | Owners of restored files |
| Deployment SSH keys | system.stateVersion |
Secrets are not tied to the hostname : the sops rules file only knows the administration key and the infrastructure key. Renaming changes nothing here.
Surveying the new hardware
Section titled “Surveying the new hardware”Nothing is modified at this stage : you only collect what will need to be written into the configuration.
-
Boot from the USB drive (
just build-isoimage), USB Wi-Fi card plugged into the port that will be its final port. -
Record interfaces, MAC addresses and disks
Fenêtre de terminal ip -o linklsblk -o NAME,SIZE,MODEL,SERIAL,TYPEThe permanent MAC of a Wi-Fi card differs from its current MAC, which is often random. The permanent one matters, visible in the
permaddrfield. -
Physically identify which port will be the WAN and which ones the LAN, by unplugging and replugging. Label the ports.
Preparing the configuration
Section titled “Preparing the configuration”Wi-Fi interfaces do not need to appear in gateway.lan.interfaces :
hostapd places its interface in the bridge by itself. If you list one
anyway, the framework removes it from the networkd bridge — otherwise
networkd would try to attach it before hostapd has switched it to AP mode,
fail in a loop, then give up managing the link.
zones: maison: gateway: wan: interface: "eno0" lan: interfaces: ["eno1", "eno2", "eno3"]
hosts: - hostname: "gw" zone: "maison:1.1" profile: "gateway" mac: "00:00:5e:00:53:00" disko: profile: "luks-btrfs-1-disk" devices: main: "/dev/nvme0n1"Renaming the host along the way is the right time to do it, since the machine is reinstalled anyway. An alias carrying the new name must then be deleted : the generator refuses a name that is both an alias and a hostname.
On the machine folder side, git mv usr/machines/<old> usr/machines/gw, then delete install/disko.nix
(deleting the old disk) and keep install/state.nix. just generate
recreates install/disko.nix from the disko block above.
Install
Section titled “Install”just install gw nixos <ip>The command formats, installs and reboots. On an encrypted disk, the
installation passphrase is requested during partitioning : note it down,
just luks will need it.
Prefer the separate steps to just full-install : on an encrypted disk,
waiting for the machine to come back assumes a boot without intervention,
which entering the passphrase forbids.
Switch over
Section titled “Switch over”-
Back up, on the old gateway
Fenêtre de terminal systemctl stop forgejo postgresqlsystemctl start restic-backups-system-main.serviceDo not stop the zone’s DNS resolver : the backup target is referred to by name, stopping it makes it unfindable.
-
Rename the repository, on the backup server
Fenêtre de terminal mv /mnt/backup/restic/<ancien> /mnt/backup/restic/gwA repository’s path contains the hostname. Renaming keeps the whole history, whereas a new name would start from an empty repository.
-
Swap the hardware: shut down, move the data disks, identical wiring, boot and unlock the disk.
-
Configure and deploy
Fenêtre de terminal just configure gwjust apply-verbose gwjust configurepushes the infrastructure key : this is the step that unlocks sops, and therefore the emergency console access. -
Republish the backup accounts on the server that hosts them
Fenêtre de terminal just apply-local
Restoring data
Section titled “Restoring data”The backup server isolates repositories by host: the authenticated user must match the first path segment. The renamed repository therefore remains inaccessible until the server republishes the new account.
restic-system-main snapshotsThis check is the real control: it must list the history of the old machine. An empty repository signals successful authentication but on the wrong path; do not restore anything in that case.
-
Stop the services whose state is about to be replaced.
-
Empty the state directories before restoring.
-
Restore, one mode at a time
Fenêtre de terminal restic-system-main restore latest --target / \--include /var/lib/forgejo --include /var/lib/postgresql -
Restore ownership, by name.
-
Restart the services and verify.
Checking before concluding
Section titled “Checking before concluding”| Contrôle | Attendu |
|---|---|
systemctl --failed | aucune unité |
ls /var/lib/postgresql | une seule majeure |
| Comptes et dépôts applicatifs | ceux d’avant la migration |
restic-system-main snapshots | historique complet |
| Adresse sur le maillage VPN | inchangée |
| Points d’accès Wi-Fi | présents, clients servis |
| Redémarrage à froid | la machine remonte seule |
The disko block of etc/config.yaml is only read at installation : once
the migration is complete, it is frozen in install/disko.nix and can be
removed. Details of the recipes in
Justfile and of the configuration
keys in Le fichier config.yaml.