@@ -69,6 +69,23 @@ http {
6969 application/manifest+json webmanifest;
7070 }
7171
72+ # static files with no sensitive content - cache with revalidation
73+ location ~ * \.(ico|png|svg|webp|woff|woff2|ttf|otf|eot)$ {
74+ add_header X-Content-Type-Options "nosniff" ;
75+ add_header X-Frame-Options "SAMEORIGIN" ;
76+ add_header Cache-Control "public, max-age=86400, must-revalidate" ;
77+ add_header Permissions-Policy "accelerometer=(), ambient-light-sensor=(), autoplay=(), battery=(), camera=(), cross-origin-isolated=(), display-capture=(), document-domain=(), encrypted-media=(), execution-while-not-rendered=(), execution-while-out-of-viewport=(), fullscreen=(), geolocation=(), gyroscope=(), keyboard-map=(), magnetometer=(), microphone=(), midi=(), navigation-override=(), payment=(), picture-in-picture=(), publickey-credentials-get=(), screen-wake-lock=(), sync-xhr=(), usb=(), web-share=(), xr-spatial-tracking=()" ;
78+ include /home/web/nginx/csp-header.conf;
79+ try_files $uri =404 ;
80+ }
81+
82+ # robots.txt and sitemap - no-store to avoid caching crawl instructions
83+ location ~ * ^/( robots\.txt|sitemap\.xml)$ {
84+ add_header X-Content-Type-Options "nosniff" ;
85+ add_header Cache-Control "no-store" ;
86+ try_files $uri =404 ;
87+ }
88+
7289 # all assets contain hash in filename, cache forever
7390 location ^~ /assets/ {
7491 charset utf-8;
@@ -91,17 +108,14 @@ http {
91108 try_files $uri =404 ;
92109 }
93110
94- location / {
95- autoindex off;
96- expires off;
111+ # Runtime config injected as a plain JS file served from 'self' — no inline script needed
112+ location = /config.js {
97113 charset utf-8;
114+ default_type application/javascript;
98115 add_header X-Content-Type-Options "nosniff" ;
99- add_header X-Frame-Options "SAMEORIGIN" ;
100- add_header Cache-Control "public, max-age=0, s-maxage=0, must-revalidate" always;
101- add_header Permissions-Policy "accelerometer=(), ambient-light-sensor=(), autoplay=(), battery=(), camera=(), cross-origin-isolated=(), display-capture=(), document-domain=(), encrypted-media=(), execution-while-not-rendered=(), execution-while-out-of-viewport=(), fullscreen=(), geolocation=(), gyroscope=(), keyboard-map=(), magnetometer=(), microphone=(), midi=(), navigation-override=(), payment=(), picture-in-picture=(), publickey-credentials-get=(), screen-wake-lock=(), sync-xhr=(), usb=(), web-share=(), xr-spatial-tracking=()" ;
102- include /home/web/nginx/csp-header.conf;
103- try_files $uri $uri / /index .html;
116+ add_header Cache-Control "no-store" ;
104117 ssi on;
118+ ssi_types application/javascript;
105119 set $apiUrl "${VITE_API_URL}" ;
106120 set $logLevel "${VITE_APP_LOG_LEVEL}" ;
107121 set $authType "${VITE_AUTH_TYPE}" ;
@@ -118,6 +132,19 @@ http {
118132 set $docsUrl "${VITE_DOCS_URL}" ;
119133 set $mazeId "${VITE_MAZE_ID}" ;
120134 set $appBaseName "${VITE_APP_BASE_NAME}" ;
135+ try_files /config.js =404 ;
136+ }
137+
138+ location / {
139+ autoindex off;
140+ expires off;
141+ charset utf-8;
142+ add_header X-Content-Type-Options "nosniff" ;
143+ add_header X-Frame-Options "SAMEORIGIN" ;
144+ add_header Cache-Control "public, max-age=0, s-maxage=0, must-revalidate" always;
145+ add_header Permissions-Policy "accelerometer=(), ambient-light-sensor=(), autoplay=(), battery=(), camera=(), cross-origin-isolated=(), display-capture=(), document-domain=(), encrypted-media=(), execution-while-not-rendered=(), execution-while-out-of-viewport=(), fullscreen=(), geolocation=(), gyroscope=(), keyboard-map=(), magnetometer=(), microphone=(), midi=(), navigation-override=(), payment=(), picture-in-picture=(), publickey-credentials-get=(), screen-wake-lock=(), sync-xhr=(), usb=(), web-share=(), xr-spatial-tracking=()" ;
146+ include /home/web/nginx/csp-header.conf;
147+ try_files $uri $uri / /index .html;
121148 }
122149 }
123150}
0 commit comments