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 80; server_name onboarding.goodwalk.co.nz; location /.well-known/acme-challenge/ { root /var/www/certbot; try_files $uri =404; } location / { return 301 https://onboarding.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"; } } server { listen 443 ssl; server_name onboarding.goodwalk.co.nz; ssl_certificate /etc/letsencrypt/live/onboarding.goodwalk.co.nz/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/onboarding.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; resolver 127.0.0.11 ipv6=off valid=30s; location ~* /\.(git|env|htaccess) { deny all; } location /api/onboarding-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/onboarding-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"; } }