Sovereign infrastructure from one typed specification: a server, its websites, DNS, git, backups and recovery
sov docs operations.md
3.9 kB · 72 lines
Markdown
at main

Operations #

Everything done from outside the server is a command, run in the instance repository: nix run .#sov -- <command> (or sov <command> in its dev shell). sov help lists them. Each one is idempotent where it can be, never shows a secret, and makes its repository changes as signed commits that the server deploys by itself.

Day to day #

Change anything edit the spec or a site, signed commit, git push
Is everything fine? sov status (the live checks; they also run hourly and alarm on failure)
Does recovery work? sov drill (also runs monthly and alarms on failure)

Secrets #

sov secrets lists every secret: what it is, where it lives, how a new one is made. They are declared next to the code that uses them (sov.secrets in the modules).

sov rotate <secret>... replaces secrets; sov rotate --all replaces every secret kept in git: the response to "a key leaked". Generated secrets need nothing from you. For secrets of outside services (healthchecks.io, Hetzner, Bluesky) it opens the right page, tells you what to click, and takes the new value in a hidden prompt. The order is always: the new value works before the old one stops.

Secret kind What rotation does
restic password the bucket accepts the new password, the server switches, the old one is removed
DNS secondaries secret the server switches, then the secondaries (Hetzner API)
host key both keys may decrypt and open the bucket, the server switches, the old key is removed
mirror deploy key the server makes a new key; you register it on the mirror
pasted tokens new token stored and deployed; you delete the old one on the service

The owner's key #

sov key rotate makes a new owner key (in the file git signs with), registers it everywhere (server login, deploy signatures, secrets, source bucket, Tangled), switches, and removes the old key everywhere. The one step left to you is printed: the key on GitHub.

If the owner's key is lost: use the paper key (below) to decrypt, reinstall from the source bucket (sov install, through the provider's rescue system), then sov key rotate and sov paper print.

The paper recovery key #

sov paper print makes a new recovery key (age): every secret is encrypted to it, and it opens the source bucket. The previous paper key stops working. It writes a printable sheet: the key in short lines with check codes and a QR code, plus the recovery steps for this instance. Print it, store it offline, delete the file.

sov paper check (yearly; the alarm reminds you): type the key in from the paper, line by line. It verifies the key decrypts the secrets and opens the bucket, and resets the reminder.

Once per new thing #

A repository on the knot sov add repo <name> "<description>", then add the printed entry to the spec
A DNS zone add it to the spec's dns.records, deploy, sov add zone <zone>, then point the domain's nameservers to spec.dns.nameservers
A domain moved to INWX sov add domain --prices <domain>, --check, then without flags (asks for the INWX login and auth codes)
A GitHub mirror repos.<name>.mirror = { owner; name; }, deploy, create the repository, register the key: ssh admin@<server> sudo ssh-keygen -y -f /var/lib/sov/secrets/mirror_key_<name> as deploy key with write access

Recovery #

sov install <user>@<ip> wipes the machine and installs the instance; on first boot it restores the state from the source bucket and starts with the same identity. The monthly drill does exactly this on a temporary VM. The paper sheet lists the steps for the case where everything else is lost.

The source bucket's door (in the box's .ssh/authorized_keys, kept by sov rotate host_key):

command="rclone serve restic --stdio /home/<dir>",restrict ssh-ed25519 <secrets/host_key.pub>