0eed557f95
Make the production deploy foolproof against the shared nginx container's read-only bind mounts on the Digital Ocean droplet. The previous maintenance flow tried to docker-cp/docker-exec into /var/www/html and /etc/nginx/conf.d, both of which are mounted :ro on prod, and /var/www/html happens to point at the WordPress html dir — so writes either failed silently or risked scribbling into another site's tree. Maintenance assets and the engagement flag are now written directly to host paths (/docker/nginx/maintenance and /docker/nginx/conf.d/maintenance.flag) that nginx already sees through its existing bind mounts, so the script no longer depends on a writable container layer, survives container rebuilds, and works regardless of read_only settings. A pre-flight check verifies the maintenance bind mount is actually present on the nginx container and fails fast with a clear "run the one-time setup" message if it isn't, instead of silently serving stale content. The nginx config now serves maintenance.html and /m/ from a dedicated /var/www/maintenance root rather than sharing the WordPress html dir. On the front end, hero images on Pack Walks, 1:1 Walks and Puppy Visits were rendering at whatever aspect ratio their source files happened to have, so one page felt tall, another wide, another oversized. They are now locked to a 4:3 frame with object-fit: cover, matching the About Us section images, which were given the same treatment. The About Us body grid was also alternating between 0.7fr/1.3fr and 1.3fr/0.7fr columns depending on whether a section was reversed, which made the copy width jump between sections; both layouts are now an even 50/50 split, with the existing order swap still handling the image-left vs image-right alternation. The reveal-on-scroll action used to require 18% of an element to intersect before fading it in, with an additional -8% bottom margin, which meant the section directly below a service-page hero stayed invisible on initial load until the user scrolled — making the page look blank below the hero on navigation. The action now does a synchronous bounding-rect check on mount and reveals anything already in the viewport immediately, falling back to the IntersectionObserver for everything below the fold. The "Explore our services" block on About Us was a bespoke icon-tile grid that did not match the homepage's "What we do" cards; it now reuses the shared ServicesSection component (with the heading exposed as a prop), so both pages produce identical card layout, descriptions, "from $" prices, and Learn more CTAs. The footer Explore column was missing the About Us link — added between Our Pricing and Contact Us so it propagates through the homepage content sync into PostgreSQL on the next deploy. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
119 lines
3.7 KiB
Plaintext
119 lines
3.7 KiB
Plaintext
limit_req_zone $binary_remote_addr zone=goodwalk_limit:10m rate=20r/s;
|
|
|
|
server {
|
|
listen 80;
|
|
server_name goodwalk.co.nz www.goodwalk.co.nz;
|
|
|
|
location /.well-known/acme-challenge/ {
|
|
root /var/www/certbot;
|
|
try_files $uri =404;
|
|
}
|
|
|
|
location / {
|
|
return 301 https://www.goodwalk.co.nz$request_uri;
|
|
}
|
|
}
|
|
|
|
server {
|
|
listen 443 ssl;
|
|
server_name goodwalk.co.nz;
|
|
|
|
ssl_certificate /etc/letsencrypt/live/goodwalk.co.nz/fullchain.pem;
|
|
ssl_certificate_key /etc/letsencrypt/live/goodwalk.co.nz/privkey.pem;
|
|
|
|
return 301 https://www.goodwalk.co.nz$request_uri;
|
|
}
|
|
|
|
server {
|
|
listen 443 ssl;
|
|
server_name www.goodwalk.co.nz;
|
|
|
|
ssl_certificate /etc/letsencrypt/live/goodwalk.co.nz/fullchain.pem;
|
|
ssl_certificate_key /etc/letsencrypt/live/goodwalk.co.nz/privkey.pem;
|
|
|
|
ssl_protocols TLSv1.2 TLSv1.3;
|
|
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
|
|
ssl_prefer_server_ciphers off;
|
|
ssl_session_cache shared:SSL:10m;
|
|
ssl_session_timeout 1d;
|
|
ssl_session_tickets off;
|
|
|
|
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
|
add_header X-Frame-Options SAMEORIGIN always;
|
|
add_header X-Content-Type-Options nosniff always;
|
|
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
|
|
|
gzip on;
|
|
gzip_vary on;
|
|
gzip_proxied any;
|
|
gzip_comp_level 6;
|
|
gzip_types text/plain text/css text/xml application/json application/javascript application/xml+rss image/svg+xml;
|
|
|
|
# Re-resolve Docker service/container names after container rebuilds so
|
|
# 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/maintenance;
|
|
internal;
|
|
add_header Cache-Control "no-store" always;
|
|
}
|
|
|
|
# Static assets used only by the maintenance page (logo, etc.). Served
|
|
# from a dedicated bind mount so they remain reachable while the
|
|
# SvelteKit app is down and do not collide with any other site's html dir.
|
|
location /m/ {
|
|
root /var/www/maintenance;
|
|
access_log off;
|
|
add_header Cache-Control "public, max-age=3600" always;
|
|
}
|
|
|
|
location ~* /\.(git|env|htaccess) {
|
|
deny all;
|
|
}
|
|
|
|
location = /xmlrpc.php {
|
|
deny all;
|
|
}
|
|
|
|
location = /wp-login.php {
|
|
return 404;
|
|
}
|
|
|
|
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;
|
|
proxy_http_version 1.1;
|
|
proxy_set_header Host $host;
|
|
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;
|
|
}
|
|
|
|
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;
|
|
proxy_set_header Host $host;
|
|
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_set_header Upgrade $http_upgrade;
|
|
proxy_set_header Connection "upgrade";
|
|
}
|
|
}
|