diff --git a/nix/atproto-likes.nix b/nix/atproto-likes.nix index 17398cf..cdc0320 100644 --- a/nix/atproto-likes.nix +++ b/nix/atproto-likes.nix @@ -1,5 +1,4 @@ -# atproto-likes — the "most-liked accounts" web UI, run as a docker-compose stack -# behind the host's nginx. +# atproto-likes — the "most-liked accounts" web UI, run as a docker-compose stack behind nginx. # # ⚠️ COPY. Canonical source: # /srv/project-orchestrator/projects/notplants-atproto/nix/atproto-likes.nix @@ -16,12 +15,16 @@ # proxying to the container on 127.0.0.1:8731 # * ports 80/443 open (they were closed — only 22 was public) # -# DNS: *.commoninternet.net is a wildcard pointing at 143.244.213.108, which is NOT -# this host. Until an explicit A record -# atproto.commoninternet.net -> 168.119.126.100 -# overrides that wildcard, ACME's HTTP-01 challenge cannot succeed and the domain -# keeps resolving elsewhere. nginx still starts in the meantime — NixOS installs a -# self-signed placeholder cert — so nothing else on the host is affected. +# DNS: atproto.commoninternet.net resolves to 143.244.213.108 — the operator's +# gateway (tailnet peer `gateway-server-aug2-9pm`, 100.80.66.110), which fronts this +# host rather than pointing at it directly. So what arrives here is the gateway's +# back-end hop, and the gateway needs a route for this hostname to either +# http://100.84.190.30 (tailnet, preferred) +# http://168.119.126.100 (public) +# preserving the Host header, passing Upgrade/Connection through (the loading page +# is a websocket), and allowing a long read timeout (a cold scan runs minutes). +# ACME here can only succeed if the gateway forwards /.well-known/acme-challenge/; +# otherwise the gateway should own the certificate and `enableACME` can go false. { config, pkgs, lib, ... }: let @@ -63,8 +66,32 @@ in enable = true; recommendedProxySettings = true; virtualHosts.${domain} = { - forceSSL = true; + # addSSL, NOT forceSSL. DNS for this domain points at the gateway + # (143.244.213.108), which fronts this host — so the request that actually + # arrives here is the gateway's back-end hop. If that hop is plain HTTP and + # we answered with a 301 to https://atproto.commoninternet.net/, it would + # resolve straight back to the gateway: a redirect loop. Serve both schemes + # and let the gateway decide where TLS terminates. + addSSL = true; + # Keeps retrying; it can only succeed if the gateway forwards + # /.well-known/acme-challenge/ here, since the A record is the gateway's. + # Until then nginx uses the self-signed placeholder NixOS installs, and the + # acme-atproto… unit sits in `failed`. Set this false if the gateway is to + # own the certificate permanently. enableACME = true; + # The `oc.commoninternet.net` vhost binds explicitly to the tailscale IP on + # port 80. nginx prefers the most specific listen address, so a request to + # 100.84.190.30:80 was only ever matched against THAT server block — this + # vhost, listening on 0.0.0.0, never got a look in, and a gateway hop over + # the tailnet was served the opencode UI instead. Listing the tailscale + # address explicitly here puts both vhosts on that socket, so server_name + # decides, which is what we want. + listen = [ + { addr = "0.0.0.0"; port = 80; ssl = false; } + { addr = "0.0.0.0"; port = 443; ssl = true; } + { addr = "100.84.190.30"; port = 80; ssl = false; } + { addr = "100.84.190.30"; port = 443; ssl = true; } + ]; locations."/" = { proxyPass = "http://127.0.0.1:${toString hostPort}"; # The loading page streams scan progress over a websocket.