# Infra runbook (mdBook), built at Nix-build time from ./docs and served by Caddy. # Reachable only over the ZeroTier mesh (firewall rule below); the public side is # already closed by the Hetzner cloud firewall. Imported by control only. { config, lib, pkgs, ... }: let mesh = import ./mesh-hosts.nix { inherit config lib; }; port = 8080; site = pkgs.stdenvNoCC.mkDerivation { name = "cnx-infra-docs"; src = ../docs; nativeBuildInputs = [ pkgs.mdbook ]; # mdbook writes a state dir under $HOME; the build sandbox has none. buildPhase = '' export HOME=$TMPDIR mdbook build -d $out ''; dontInstall = true; }; in { # ":port" makes Caddy serve plain HTTP (no automatic TLS) on all interfaces; # the mesh-scoped firewall rule below is what constrains reachability. services.caddy = { enable = true; virtualHosts.":${toString port}".extraConfig = '' root * ${site} # mdBook doesn't fingerprint asset filenames, and every file in the Nix # store carries an epoch (1970) mtime, so file_server's only validator never # changes across redeploys — conditional requests would 304 forever and pin # browsers to stale docs. no-store sidesteps caching entirely; pages are tiny # and mesh-only, so refetching on each load is free. header Cache-Control "no-store" file_server ''; }; networking.firewall.extraInputRules = '' ip6 saddr ${mesh.subnet} tcp dport ${toString port} accept ''; }