# nginx server block for bchanot.fr static site. # Container (nginx-unprivileged) listens on 8080; host port is configured via # docker-compose (PORT env var). A host-level reverse proxy (nginx, Traefik, # Caddy) should terminate TLS and proxy_pass to http://127.0.0.1:${PORT}. server { listen 8080; listen [::]:8080; server_name _; root /usr/share/nginx/html; index index.html; # Don't advertise the nginx version. server_tokens off; # Security headers — shared snippet. Re-included in every location that # sets its own add_header (inheritance is all-or-nothing in nginx). include /etc/nginx/snippets/security-headers.conf; # Forwarded headers — trust only the local reverse proxy (the container # port is bound to 127.0.0.1 in docker-compose). real_ip_header X-Forwarded-For; set_real_ip_from 127.0.0.1; # Compression. gzip on; gzip_vary on; gzip_min_length 1024; gzip_proxied any; gzip_comp_level 6; gzip_types text/plain text/css text/javascript application/javascript application/json application/xml application/pdf image/svg+xml; # Long cache for the PDF (regenerated rarely, content-hash not used). location ~* \.pdf$ { add_header Cache-Control "public, max-age=604800"; include /etc/nginx/snippets/security-headers.conf; } # Short cache for HTML so content updates land fast. location ~* \.html$ { add_header Cache-Control "public, max-age=3600, must-revalidate"; include /etc/nginx/snippets/security-headers.conf; } # Long cache for favicon + image assets (rarely change). location ~* \.(?:ico|svg|png|jpg|jpeg|gif|webp)$ { add_header Cache-Control "public, max-age=2592000, immutable"; include /etc/nginx/snippets/security-headers.conf; access_log off; } # Logs to stdout/stderr (default in nginx images). access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log warn; # Block access to dotfiles (defense-in-depth — none are shipped anyway). location ~ /\. { return 404; } # Default: serve files, fall back to 404. location / { try_files $uri $uri/ =404; } }