# Full nginx configuration — rendered to /etc/nginx/nginx.conf # (NOT placed in conf.d/ to avoid include nesting issues with Alpine nginx) user nginx; worker_processes auto; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; log_format kmtn_json escape=json '{' '"time":"$time_iso8601",' '"remote_addr":"$remote_addr",' '"x_forwarded_for":"$http_x_forwarded_for"' '}'; access_log /logs/access.log kmtn_json; sendfile on; upstream ssr_backend { server 127.0.0.1:4200; } server { listen 80; server_name _; root /usr/share/nginx/html; index index.html; # Serve static assets directly from disk (hashed filenames are immutable) location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot|map)$ { expires 1y; add_header Cache-Control "public, immutable"; access_log off; } # Dynamic sitemap.xml + robots.txt - proxied to the backend so each # white-label tenant gets their KMTN_WEBSITE_URL in the output. location = /sitemap.xml { proxy_pass __API_UPSTREAM__/api/sitemap/sitemap.xml; 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 $http_x_forwarded_proto; } location = /robots.txt { proxy_pass __API_UPSTREAM__/api/sitemap/robots.txt; 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 $http_x_forwarded_proto; } # Proxy API calls to the backend service location /api/ { proxy_pass __API_UPSTREAM__; proxy_set_header Host $host; proxy_set_header Origin $http_origin; proxy_set_header Referer $http_referer; 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 $http_x_forwarded_proto; proxy_set_header X-Forwarded-Host $host; # Disable caching through the double-proxy chain proxy_cache off; add_header Cache-Control "no-store, no-cache, must-revalidate" always; add_header Pragma "no-cache" always; add_header Vary "*" always; } # Proxy all page requests to the Angular SSR server. # The SSR server handles both spider SSR rendering and serves CSR shells # to regular users, with fresh station config injected at runtime. location / { proxy_pass http://ssr_backend; 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 $http_x_forwarded_proto; proxy_set_header X-Forwarded-Host $host; # SSR responses should not be cached by intermediate proxies proxy_cache off; add_header X-Powered-By "Angular SSR" always; # Prevent browsers from caching HTML pages — content changes frequently add_header Cache-Control "no-cache, no-store, must-revalidate" always; add_header Pragma "no-cache" always; } } }