server { listen 80; server_name _; root /usr/share/nginx/html; index index.html; # TLS terminates at Dokploy's Traefik; keep redirects relative so they stay on https. absolute_redirect off; # The client address arrives in X-Forwarded-For from Traefik on the private network. set_real_ip_from 10.0.0.0/8; set_real_ip_from 172.16.0.0/12; set_real_ip_from 192.168.0.0/16; real_ip_header X-Forwarded-For; real_ip_recursive on; server_tokens off; gzip on; gzip_comp_level 6; gzip_min_length 1024; gzip_types text/plain text/css text/xml application/xml application/javascript application/json image/svg+xml; add_header X-Content-Type-Options "nosniff" always; add_header Referrer-Policy "strict-origin-when-cross-origin" always; add_header X-Frame-Options "SAMEORIGIN" always; location = /healthz { access_log off; default_type text/plain; return 200 "ok\n"; } # The contact form is the one dynamic path: server/contact.mjs, sending by SMTP. location = /contact { limit_except POST { deny all; } client_max_body_size 64k; proxy_pass http://127.0.0.1:3000; proxy_set_header Host $host; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_read_timeout 30s; proxy_intercept_errors on; error_page 502 503 504 = @contact_down; } # Handler not running: send the visitor to the error page in their language. location @contact_down { if ($http_referer ~ "/de(/|$|#)") { return 303 /de/contact/error; } return 303 /contact/error; } # trailingSlash: 'never' — /team is served from /team/index.html; /team/ redirects to /team. location ~ ^(.+)/$ { return 301 $1$is_args$args; } location / { try_files $uri $uri.html $uri/index.html =404; } # Astro's hashed build assets never change. location ^~ /_astro/ { add_header Cache-Control "public, max-age=31536000, immutable" always; add_header X-Content-Type-Options "nosniff" always; try_files $uri =404; } location ~* \.(?:woff2|mp4|webm|avif|webp|jpg|jpeg|png|svg)$ { add_header Cache-Control "public, max-age=2592000" always; add_header X-Content-Type-Options "nosniff" always; try_files $uri =404; } error_page 404 /404.html; location = /404.html { internal; } }