From 47bef090f39e17fbe7dbeebbd4549ece7167318e Mon Sep 17 00:00:00 2001 From: autonomic-bot Date: Mon, 3 Aug 2026 18:41:08 +0000 Subject: [PATCH] nginx(oc): serve oc.commoninternet.net over HTTPS (443) with a self-signed cert MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a 443 listener on the tailscale IP for the opencode vhost, alongside the existing port 80. The name resolves to a CGNAT tailscale IP so Let's Encrypt HTTP-01 can't validate it and there's no DNS-01 provider here; the vhost is tailnet-only, so a self-signed cert (out-of-band at /etc/nginx/oc-selfsigned.*, like oc-htpasswd) is acceptable. addSSL=true is required so the NixOS nginx module actually renders ssl_certificate — without it nginx -t fails and takes the atproto vhost down too. Rationale + regen command documented inline. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_016L6nYYwkCWnrEFKTnKAfet --- .../configuration.nix | 39 ++++++++++++++++++- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/nix/hosts/cc-ci-orchestrator-hetzner/configuration.nix b/nix/hosts/cc-ci-orchestrator-hetzner/configuration.nix index a9568de..02eaccf 100644 --- a/nix/hosts/cc-ci-orchestrator-hetzner/configuration.nix +++ b/nix/hosts/cc-ci-orchestrator-hetzner/configuration.nix @@ -157,8 +157,43 @@ SSHCFG enable = true; recommendedProxySettings = true; virtualHosts."oc.commoninternet.net" = { - # Listen on the tailscale interface only — not the public IP. - listen = [{ addr = "100.84.190.30"; port = 80; ssl = false; }]; + # Listen on the tailscale interface only — not the public IP. Both 80 and 443. + # 443 uses a SELF-SIGNED cert (below): this name resolves to a CGNAT tailscale + # IP, so Let's Encrypt HTTP-01 can't validate it and there is no DNS-01 provider + # configured on this host. The trusted *.ci.commoninternet.net wildcard lives on + # the coop-cloud swarm (91.98.47.73), not here, and doesn't cover this label. + # Self-signed is fine because the vhost is tailnet-only (trusted network); the + # browser shows a one-time trust prompt. (Chosen by operator, 2026-08-03.) + # + # The cert/key are created out of band — same convention as oc-htpasswd, NOT in + # git and NOT in the nix store (a store path would be world-readable): + # + # /etc/nginx/oc-selfsigned.crt root:nginx 0644 + # /etc/nginx/oc-selfsigned.key root:nginx 0640 + # + # Regenerate (10y, SANs = hostname + tailscale IP + ts.net name) with: + # openssl req -x509 -newkey rsa:2048 -nodes -days 3650 \ + # -keyout /etc/nginx/oc-selfsigned.key -out /etc/nginx/oc-selfsigned.crt \ + # -subj /CN=oc.commoninternet.net \ + # -addext "subjectAltName=DNS:oc.commoninternet.net,DNS:cc-ci-orchestrator-1.taila4a0bf.ts.net,IP:100.84.190.30" + # sudo chown root:nginx /etc/nginx/oc-selfsigned.{crt,key} + # sudo chmod 644 /etc/nginx/oc-selfsigned.crt && sudo chmod 640 /etc/nginx/oc-selfsigned.key + # + # NOTE: like oc-htpasswd, if these files go missing nginx fails to START — which + # would take the atproto vhost down with it. Recreate them before rebuilding on + # a fresh host. + listen = [ + { addr = "100.84.190.30"; port = 80; ssl = false; } + { addr = "100.84.190.30"; port = 443; ssl = true; } + ]; + # addSSL (serve BOTH http+https) is required, not cosmetic: the NixOS nginx + # module only renders the `ssl_certificate` directives when a vhost is flagged + # as an SSL vhost. An explicit `listen ... ssl` + sslCertificate WITHOUT this + # flag produces an SSL listener with no cert → `nginx -t` fails and the whole + # service (atproto included) won't start. + addSSL = true; + sslCertificate = "/etc/nginx/oc-selfsigned.crt"; + sslCertificateKey = "/etc/nginx/oc-selfsigned.key"; # HTTP basic auth in front of opencode. The opencode web UI has no # authentication of its own and can drive agent sessions, so since this host