-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathnginx.conf
More file actions
159 lines (141 loc) · 5.59 KB
/
nginx.conf
File metadata and controls
159 lines (141 loc) · 5.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# =============================================================================
# Nginx Configuration - Google Authenticator Export Decoder PWA
# =============================================================================
# Optimized for serving a React SPA with:
# - Aggressive caching for hashed assets
# - Gzip compression
# - Security headers
# - PWA service worker support
# =============================================================================
server {
listen 80;
listen [::]:80;
server_name _;
# Root directory for static files
root /usr/share/nginx/html;
index index.html;
# -------------------------------------------------------------------------
# Compression
# -------------------------------------------------------------------------
gzip on;
gzip_vary on;
gzip_min_length 256;
gzip_comp_level 6;
gzip_proxied any;
gzip_types
text/plain
text/css
text/xml
text/javascript
application/javascript
application/json
application/xml
application/rss+xml
application/atom+xml
application/manifest+json
image/svg+xml
font/woff
font/woff2;
# -------------------------------------------------------------------------
# Security Headers
# -------------------------------------------------------------------------
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(self), microphone=()" always;
# Content Security Policy
# - Allows Google Fonts (fonts.googleapis.com, fonts.gstatic.com)
# - Allows camera for QR scanning (via getUserMedia)
# - Allows blob: for QR scanning library
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com data:; img-src 'self' data: blob:; connect-src 'self'; media-src 'self' blob:; object-src 'none'; frame-ancestors 'self';" always;
# -------------------------------------------------------------------------
# PWA Files - No Cache
# -------------------------------------------------------------------------
# Service Worker must never be cached
location = /sw.js {
add_header Cache-Control "no-cache, no-store, must-revalidate";
add_header Pragma "no-cache";
add_header Expires "0";
try_files $uri =404;
}
# Web App Manifest - minimal cache
location = /manifest.webmanifest {
add_header Cache-Control "no-cache, must-revalidate";
types {
application/manifest+json webmanifest;
}
try_files $uri =404;
}
# Workbox files
location ~* ^/workbox-.*\.js$ {
add_header Cache-Control "no-cache, no-store, must-revalidate";
try_files $uri =404;
}
# -------------------------------------------------------------------------
# Static Assets - Aggressive Caching
# -------------------------------------------------------------------------
# Vite uses content hashes in filenames - safe to cache forever
location /assets/ {
add_header Cache-Control "public, max-age=31536000, immutable";
access_log off;
try_files $uri =404;
}
# Localization files - cache with revalidation
location /locales/ {
add_header Cache-Control "public, max-age=3600, must-revalidate";
try_files $uri =404;
}
# Icons and images - 7 days cache
location ~* \.(ico|png|jpg|jpeg|gif|svg|webp)$ {
add_header Cache-Control "public, max-age=604800";
access_log off;
try_files $uri =404;
}
# Fonts - long cache
location ~* \.(woff|woff2|ttf|otf|eot)$ {
add_header Cache-Control "public, max-age=31536000, immutable";
add_header Access-Control-Allow-Origin "*";
access_log off;
try_files $uri =404;
}
# -------------------------------------------------------------------------
# SPA Routing
# -------------------------------------------------------------------------
# Serve index.html for all routes (React Router support)
location / {
try_files $uri $uri/ /index.html;
# index.html should not be cached aggressively
location = /index.html {
add_header Cache-Control "no-cache, must-revalidate";
}
}
# -------------------------------------------------------------------------
# Health Check
# -------------------------------------------------------------------------
location = /health {
access_log off;
add_header Content-Type text/plain;
return 200 "OK";
}
# -------------------------------------------------------------------------
# Security
# -------------------------------------------------------------------------
# Block hidden files (except .well-known for ACME/SSL)
location ~ /\.(?!well-known) {
deny all;
access_log off;
log_not_found off;
}
# Block common attack patterns
location ~* (\.php|\.asp|\.aspx|\.jsp|\.cgi)$ {
deny all;
access_log off;
log_not_found off;
}
# -------------------------------------------------------------------------
# Error Pages
# -------------------------------------------------------------------------
error_page 404 /index.html;
error_page 500 502 503 504 /index.html;
}