server { listen ${PORT}; server_name _; root /usr/share/nginx/html; index index.html; server_tokens off; 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; gzip on; gzip_vary on; gzip_min_length 1024; gzip_types text/css application/javascript application/json image/svg+xml text/plain; location = /healthz { access_log off; default_type text/plain; return 200 "ok\n"; } # Los archivos con hash son inmutables; los inexistentes devuelven 404. location /assets/ { expires 1y; try_files $uri =404; } # Impide publicar archivos ocultos, variables de entorno o metadatos Git. location ~ /\. { deny all; } # No servir HTML como respuesta a una solicitud de un recurso inexistente. location ~* \.(?:js|mjs|css|map|png|jpe?g|gif|svg|ico|webp|woff2?|ttf|json|txt|xml)$ { try_files $uri =404; } location = /index.html { add_header Cache-Control "no-store"; 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; } # React Router: permite abrir o recargar /contact, /blog/2, etc. location / { try_files $uri $uri/ /index.html; } }