From 65feed5fc6c86c10cb56d49d76bc32e343adf649 Mon Sep 17 00:00:00 2001 From: Anthony Ettinger Date: Sat, 17 Oct 2026 09:31:03 +0000 Subject: [PATCH] deploy-ssh 0.1.2: www and other aliases 301 to the first domain; reload nginx on config change OpenInstall's nginx site listed every DOMAINS name in both server blocks and redirected port 80 to https://$host, so www.example.com served the app as a second hostname (pit.world answered 200 with an empty body there). The first name is now canonical: port 80 and a separate 443 block for the others answer 301 to https://. The no-cert path is unchanged so certbot's first challenge still reaches every name. Also: write_nginx piped nginx_conf into put_root_file, so CHANGED=1 was set in a subshell and a changed config never triggered the reload. Process substitution instead. Same fixes as moshcoder/pit.world #5 and #6. Co-Authored-By: Claude Opus 5.5 --- packages/targets/deploy-ssh/bin/install.sh | 29 +++++++++++++++++----- packages/targets/deploy-ssh/package.json | 2 +- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/packages/targets/deploy-ssh/bin/install.sh b/packages/targets/deploy-ssh/bin/install.sh index 16818a41..e50484cc 100755 --- a/packages/targets/deploy-ssh/bin/install.sh +++ b/packages/targets/deploy-ssh/bin/install.sh @@ -25,7 +25,9 @@ # PORT the app listens here, on loopback (default: 3000) # HEALTH_PATH GET this until it answers 2xx/3xx (default: /) # HEALTH_TIMEOUT seconds (default: 120) -# DOMAINS "example.com www.example.com": nginx site for them, none if empty +# DOMAINS "example.com www.example.com": nginx site for them, none if empty. +# The first is canonical: once TLS is up, every other name +# (and plain http) answers 301 to https://. # TLS 1 | 0: Let's Encrypt via certbot (default: 1) # TLS_EMAIL ACME account email (default: none) # STATIC_DIR RUNTIME=static: directory nginx serves (default: dist) @@ -313,8 +315,9 @@ EOF } nginx_conf() { - local cert="$1" first + local cert="$1" first aliases first="${DOMAINS%% *}" + aliases="$(printf '%s' "${DOMAINS#"$first"}" | xargs)" local body if [ "$RUNTIME" = static ]; then local fallback='=404' @@ -342,13 +345,26 @@ server { listen 80; listen [::]:80; server_name $DOMAINS; - return 301 https://\$host\$request_uri; + return 301 https://$first\$request_uri; } +$( [ -n "$aliases" ] && cat < "$backup" 2>/dev/null || : > "$backup" CHANGED=0 - nginx_conf "$cert" | put_root_file "$conf" 0644 + # Not a pipe: put_root_file must run in this shell so CHANGED=1 survives. + put_root_file "$conf" 0644 < <(nginx_conf "$cert") [ -n "$link" ] && { $SUDO test -L "$link" || { $SUDO ln -sfn "$conf" "$link"; CHANGED=1; }; } if [ "$CHANGED" = 1 ]; then if ! $SUDO nginx -t >/dev/null 2>&1; then @@ -407,7 +424,7 @@ write_nginx() { for d in $DOMAINS; do args+=(-d "$d"); done if [ -n "$TLS_EMAIL" ]; then args+=(-m "$TLS_EMAIL"); else args+=(--register-unsafely-without-email); fi if $SUDO certbot "${args[@]}"; then - nginx_conf 1 | put_root_file "$conf" 0644 + put_root_file "$conf" 0644 < <(nginx_conf 1) $SUDO nginx -t && $SUDO systemctl reload nginx log "tls: certificate issued for $DOMAINS" else diff --git a/packages/targets/deploy-ssh/package.json b/packages/targets/deploy-ssh/package.json index 03605378..80baa3b7 100644 --- a/packages/targets/deploy-ssh/package.json +++ b/packages/targets/deploy-ssh/package.json @@ -1,6 +1,6 @@ { "name": "@profullstack/sh1pt-target-deploy-ssh", - "version": "0.1.1", + "version": "0.1.2", "type": "module", "main": "./src/index.ts", "scripts": {