No description
  • Nix 68%
  • JavaScript 10.4%
  • Python 7.6%
  • Shell 4.9%
  • Luau 3.3%
  • Other 5.7%
Find a file
2026-10-24 09:03:55 +00:00
_sources apps: drop parked packages (vesktop patch, librediscord, stremio-linux-shell, dcts-client-shipping + its nvfetcher source) 2026-10-11 20:15:07 +00:00
docs archive: archive-status treats an activating oneshot as running (is-active returned non-zero mid-run, so it said idle and skipped the live remote size); docs start it with --no-block and read the journal with -a 2026-10-17 11:50:26 +00:00
modules fix: mod bind 2026-10-24 09:03:55 +00:00
.envrc docs: AGENTS.md for agent sessions in this repo; .envrc points at devshell/devshell.nix 2026-10-12 12:15:04 +00:00
.gitignore gitignore: trash-cli's .Trash-*/ (trash inside the opencode sandbox puts it in the repo root, its own mount) 2026-10-14 21:04:44 +00:00
.sops.yaml muba: offsite backup laptop joins the flake (wireguard id 6, colmena over wg0, builds on muho), its 3.6T LUKS disk unlocks from a key file and never blocks boot; first install runbook in docs/BACKUP.md 2026-10-12 15:52:11 +00:00
AGENTS.md AGENTS.md: open Forgejo PRs with AGit push options 2026-10-15 12:22:23 +00:00
flake.lock flake.lock: Update 2026-10-19 02:43:14 +00:00
flake.nix agent-dashboard: remove (moved to hefring-platform) 2026-10-15 15:13:48 +00:00
nvfetcher.toml apps: drop parked packages (vesktop patch, librediscord, stremio-linux-shell, dcts-client-shipping + its nvfetcher source) 2026-10-11 20:15:07 +00:00
README.md README: reinstalling an existing host: what disko wipes vs restic's allow-list, a pre-wipe safety-net copy to /mnt/bulk, and not overwriting the hand-edited hardware-configuration 2026-10-17 11:50:26 +00:00
statix.toml flake: nix fmt (alejandra) and format/deadnix/statix checks; format the 11 unformatted files, statix fixes (inherit, _: patterns, parens, or), statix.toml drops repeated_keys 2026-10-12 09:57:04 +00:00

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't cp: diff /mnt/etc/nixos/hardware-configuration.nix modules/hosts/$(hostname)/_hardware-configuration.nix and 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/bulk isn'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
  '';