Operator rule: secrets live in /secrets and consumers reach them from there.
Three subdirectories with the ownership each consumer needs — files/ (loops),
host/ (root: ssh host keys + sops age identity), nginx/ (root:nginx: the
opencode UI htpasswd) — under a 0711 /secrets so nginx can traverse to its own
without the directory being listable.
sshd's hostKeys and sops-nix's sshKeyPaths/keyFile are pointed at /secrets
DIRECTLY rather than through symlinks: the ed25519 host key is load-bearing
beyond ssh, since its age identity (age1tmvg…) is a recipient of cc-ci-secrets,
and a dangling symlink would let sshd write a NEW key and silently make every
cc-ci secret undecryptable. The /etc/ssh symlinks are added for discoverability
only, so nothing depends on activation ordering.
nginx's htpasswd path becomes an option (opencodeUiHtpasswdFile) defaulting
under /secrets, rather than a hard-coded /etc/nginx path.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FqkQq3CDmFWcQ7u1LzoyRz