From 9d87d08547b0b840cedd845f11b24595d1d50487 Mon Sep 17 00:00:00 2001 From: ponzischeme89 Date: Tue, 5 May 2026 08:45:48 +1200 Subject: [PATCH 1/2] Add maintenance page served by nginx during deploys When the SvelteKit upstream is unreachable (container restart, deploy) nginx now serves a static, brand-styled "Be right back" page instead of the default 502/503. Auto-reloads after 60s so visitors don't sit on it once the app is back. - nginx/maintenance.html: self-contained, no external assets, inline paw SVG, brand colours, contact details fallback - nginx/nginx.conf: proxy_intercept_errors + error_page 502/503/504 on both location blocks; 2s proxy_connect_timeout so nginx fails over fast instead of holding the connection for 60s Deploy note: the html file needs to live at /var/www/html/maintenance.html inside the nginx container (already mounted from /docker/wordpress/goodwalk.co.nz/html). Co-Authored-By: Claude Opus 4.7 --- nginx/maintenance.html | 150 +++++++++++++++++++++++++++++++++++++++++ nginx/nginx.conf | 20 ++++++ 2 files changed, 170 insertions(+) create mode 100644 nginx/maintenance.html diff --git a/nginx/maintenance.html b/nginx/maintenance.html new file mode 100644 index 0000000..ad460cd --- /dev/null +++ b/nginx/maintenance.html @@ -0,0 +1,150 @@ + + + + + + + Be right back | Goodwalk + + + +
+ + +

Goodwalk

+

Be right back!

+

We're updating the site — should only take a minute. Thanks for your patience.

+ +
+ Need us now? Email info@goodwalk.co.nz + or call (022) 642 1011. +
+
+ + + + diff --git a/nginx/nginx.conf b/nginx/nginx.conf index 371ee75..456d1e4 100644 --- a/nginx/nginx.conf +++ b/nginx/nginx.conf @@ -29,6 +29,14 @@ server { gzip on; gzip_types text/plain text/css application/javascript application/json image/svg+xml; + # Served when the SvelteKit upstream is unreachable (deploys, restarts). + # Mounted into the nginx container at /var/www/html/maintenance.html. + location = /maintenance.html { + root /var/www/html; + internal; + add_header Cache-Control "no-store" always; + } + location /api/submit { proxy_pass http://mail-api:8000/submit; proxy_http_version 1.1; @@ -36,6 +44,10 @@ server { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; + + proxy_intercept_errors on; + proxy_connect_timeout 2s; + error_page 502 503 504 = /maintenance.html; } location / { @@ -47,5 +59,13 @@ server { proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; + + # Serve a static maintenance page when the app container is down/restarting, + # rather than nginx's default 502/503. The `=` keeps the original status + # code so search engines treat it as a transient outage, not a real page. + proxy_intercept_errors on; + proxy_connect_timeout 2s; + proxy_next_upstream error timeout http_502 http_503 http_504; + error_page 502 503 504 = /maintenance.html; } } From c2e6282efaf5ce7abe6797269e92c11ca008de92 Mon Sep 17 00:00:00 2001 From: ponzischeme89 Date: Tue, 5 May 2026 14:10:16 +1200 Subject: [PATCH 2/2] Wire maintenance page into deploy script as a dynamic toggle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaces the earlier auto-fallback-on-upstream-error approach with an explicit flag-file toggle controlled by the deploy script. The flag is touched before stopping the app and removed on successful finish (or via trap if the deploy aborts), so a failed deploy doesn't strand the site in maintenance. - nginx/goodwalk.co.nz.svelte.conf.example: error_page 503 routes to /maintenance.html (internal); /m/ serves static maintenance assets; the / and /api/submit blocks return 503 when /etc/nginx/conf.d/ maintenance.flag exists. - nginx/maintenance.html: brand-styled "Be right back" page — full Goodwalk green background, white card with yellow accent, real Goodwalk logo, contact details fallback, auto-reload after 60s. - nginx/logo.png: maintenance-time logo (served from /m/logo.png). - nginx/nginx.conf: reverted the earlier auto-fallback edits; this file is not deployed (the prod conf is goodwalk.co.nz.svelte.conf .example). - scripts/deploy-remote.sh: copies maintenance.html + logo into the nginx container, reloads nginx so the new conf is live, touches the flag, then runs the rebuild, then clears the flag. Adds a trap-based clear_maintenance_flag fallback. Also adds a defensive env-file merger that appends new keys from deploy.env.template without clobbering live values, with a timestamped .env backup. Plus a small a11y polish unrelated to maintenance: - ServicesSection: "Learn more" links now include screen-reader-only "about " context. - base.css: adds .visually-hidden utility class. Co-Authored-By: Claude Opus 4.7 --- nginx/goodwalk.co.nz.svelte.conf.example | 28 +++++ nginx/logo.png | Bin 0 -> 4874 bytes nginx/maintenance.html | 95 ++++++++++++----- nginx/nginx.conf | 20 ---- scripts/deploy-remote.sh | 123 +++++++++++++++++++--- src/lib/components/ServicesSection.svelte | 4 +- src/lib/styles/base.css | 12 +++ 7 files changed, 219 insertions(+), 63 deletions(-) create mode 100644 nginx/logo.png diff --git a/nginx/goodwalk.co.nz.svelte.conf.example b/nginx/goodwalk.co.nz.svelte.conf.example index e509f4d..77192db 100644 --- a/nginx/goodwalk.co.nz.svelte.conf.example +++ b/nginx/goodwalk.co.nz.svelte.conf.example @@ -53,6 +53,26 @@ server { # nginx does not keep stale upstream IPs in memory. resolver 127.0.0.11 ipv6=off valid=30s; + # Maintenance mode: when /etc/nginx/conf.d/maintenance.flag exists, + # serve the static "be right back" page with a 503 status. The flag is + # toggled by the deploy script (touch / rm) without reloading nginx. + error_page 503 /maintenance.html; + + location = /maintenance.html { + root /var/www/html; + internal; + add_header Cache-Control "no-store" always; + } + + # Static assets used only by the maintenance page (logo, etc.). Served + # directly from the nginx html mount so they remain reachable while the + # SvelteKit app is down. + location /m/ { + root /var/www/html; + access_log off; + add_header Cache-Control "public, max-age=3600" always; + } + location ~* /\.(git|env|htaccess) { deny all; } @@ -66,6 +86,10 @@ server { } location /api/submit { + if (-f /etc/nginx/conf.d/maintenance.flag) { + return 503; + } + set $goodwalk_mail_api goodwalk_svelte_mail_api:8000; limit_req zone=goodwalk_limit burst=10 nodelay; proxy_pass http://$goodwalk_mail_api/submit; @@ -77,6 +101,10 @@ server { } location / { + if (-f /etc/nginx/conf.d/maintenance.flag) { + return 503; + } + set $goodwalk_frontend goodwalk_svelte_app:3000; proxy_pass http://$goodwalk_frontend; proxy_http_version 1.1; diff --git a/nginx/logo.png b/nginx/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..f3b19a5f23df238dd5556cc4e9f2c3314080f970 GIT binary patch literal 4874 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 literal 0 HcmV?d00001 diff --git a/nginx/maintenance.html b/nginx/maintenance.html index ad460cd..349392b 100644 --- a/nginx/maintenance.html +++ b/nginx/maintenance.html @@ -8,8 +8,8 @@ -
- - -

Goodwalk

-

Be right back!

-

We're updating the site — should only take a minute. Thanks for your patience.

- -
- Need us now? Email info@goodwalk.co.nz - or call (022) 642 1011. +
+
+ Goodwalk
-
+ +
+ + +

Goodwalk

+

Be right back!

+

We're updating the site — should only take a minute. Thanks for your patience.

+ +
+ Need us now? Email info@goodwalk.co.nz + or call (022) 642 1011. +
+
+ +

Auckland Central dog walking · Tiny Gang pack walks · 1:1 walks · Puppy visits

+