← back to Dw Domain Fleet
fix(nginx): durable :443 socket normalization for fleet HTTPS-000 socket-specificity bug
990e3da49429bf8f1ce6dcac146db13c67bb0756 · 2026-09-09 10:35:01 -0700 · Steve Abrams
Root cause: certbot inherits the vhost wildcard 'listen 80' and emits wildcard
'listen 443 ssl' (0.0.0.0:443); the box's working sites + default_server bind the
specific 45.61.58.125:443, which nginx prefers for external traffic, leaving fleet
vhosts unreachable externally (wrong cert -> curl 000). Add scripts/normalize-listen-socket.sh
(post-certbot :443 IP-bind, idempotent, dry-run default) + document the constraint
in gen-nginx.js (:80 must stay wildcard for the loopback smoke test).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JDeaFL4eeREBZX79tc4cnr
Files touched
M scripts/gen-nginx.jsA scripts/normalize-listen-socket.sh
Diff
commit 990e3da49429bf8f1ce6dcac146db13c67bb0756
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Wed Sep 9 10:35:01 2026 -0700
fix(nginx): durable :443 socket normalization for fleet HTTPS-000 socket-specificity bug
Root cause: certbot inherits the vhost wildcard 'listen 80' and emits wildcard
'listen 443 ssl' (0.0.0.0:443); the box's working sites + default_server bind the
specific 45.61.58.125:443, which nginx prefers for external traffic, leaving fleet
vhosts unreachable externally (wrong cert -> curl 000). Add scripts/normalize-listen-socket.sh
(post-certbot :443 IP-bind, idempotent, dry-run default) + document the constraint
in gen-nginx.js (:80 must stay wildcard for the loopback smoke test).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JDeaFL4eeREBZX79tc4cnr
---
scripts/gen-nginx.js | 11 ++++++++
scripts/normalize-listen-socket.sh | 52 ++++++++++++++++++++++++++++++++++++++
2 files changed, 63 insertions(+)
diff --git a/scripts/gen-nginx.js b/scripts/gen-nginx.js
index b2ec00a..5f91a7c 100644
--- a/scripts/gen-nginx.js
+++ b/scripts/gen-nginx.js
@@ -2,6 +2,17 @@
/**
* gen-nginx.js — generate one nginx vhost per fleet domain → data/nginx/<domain>.conf
* HTTP-only initially (port 80); certbot --nginx adds the 443 block + redirect.
+ *
+ * SOCKET WARNING (root cause of the 2026-09-09 fleet HTTPS-000 outage):
+ * The :80 block MUST stay wildcard `listen 80;` — the deploy smoke test curls
+ * http://127.0.0.1/health with a Host header and needs the wildcard :80 socket.
+ * But certbot inherits that wildcard and emits a wildcard `listen 443 ssl;`
+ * (0.0.0.0:443), while this box's working sites + default_server bind the SPECIFIC
+ * `listen 45.61.58.125:443 ssl`. nginx routes external :443 to the MOST-SPECIFIC
+ * socket, so wildcard-:443 fleet vhosts are unreachable externally (wrong cert →
+ * curl 000). Therefore, AFTER every certbot issuance/renewal, run
+ * scripts/normalize-listen-socket.sh --apply to rewrite the fleet vhosts'
+ * `listen 443 ssl` → `listen 45.61.58.125:443 ssl`. Do NOT IP-bind the :80 line.
*/
const fs = require('fs');
const path = require('path');
diff --git a/scripts/normalize-listen-socket.sh b/scripts/normalize-listen-socket.sh
new file mode 100755
index 0000000..6ab2bb7
--- /dev/null
+++ b/scripts/normalize-listen-socket.sh
@@ -0,0 +1,52 @@
+#!/usr/bin/env bash
+# normalize-listen-socket.sh — fix the fleet HTTPS-000 socket-specificity bug.
+#
+# ROOT CAUSE (proven 2026-09-09): certbot --nginx inherits the vhost's wildcard
+# `listen 80;` and emits a wildcard `listen 443 ssl;` (= 0.0.0.0:443). The working
+# sites on this box (homesonspec, rentv, ...) and the default_server bind the
+# SPECIFIC `listen 45.61.58.125:443 ssl`. nginx delivers an inbound packet to the
+# MOST-SPECIFIC bound socket, so ALL external :443 traffic to the public IP is
+# handled by the IP-bound socket — the fleet vhosts (only on the 0.0.0.0 socket)
+# never receive it externally, so SNI falls through to the wrong cert → curl 000.
+#
+# We CANNOT fix this by IP-binding the vhost's `listen 80` (the deploy smoke test
+# curls http://127.0.0.1/health with a Host header and needs the wildcard :80
+# socket). So we normalize ONLY the :443 IPv4 listen, AFTER certbot has issued.
+#
+# Idempotent. Run this after any certbot issuance/renewal on the fleet vhosts.
+# Usage (on the box): bash normalize-listen-socket.sh [--apply]
+# default = dry-run (prints what would change); --apply edits + nginx -t + reload.
+set -euo pipefail
+
+IP=45.61.58.125
+NGDIR=/etc/nginx/sites-available
+FLEETDIR=/root/public-projects/dw-domain-fleet/data/nginx
+EXTRA=(petitionyour.org) # non-fleet domains sharing the same bug
+APPLY=0; [ "${1:-}" = "--apply" ] && APPLY=1
+
+# authoritative fleet set = the .conf basenames shipped in the repo
+mapfile -t DOMAINS < <(ls "$FLEETDIR" 2>/dev/null | sed 's/\.conf$//')
+DOMAINS+=("${EXTRA[@]}")
+
+changed=0
+for d in "${DOMAINS[@]}"; do
+ f="$NGDIR/$d.conf"
+ [ -f "$f" ] || { echo "skip (no conf): $d"; continue; }
+ # only touch confs that actually have a wildcard IPv4 :443 ssl listen
+ if grep -Eq '^[[:space:]]*listen[[:space:]]+443 ssl' "$f"; then
+ echo "FIX $d : listen 443 ssl -> listen $IP:443 ssl"
+ if [ "$APPLY" = 1 ]; then
+ sed -ri "s#^([[:space:]]*listen[[:space:]]+)443 ssl#\1$IP:443 ssl#" "$f"
+ fi
+ changed=$((changed+1))
+ else
+ echo "ok $d : no wildcard :443 (already IP-bound or no 443 block)"
+ fi
+done
+
+echo "==== $changed conf(s) need normalization ===="
+if [ "$APPLY" = 1 ]; then
+ nginx -t && systemctl reload nginx && echo "RELOADED"
+else
+ echo "(dry-run — re-run with --apply to edit + nginx -t + reload)"
+fi
← e10d68c monetize: render authored content copy verbatim (skip DW wal
·
back to Dw Domain Fleet
·
TK-11322: add red flocked hero asset for barwallpaper.com mo ebca1a8 →