Repository navigation
Expand file tree
/
Copy pathnginx.conf
More file actions
368 lines (316 loc) · 15 KB
/
Copy pathnginx.conf
File metadata and controls
368 lines (316 loc) · 15 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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
# WebSocket settings
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
# Cache configuration
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=STATIC:10m inactive=24h max_size=1g;
# API cache for frequently requested endpoints
proxy_cache_path /var/cache/nginx/api levels=1:2 keys_zone=API_CACHE:10m inactive=60m max_size=100m;
server {
listen 80 default_server;
# Emit relative Location headers, so the browser resolves a redirect
# against the origin it actually used.
#
# nginx expands a relative `return 30x /path` into an absolute URL by
# default, built from the LISTENER's scheme and the request's Host
# header -- neither of which is the public one here. TLS terminates at
# Cloudflare and this block listens on plain 80, and the blue/green load
# balancer addresses each origin by its colour hostname (see
# docs/MultiServer.md), so `Host` arrives as e.g. blue.openfront.dev.
# `return 302 /#steam-link` below therefore went out as
# `http://blue.openfront.dev/#steam-link`: an internal slot name AND a
# downgrade to a scheme nothing answers on publicly, so /link only
# worked for browsers that silently re-upgraded it (HSTS/HTTPS-First)
# and hung for the rest.
#
# That is the worst possible place for it: /link exists for players
# whose desktop app could NOT open a browser, so it is typed by hand,
# often on a phone with its own HSTS state. Turning absolute redirects
# off fixes the host and the scheme together, and keeps doing so for any
# hostname added later -- a relative Location is valid per RFC 7231.
absolute_redirect off;
# Large cookie support
large_client_header_buffers 4 32k;
proxy_buffer_size 32k;
proxy_busy_buffers_size 48k;
proxy_buffers 4 32k;
# Logging
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
location ^~ /assets/ {
proxy_pass http://127.0.0.1:3000;
proxy_cache STATIC;
proxy_cache_valid 200 302 24h;
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
proxy_cache_lock on;
add_header X-Cache-Status $upstream_cache_status;
add_header Cache-Control "public, max-age=31536000, immutable";
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 $scheme;
}
location ^~ /_assets/ {
proxy_pass http://127.0.0.1:3000;
proxy_cache STATIC;
proxy_cache_valid 200 302 24h;
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
proxy_cache_lock on;
add_header X-Cache-Status $upstream_cache_status;
add_header Cache-Control "public, max-age=31536000, immutable";
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 $scheme;
}
location ~* ^/w(\d+)(/(?:assets|_assets)/.*)$ {
set $worker $1;
proxy_pass http://127.0.0.1:$worker_port$2$is_args$args;
proxy_cache STATIC;
proxy_cache_valid 200 302 24h;
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
proxy_cache_lock on;
add_header X-Cache-Status $upstream_cache_status;
add_header Cache-Control "public, max-age=31536000, immutable";
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
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 $scheme;
}
# Worker locations - Processing this first so worker-specific requests are handled by workers
# This prevents static file regexes from capturing worker requests
location ~* ^/w(\d+)(/.*)?$ {
set $worker $1;
# Preserve query string by appending $is_args$args
proxy_pass http://127.0.0.1:$worker_port$2$is_args$args;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
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 $scheme;
}
# Randomly distribute new-game creation across the live workers; the worker
# mints a self-owned id and returns it. The openfront_workers upstream is
# generated at container start from NUM_WORKERS (generate-nginx-upstream.sh)
# and can be reused by any future endpoint that wants the same balancing.
location = /api/create_game {
proxy_pass http://openfront_workers;
proxy_http_version 1.1;
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 $scheme;
}
# Admin bot create-game: same random-worker balancing as /api/create_game.
# The worker checks the admin bot key, mints a self-owned id, and returns it.
location = /api/adminbot/create_game {
proxy_pass http://openfront_workers;
proxy_http_version 1.1;
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 $scheme;
}
# Admin bot create-pool: same random-worker balancing. One worker mints EVERY
# member of the pool, so the whole pool lands on the host that served this
# request — which is what lets the members share a config and a sibling list.
# Needs its own block: the locations above are exact matches (`=`), so a path
# without one 404s at the proxy and never reaches the worker.
location = /api/adminbot/create_pool {
proxy_pass http://openfront_workers;
proxy_http_version 1.1;
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 $scheme;
}
# Static file handling with proper MIME types and consistent caching
location ~* \.(jpg|jpeg|png|gif|ico|svg|webp|woff|woff2|ttf|eot)$ {
proxy_pass http://127.0.0.1:3000;
# Include MIME types
include /etc/nginx/mime.types;
# Cache configuration for static files
proxy_cache STATIC;
proxy_cache_valid 200 302 24h; # Cache successful responses for 24 hours
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
proxy_cache_lock on;
# Show cache status in response headers
add_header X-Cache-Status $upstream_cache_status;
# Standard proxy headers
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 $scheme;
# Default cache policy for static files
add_header Cache-Control "public, max-age=86400"; # 24 hours
}
# Apple Pay domain verification (served by src/server/Master.ts from a
# vendored file). Static 9 KB that effectively never changes; cached here
# so Apple's fetches — or anyone hammering the URL — are answered from
# nginx instead of reaching node.
location = /.well-known/apple-developer-merchantid-domain-association {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_cache STATIC;
# One cache entry regardless of query string. The default key includes
# $request_uri (query and all), so ?r=1, ?r=2, ... would each miss the
# cache and reach node — the classic cache-busting bypass. The file is
# identical whatever the query, so key on the bare path.
proxy_cache_key $scheme$proxy_host$uri;
proxy_cache_valid 200 24h;
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
proxy_cache_lock on;
add_header X-Cache-Status $upstream_cache_status;
# Standard proxy headers
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 $scheme;
}
# /api/health endpoint - No caching, always hit the backend
location = /api/health {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
# Cache configuration - No caching for health checks
proxy_cache off;
add_header X-Cache-Status "BYPASS";
add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate";
add_header Pragma "no-cache";
add_header Expires "0";
# Standard proxy headers
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 $scheme;
}
# /commit.txt endpoint - Cache for 5 seconds
location = /commit.txt {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
# Cache configuration
proxy_cache API_CACHE;
proxy_cache_valid 200 5s; # Cache successful responses for 5 seconds
proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504;
proxy_cache_lock on;
add_header X-Cache-Status $upstream_cache_status;
# Standard proxy headers
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 $scheme;
}
# Short, hand-typeable alias for the Steam account-linking route.
#
# This is the one URL in the product a player types by hand, and they
# type it in a degraded situation: the desktop app could not open a
# browser, so the browser being used may be on another device entirely
# (a phone is realistic). "#" sits behind a symbol layer on a phone
# keyboard, so the canonical /#steam-link is a poor thing to dictate.
#
# 302 rather than 301: a permanent redirect is cached hard by browsers
# and would outlive any decision to retarget /link.
location = /link {
return 302 /#steam-link;
}
# Same target, trailing slash. `location =` is an exact match, so /link
# alone would 404 on /link/ -- and browsers and address-bar autocomplete
# both append slashes. For a URL whose whole purpose is surviving being
# hand-typed on an unfamiliar device, that is not a variant to lose.
location = /link/ {
return 302 /#steam-link;
}
# Binary files caching
location ~* \.(bin|dat|exe|dll|so|dylib)$ {
proxy_pass http://127.0.0.1:3000;
add_header Cache-Control "public, max-age=31536000, immutable"; # 1 year for binary files
proxy_cache STATIC;
proxy_cache_valid 200 302 24h;
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
proxy_cache_lock on;
add_header X-Cache-Status $upstream_cache_status;
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 $scheme;
}
# Specific file type caching rules (outside the /static/ location)
location ~* \.js$ {
proxy_pass http://127.0.0.1:3000;
add_header Content-Type application/javascript;
add_header Cache-Control "public, max-age=31536000, immutable"; # 1 year for JS files
proxy_cache STATIC;
proxy_cache_valid 200 302 24h;
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
proxy_cache_lock on;
add_header X-Cache-Status $upstream_cache_status;
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 $scheme;
}
location ~* \.css$ {
proxy_pass http://127.0.0.1:3000;
add_header Content-Type text/css;
add_header Cache-Control "public, max-age=31536000, immutable"; # 1 year for CSS files
proxy_cache STATIC;
proxy_cache_valid 200 302 24h;
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
proxy_cache_lock on;
add_header X-Cache-Status $upstream_cache_status;
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 $scheme;
}
# Updated HTML file caching - 1 second cache
location ~* \.html$ {
proxy_pass http://127.0.0.1:3000;
add_header Content-Type text/html;
add_header Cache-Control "public, max-age=1"; # 1 second for HTML files
proxy_cache STATIC;
proxy_cache_valid 200 302 1s; # Cache successful responses for 1 second
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
proxy_cache_lock on;
add_header X-Cache-Status $upstream_cache_status;
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 $scheme;
}
# Root location with short shared cache for the app shell
location = / {
proxy_pass http://127.0.0.1:3000;
# Cache the shared app shell briefly at the proxy; browser/CDN policy
# comes from the upstream Cache-Control header.
proxy_cache STATIC;
proxy_cache_valid 200 302 300s;
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
proxy_cache_lock on;
# Show cache status in response headers
add_header X-Cache-Status $upstream_cache_status;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
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 $scheme;
}
# Default location for all other requests
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
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 $scheme;
}
}