Files
homepage_relaunch/docker/nginx.conf
T
2026-10-05 10:44:55 +02:00

87 lines
2.8 KiB
Nginx Configuration File

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;
}
# The proof-of-work challenge the form solves before it sends; issued by the same handler.
location = /contact/challenge {
limit_except GET { deny all; }
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_read_timeout 10s;
}
# 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;
}
}