fix(nginx): IPv6 listeners — companion mesh HTTP to the node's ULA never connected

Phones on the FIPS mesh reach the node at http://[<fips0 ULA>], but every
shipped nginx config listened on IPv4 only — nothing answered [::]:80/443,
so mesh HTTP failed with the tunnel fully healthy (found live on
framework-pt during the vc24 5G session, 2026-07-23). Canonical conf gains
listen [::] lines and patch_nginx_conf self-heals deployed nodes (covers
the sites-enabled -> archipelago-http dev variant via the existing
canonicalize pass); validated by the existing nginx -t + rollback flow.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
archipelago 2026-07-23 17:57:58 -04:00
parent 908e6185c8
commit 1e89362e71
2 changed files with 27 additions and 0 deletions

View File

@ -991,6 +991,13 @@ async fn patch_nginx_conf(path: &str) -> Result<bool> {
// B13: fedimint block present but lacking the asset-rewrite sub_filters. // B13: fedimint block present but lacking the asset-rewrite sub_filters.
let needs_fedimint_css = content.contains("location /app/fedimint/") let needs_fedimint_css = content.contains("location /app/fedimint/")
&& !content.contains("'href=\"/' 'href=\"/app/fedimint/'"); && !content.contains("'href=\"/' 'href=\"/app/fedimint/'");
// Companion mesh access: phones reach this node over FIPS at its fips0
// ULA (http://[fdxx:…]). Configs shipped before 2026-07-23 listened on
// IPv4 only, so the ULA could never connect — nothing answered [::]:80.
let missing_v6_http = content.contains("listen 80 default_server;")
&& !content.contains("listen [::]:80");
let missing_v6_https = content.contains("listen 443 ssl default_server;")
&& !content.contains("listen [::]:443");
if !missing_app_catalog if !missing_app_catalog
&& !missing_bitcoin_status && !missing_bitcoin_status
&& !missing_lnd_proxy && !missing_lnd_proxy
@ -998,12 +1005,27 @@ async fn patch_nginx_conf(path: &str) -> Result<bool> {
&& !missing_pine_status && !missing_pine_status
&& !has_lnd_dup_cors && !has_lnd_dup_cors
&& !needs_fedimint_css && !needs_fedimint_css
&& !missing_v6_http
&& !missing_v6_https
{ {
return Ok(false); return Ok(false);
} }
let mut patched = content.clone(); let mut patched = content.clone();
if missing_v6_http {
patched = patched.replace(
"listen 80 default_server;",
"listen 80 default_server;\n listen [::]:80 default_server;",
);
}
if missing_v6_https {
patched = patched.replace(
"listen 443 ssl default_server;",
"listen 443 ssl default_server;\n listen [::]:443 ssl default_server;",
);
}
if has_lnd_dup_cors { if has_lnd_dup_cors {
// Drop the redundant nginx-side CORS headers so the backend's single // Drop the redundant nginx-side CORS headers so the backend's single
// validated Access-Control-Allow-Origin is the only one returned. // validated Access-Control-Allow-Origin is the only one returned.

View File

@ -9,6 +9,10 @@ resolver_timeout 5s;
server { server {
listen 80 default_server; listen 80 default_server;
# IPv6 listener is REQUIRED: companion phones reach this node over the
# FIPS mesh at its fips0 ULA (http://[fdxx:…]) — without [::]:80 that
# address can never connect (found live 2026-07-23, framework-pt).
listen [::]:80 default_server;
server_name _; server_name _;
root /opt/archipelago/web-ui; root /opt/archipelago/web-ui;
@ -901,6 +905,7 @@ server {
# HTTPS - required for PWA install (Add to Home Screen) from dev servers # HTTPS - required for PWA install (Add to Home Screen) from dev servers
server { server {
listen 443 ssl default_server; listen 443 ssl default_server;
listen [::]:443 ssl default_server;
server_name _; server_name _;
ssl_certificate /etc/archipelago/ssl/archipelago.crt; ssl_certificate /etc/archipelago/ssl/archipelago.crt;