From 4730239f843824d41094db9316b082784b446cb7 Mon Sep 17 00:00:00 2001 From: Babissimo Date: Tue, 15 Sep 2026 15:09:58 +0100 Subject: [PATCH] Retire the fleet's legacy vhost, now Cloudflare routes that name ${HOST_LEGACY_REDIRECT} existed to proxy tower-finder.retina.fm, the name the fleet calls, to tower-finder-service. Since the origin flip of 2026-09-14 Cloudflare sends that name to the service's own edge on 8443, so nothing reaches this vhost and it is dead weight. Held back from the UI removal it was originally part of, because it carries a risk that change does not. Until this merges, deleting the Cloudflare origin rule is a working rollback: the name lands here and this vhost proxies it on. Afterwards it is not, and worse than merely absent. The template declares no default_server on 443, so nginx falls back to the FIRST 443 block, which is the towers SPA. A node calling /api/towers would then be answered with an HTML page and a 200, and fail on decode rather than on a status it can branch on. Merge this only once the flip is trusted enough to give that rollback up. A catch-all default_server that refused unmatched hostnames outright would turn the failure loud, and is worth doing, but it changes behaviour for every unmatched name rather than this one and belongs in its own change. EXPECTED_TLS_VHOSTS drops 8 to 7 alongside the removed vhost; it is hardcoded and fails all three environments at once if left behind. Co-Authored-By: Claude Opus 5 --- backend/tests/nginx_helpers.py | 1 - backend/tests/test_towers_vhost_coverage.py | 8 ++----- deploy/check-env-parity.py | 3 +-- deploy/nginx/nginx.conf.template | 23 +-------------------- deploy/render-nginx-config.py | 1 - docker-compose.local.yml | 1 - docker-compose.prod.yml | 1 - docker-compose.staging.yml | 1 - docker-compose.test.yml | 1 - 9 files changed, 4 insertions(+), 36 deletions(-) diff --git a/backend/tests/nginx_helpers.py b/backend/tests/nginx_helpers.py index 26c95b2f..20d311ae 100644 --- a/backend/tests/nginx_helpers.py +++ b/backend/tests/nginx_helpers.py @@ -25,7 +25,6 @@ "HOST_ADMIN": "admin.example.com", "HOST_DATA": "data.example.com", "HOST_TESTMAP": "testmap.example.com", - "HOST_LEGACY_REDIRECT": "tower-finder.example.com", "CSP_CONNECT_SRC": "https://api.example.com", } diff --git a/backend/tests/test_towers_vhost_coverage.py b/backend/tests/test_towers_vhost_coverage.py index 2b2b08b9..51767803 100644 --- a/backend/tests/test_towers_vhost_coverage.py +++ b/backend/tests/test_towers_vhost_coverage.py @@ -68,12 +68,8 @@ def routed_roles() -> set[str]: def test_the_template_routes_the_roles_we_think_it_does(routed_roles): - """A new routed vhost must be added to _ROLE_TO_SMOKE_VAR and the smoke test. - - HOST_LEGACY_REDIRECT is the fleet's own name for the service, proxied whole - rather than at /api/towers, and is not part of the SPA seam. - """ - assert routed_roles - {"HOST_LEGACY_REDIRECT"} == set(_ROLE_TO_SMOKE_VAR) + """A new routed vhost must be added to _ROLE_TO_SMOKE_VAR and the smoke test.""" + assert routed_roles == set(_ROLE_TO_SMOKE_VAR) def test_the_smoke_test_probes_every_routed_vhost(routed_roles): diff --git a/deploy/check-env-parity.py b/deploy/check-env-parity.py index f0f07708..475a367c 100755 --- a/deploy/check-env-parity.py +++ b/deploy/check-env-parity.py @@ -52,7 +52,7 @@ # Every vhost the template defines must be TLS in a deployed environment. Update # this alongside the template if a vhost is added or removed. -EXPECTED_TLS_VHOSTS = 8 +EXPECTED_TLS_VHOSTS = 7 # Key paths permitted to differ between the environments, as regexes matched # against the dotted path into the merged compose tree. @@ -175,7 +175,6 @@ def _compile_allowed(entries) -> tuple: "HOST_ADMIN", "HOST_DATA", "HOST_TESTMAP", - "HOST_LEGACY_REDIRECT", "CSP_CONNECT_SRC", ) diff --git a/deploy/nginx/nginx.conf.template b/deploy/nginx/nginx.conf.template index abf8e0ff..e44b1da0 100644 --- a/deploy/nginx/nginx.conf.template +++ b/deploy/nginx/nginx.conf.template @@ -19,7 +19,7 @@ # Redirect all HTTP → HTTPS server { listen 80; - server_name ${HOST_MAIN} ${HOST_API} ${HOST_MAP} ${HOST_DASH} ${HOST_ADMIN} ${HOST_DATA} ${HOST_TESTMAP} ${HOST_LEGACY_REDIRECT} _; + server_name ${HOST_MAIN} ${HOST_API} ${HOST_MAP} ${HOST_DASH} ${HOST_ADMIN} ${HOST_DATA} ${HOST_TESTMAP} _; return 301 https://$host$request_uri; } # RETINA_ENDIF @@ -316,24 +316,3 @@ server { # RETINA_INCLUDE snippets/spa.conf } - -# ${HOST_LEGACY_REDIRECT} — standalone tower-finder-service, the name the fleet -# calls. `retina-spectrum` reads it from retina-node's compose and nothing -# overrides it, so this name cannot move without an OTA rollout. -server { - # RETINA_IF TLS - listen 443 ssl; - # RETINA_ELSE - listen 80; - # RETINA_ENDIF - server_name ${HOST_LEGACY_REDIRECT}; - - # RETINA_IF TLS - # RETINA_INCLUDE snippets/tls.conf - # RETINA_ENDIF - # RETINA_INCLUDE snippets/security-headers-api.conf - - location / { - # RETINA_INCLUDE snippets/tower-finder.conf - } -} diff --git a/deploy/render-nginx-config.py b/deploy/render-nginx-config.py index 08919796..c7e317f5 100755 --- a/deploy/render-nginx-config.py +++ b/deploy/render-nginx-config.py @@ -53,7 +53,6 @@ "HOST_ADMIN", "HOST_DATA", "HOST_TESTMAP", - "HOST_LEGACY_REDIRECT", "CSP_CONNECT_SRC", ) diff --git a/docker-compose.local.yml b/docker-compose.local.yml index cf851339..0f931113 100644 --- a/docker-compose.local.yml +++ b/docker-compose.local.yml @@ -75,7 +75,6 @@ services: - HOST_ADMIN=admin.localhost - HOST_DATA=data.localhost - HOST_TESTMAP=testmap.localhost - - HOST_LEGACY_REDIRECT=tower-finder.localhost - CORS_ORIGINS=http://towers.localhost:8080,http://api.localhost:8080,http://map.localhost:8080,http://testmap.localhost:8080,http://dash.localhost:8080,http://data.localhost:8080 # The published port is part of the origin, so these carry :8080 where the # deployed values do not. ws:// rather than wss:// for the same reason the diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index 5527ac0e..b4b6abd0 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -68,7 +68,6 @@ services: # hostnames are tokenised. So the block still renders, under a name with # no DNS record, and never receives a request. - HOST_TESTMAP=testmap-retired.retina.fm - - HOST_LEGACY_REDIRECT=tower-finder.retina.fm # The only host-naming part of the CSP. wss://*.retina.fm already covers # both environments, so only the two explicit origins vary. - CSP_CONNECT_SRC=https://api.retina.fm https://admin.retina.fm wss://*.retina.fm diff --git a/docker-compose.staging.yml b/docker-compose.staging.yml index 5b5a2bb5..af72aadc 100644 --- a/docker-compose.staging.yml +++ b/docker-compose.staging.yml @@ -79,7 +79,6 @@ services: # staging-map.retina.fm serves identical data if a staging-prefixed name is # ever wanted back. - HOST_TESTMAP=testmap.retina.fm - - HOST_LEGACY_REDIRECT=staging-tower-finder.retina.fm # The only host-naming part of the CSP. wss://*.retina.fm already covers # both environments, so only the two explicit origins vary. - CSP_CONNECT_SRC=https://staging-api.retina.fm https://staging-admin.retina.fm wss://*.retina.fm diff --git a/docker-compose.test.yml b/docker-compose.test.yml index a98a4531..9bdea8e8 100644 --- a/docker-compose.test.yml +++ b/docker-compose.test.yml @@ -92,7 +92,6 @@ services: - HOST_ADMIN=test-admin.retina.fm - HOST_DATA=test-data.retina.fm - HOST_TESTMAP=test-testmap.retina.fm - - HOST_LEGACY_REDIRECT=test-tower-finder.retina.fm - CSP_CONNECT_SRC=https://test-api.retina.fm https://test-admin.retina.fm wss://*.retina.fm # This droplet was resized 2026-08-14 to 4 cores / 8 GB (from staging's # 2-core size) because the solver could not keep up with this fleet: at