Infrastructure
├── modules/ # the services and roles those hosts enable
├── overlays/ # package overrides the hosts share
├── flake.nix # the entry point
└── flake.lock # every input pinned to a revision
What this is
My infrastructure is declared, not administered. Every machine is described in Nix code, the description lives in Git, and the running system is whatever the current revision says it is. Nothing is installed by hand on a live host, and nothing about a host’s state exists only on that host.
That has three consequences worth stating plainly: a change is reviewable before it happens, a machine is reproducible from its declaration, and a bad deploy is reverted instead of debugged in place.
The two repositories
The fleet is split into two flakes on purpose.
The public flake carries the parts that describe how a machine is built: one directory per host, and a module tree those hosts inherit — kernel and SSH hardening, compressed swap, the internal DNS zone, secrets handling, the deploy health gate, and the agents that ship metrics and logs. It is published, so the shape of the fleet is inspectable without exposing anything that protects it.
The private flake carries what only means something for a running service: the client-facing tiers, the credentials and key material, the deployment wiring those services need, and the recovery runbooks. It is consumed as a pinned input, never vendored, and it is not published.
Secrets are encrypted at rest in the repository and decrypted at activation, on the host that needs them. There is no plaintext credential in either flake, none baked into a build, and none pasted into a CI variable.
How a change reaches a host
- A pull request. CI evaluates the whole configuration and builds every host the change touches, then runs the repository’s gates over the result.
- A merge to main. A self-hosted runner builds the affected hosts and activates the new generation on each of them.
- A health gate. The deploy polls the host’s critical units until they are active again — a unit still activating does not count — and then asserts that nothing on the host sits in a failed state.
- An automatic rollback. If the gate is violated, the host returns to the previous generation by itself. A deploy that cannot prove itself healthy does not stay.
- A weekly input update. Dependencies are advanced on a schedule, through the same gate, as the only unattended path that moves an input. Nothing else upgrades a host: main moves, and the hosts follow.
The network
One machine is reachable from the internet. Everything else speaks only over an encrypted mesh, and the administrative paths — SSH, the forge, the dashboards — are inside that mesh rather than exposed and authenticated at the edge.
- The public surface is a deliberate list, not a default one: the web port and its ACME companion, and one relay needed for calls. Nothing else is open.
- DNS resolves inside the network, so queries are not visible to the network the device happens to be on.
- Host-to-host traffic is encrypted. A machine that has not been joined to the mesh is not addressable at all, and a scanner finds nothing to authenticate against.
- The client VPN tiers run on the same design: the tunnel is the same data path for all of them, and the tiers differ in the DNS posture the client gets, not in how the traffic is carried.
Backups and recovery
- Database state is backed up physically with point-in-time recovery; file state is snapshotted on a schedule. Both are encrypted before they leave the host.
- Backups land off-site, in an object store the fleet does not operate.
- The restore path is documented and exercised, not assumed: a machine can be rebuilt from its declaration plus the encrypted backups, within a recovery time that is stated and tested rather than hoped for.
- Retention is bounded by data class rather than by disk space — the shortest window for client and visitor data, the longest for operational data.
Monitoring and the published audit
Every host ships metrics and logs into a central stack with bounded retention, and dashboards and alerts read from that. On top of it runs the part worth mentioning here: a daily check re-derives the state of each host, tests the logging posture behaviourally — re-applying the setting and then looking for what was actually written, rather than reading it off a config file — and signs a report per host. Those reports are published, with monthly roll-ups that freeze once closed, at Infrastructure audit.
That is the difference between a claim and a claim you can check.
What is deliberately not on this page
This page describes how the infrastructure is built, not what is in it. There are no host names, no network addresses, no ports, no service inventory, and no credentials here — those belong in the repositories, and the ones that matter are in the private flake. If you want the specifics of how a part of it works, that is what an audit is for.