- Nix 68%
- JavaScript 10.4%
- Python 7.6%
- Shell 4.9%
- Luau 3.3%
- Other 5.7%
| _sources | ||
| docs | ||
| modules | ||
| .envrc | ||
| .gitignore | ||
| .sops.yaml | ||
| AGENTS.md | ||
| flake.lock | ||
| flake.nix | ||
| nvfetcher.toml | ||
| README.md | ||
| statix.toml | ||
Repository layout and design choices: docs/STRUCTURE.md. Backups: docs/BACKUP.md. Monitoring: docs/MONITORING.md. Open improvements: docs/HANDOFF.md. opencode: docs/OPENCODE_SANDBOX.md (the sandbox).
Installation
sudo nix --experimental-features "nix-command flakes" run github:nix-community/disko/latest -- --mode destroy,format,mount --flake .#$(hostname) # layout: mods.disko in the host
sudo mkdir /tmp/mnt
sudo mount /dev/mapper/crypted /tmp/mnt
sudo btrfs subvolume snapshot -r /tmp/mnt/root /tmp/mnt/root-blank
sudo umount /tmp/mnt
sudo nixos-generate-config --no-filesystems --root /mnt
# Fresh host: copy it. Reinstall: DON'T copy blindly, it drops hand edits
# (muon: the /mnt/bulk mount, mtu 1280, libvirtd, supportedFilesystems).
# Diff and port only the detected bits; see "Reinstalling an existing host".
cp /mnt/etc/nixos/hardware-configuration.nix modules/hosts/$(hostname)/_hardware-configuration.nix
rbw config set email admin@muon.host
rbw config set base_url https://vault.muon.host
rbw login
rbw get sops | sudo install -D -m 0400 -o root -g root /dev/stdin /mnt/persist/var/lib/sops-nix/key.txt
sudo chmod 0700 /mnt/persist/var/lib/sops-nix
sudo nixos-install --root /mnt --no-root-passwd --flake .#$(hostname)
sudo cp -r /mnt/var/lib/nixos/* /mnt/persist/var/lib/nixos/
sudo cp {/mnt,/mnt/persist}/etc/machine-id
The system copy of the sops key is root-only (file and directory): only
activation reads it. After the first boot, run sops-bootstrap in the dev
shell to put the key from rbw in ~/.config/sops/age/keys.txt, which
home-manager and the sops CLI use. (install-flake on the muin ISO does this
step for you.) Run the same command on any machine that has lost its sops key.
Reinstalling an existing host
disko's destroy,format wipes the whole mods.disko.device disk (picked by
id). Anything else (muon's /mnt/bulk on sdb, the old 840 on sda) is left
untouched, so data there needs no prep, and in-flight archive-sync uploads
don't have to finish first.
The danger is the wiped disk: restic is an allow-list (mods.backup.paths:
documents, misc/{music,pictures,videos}, projects, work, Signal, Thunderbird,
Zen, .ssh, .gnupg, ludusavi saves). Everything else on it is gone, e.g. the
rest of ~ (~/.local/share, other app config, ~/go, Downloads), VM images
(*.qcow2 is excluded from restic), Actual Budget (/var/lib/private/actual),
Docker volumes, tailscale/syncthing/i2pd identities and the SSH host keys.
Checklist (bash syntax; in nushell run bash first):
# 1. Everything worth keeping is pushed: the flake itself is NOT in restic.
git -C ~/.config/home status -sb # clean, not ahead of origin
# 2. One last restic run, and a test restore.
sudo systemctl start --no-block restic-backups-$(hostname).service
backup-status # wait for "last result: success"
# restic restore latest --target /tmp/t --include ~/documents/<some-file>
# 3. archive-status: anything you mean to drop (e.g. ~/refactor) must show
# "FULLY SYNCED + VERIFIED"; it is wiped with the disk.
# 4. Safety-net copy of the disk being wiped onto one that survives
# (muon: /mnt/bulk). Restore from it after the install, then delete it.
df -h /mnt/bulk; sudo du -sxh /home/muon /var/lib # does it fit?
sudo mkdir -p /mnt/bulk/pre-reinstall
sudo rsync -aHAX --info=progress2 --exclude=.cache --exclude=refactor \
/home/muon/ /mnt/bulk/pre-reinstall/home/
sudo systemctl stop docker.service docker.socket # consistent volumes
sudo rsync -aHAX --info=progress2 --exclude=docker/overlay2 \
/var/lib/ /mnt/bulk/pre-reinstall/var-lib/
sudo cp -a /etc/ssh /etc/machine-id /mnt/bulk/pre-reinstall/
# 5. The sops key is retrievable (the install needs it).
rbw get sops | head -c 20; echo
# 6. Flip the host to the disko layout and push it: muon sets
# `impermanent = true` in modules/hosts/muon/configuration.nix
# (then delete _legacy-disks.nix once it boots).
During the install (the block above), additionally:
- hardware-configuration: after
nixos-generate-config, don'tcp:diff /mnt/etc/nixos/hardware-configuration.nix modules/hosts/$(hostname)/_hardware-configuration.nixand port only detection changes (kernel modules, CPU), keeping the hand edits. - SSH host keys: muho pins muon's ed25519 key (builder / cache), so carry
the old ones over before
nixos-install(see_persist.nix):sudo install -D -m600 /mnt/bulk/pre-reinstall/ssh/ssh_host_* -t /mnt/persist/etc/ssh/(/mnt/bulkisn't mounted in the installer: mount sdb somewhere first and adjust the path.) - State that needs restoring from
pre-reinstall/var-lib/after the first boot:private/actual,tailscale,syncthing,i2pd,libvirt,archive. Stop the matching service, copy, fix ownership, start it again. Under impermanence these live in/persist/var/lib/...(_persist.nix).
Impermanence
Erasure
boot.initrd.postResumeCommands = lib.mkAfter /* bash */ ''
mkdir /btrfs_tmp
mount /dev/mapper/crypted /btrfs_tmp
if [[ -e /btrfs_tmp/root ]]; then
mkdir -p /btrfs_tmp/old_roots
timestamp=$(date --date="@$(stat -c %Y /btrfs_tmp/root)" "+%Y-%m-%-d_%H:%M:%S")
mv /btrfs_tmp/root "/btrfs_tmp/old_roots/$timestamp"
fi
delete_subvolume_recursively() {
IFS=$'\n'
for i in $(btrfs subvolume list -o "$1" | cut -f 9- -d ' '); do
delete_subvolume_recursively "/btrfs_tmp/$i"
done
btrfs subvolume delete "$1"
}
for i in $(find /btrfs_tmp/old_roots/ -maxdepth 1 -mtime +30); do
delete_subvolume_recursively "$i"
done
btrfs subvolume create /btrfs_tmp/root
umount /btrfs_tmp
'';