-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathserver.conf
376 lines (300 loc) · 10.4 KB
/
server.conf
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
369
370
371
372
373
374
375
376
# Set rate limit zone 'flood'
limit_req_zone $binary_remote_addr zone=flood:15m rate=5r/s;
# Sets a $real_scheme variable whose value is the scheme passed by the load
# balancer in X-Forwarded-Proto (if any), defaulting to $scheme.
# Similar to how the HttpRealIp module treats X-Forwarded-For.
map $http_x_forwarded_proto $real_scheme {
default $http_x_forwarded_proto;
'' $scheme;
}
upstream fpm {
server unix:/sock/fpm.sock;
}
# Configure fastcgi cache
fastcgi_cache mojiCache;
fastcgi_cache_valid 200 10m;
fastcgi_cache_methods GET HEAD;
fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
add_header X-Fastcgi-Cache $upstream_cache_status;
fastcgi_cache_path /var/run/nginx-cache levels=1:2 keys_zone=mojiCache:100m inactive=60m;
fastcgi_cache_use_stale updating error timeout invalid_header http_500;
fastcgi_cache_key "$request_method$host$request_uri:$cookie_dw_agency";
fastcgi_ignore_headers Cache-Control Expires Set-Cookie;
geo $ip_group {
default 0;
include /etc/nginx/geo.conf;
}
# Map IP groups to capabilities.
map $ip_group $ip_skip_oauth {
0 0; # Default IP group value
1 1; # Allowed IPs
2 1; # Allowed IPs (depricating)
3 0; # Cloud Platform IPs
4 1; # Local IP (127.0.0.1)
5 0; # Cloud Platform Egress IPs
default 0; # Default value
}
map $ip_group $ip_skip_cache {
3 1; # Cloud Platform IPs
4 1; # Local IP (127.0.0.1)
5 1; # Cloud Platform Egress IPs
default 0; # Default value
}
map $ip_group $ip_access_cron {
4 1; # Local IP (127.0.0.1)
default 0; # Default value
}
map $ip_group $ip_access_metrics {
3 1; # Cloud Platform IPs
4 1; # Local IP (127.0.0.1)
default 0; # Default value
}
map $ip_group $ip_access_health {
3 1; # Cloud Platform IPs
4 1; # Local IP (127.0.0.1)
default 0; # Default value
}
server {
listen 8080 default_server; # For default requests.
server_name localhost;
root /var/www/html/public;
index index.php;
# Prevents internal rewrites/redirects going to http and port 8080.
absolute_redirect off;
client_max_body_size 256m;
server_tokens off;
location = /favicon.ico {
log_not_found off;
access_log off;
}
###
# CUSTOM ERROR PAGES
###
error_page 400 /app/themes/clarity/error-pages/400.html;
error_page 401 /auth/401; # Use a dynamic 401 page, to conditionally rediect to login.
error_page 403 /app/themes/clarity/error-pages/403.html;
error_page 404 /app/themes/clarity/error-pages/404.html;
error_page 500 /app/themes/clarity/error-pages/500.html;
error_page 503 /app/themes/clarity/error-pages/maintenance.html;
# Empty location blocks to allow access when "/" location
# sends an HTTP 503 during maintenance mode
location /app/themes/clarity/error-pages/ {
# If the file exists, serve it directly, else return 404.
try_files $uri =404;
}
location /app/themes/clarity/dist/ {
# If the file exists, serve it directly, else return 404.
try_files $uri =404;
}
# Rewrite old upload URLs to the bedrock equivalent
location /wp-content/uploads/ {
rewrite ^/wp-content/uploads/(.*)$ /app/uploads/$1 permanent;
}
# We use the header X-Moj-Ip-Group internally, if the client sends this header return Bad Request.
if ($http_x_moj_ip_group != "") {
return 400;
}
##
# CACHING
##
# Cache the request, unless...
set $skip_cache 0;
# ...it's a POST request
if ($request_method = POST) {
set $skip_cache 1;
}
# ...there are query string parameters
if ($query_string != "") {
set $skip_cache 1;
}
# ...it's for a special WordPress URL which should not be cached (including wp-admin)
if ($request_uri ~* "(/wp-admin/|/xmlrpc.php|/wp-(app|cron|login|register|mail).php|wp-.*.php|/feed/|index.php|wp-comments-popup.php|wp-links-opml.php|wp-locations.php|sitemap(_index)?.xml|[a-z0-9_-]+-sitemap([0-9]+)?.xml)") {
set $skip_cache 1;
}
# ...it's to an auth path
if ($request_uri ~* "^/auth/") {
set $skip_cache 1;
}
# ...it's to the service's metrics endpoint
if ($request_uri ~* "^/metrics/service") {
set $skip_cache 1;
}
# ...it's to the liveness or readiness endpoint
if ($request_uri ~* "^/(liveness|readiness)$" ) {
set $skip_cache 1;
}
# ...it's from a logged in user, the cookie 'wordpress_no_cache' exists.
if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in") {
set $skip_cache 1;
}
# ...it's from a user with a specific IP group
# this is necessary for serving long TTL CLoudFront cookies to the intranet-archive service.
if ($ip_skip_cache = 1) {
set $skip_cache 1;
}
# Skip cache if the concatenated value doesn't contain 200 - the user is not allowed.
# Use concatenation and !~ regex because we cant use the OR operator in nginx
if ($auth_status !~ 200) {
set $skip_cache 1;
}
##
# LOCATIONS
# - Deny
# - Cache
# - Auth
# - Static files & WordPress
# - PHP scripts
# - Misc
##
##
# LOCATIONS - Deny
##
# Deny access to any files with a .php extension in the uploads directory
# Works in sub-directory installs and also in multisite network
# Keep logging the requests to parse later (or to pass to firewall utilities such as fail2ban)
location ~* /(?:uploads|files)/.*\.php$ {
deny all;
}
# deny access to dotfiles accept .well-known
# this will deny access to .git, .htaccess, .env, and other sensitive files
location ~ /\.(?!well-known).* {
deny all;
}
# Deny access to load-scripts.php and load-styles.php to prevent DoS attacks.
# These are endpoints used by php to concatenate scripts and styles.
# We're serving these with nginx instead.
location ~* ^/wp/wp-admin/load-(?:scripts|styles)\.php$ {
deny all;
}
##
# LOCATIONS - Cache
##
# Purge a cached page.
location ~ /purge-cache(/.*) {
fastcgi_cache_purge mojiCache "$request_method$host$1:*";
}
##
# LOCATIONS - Auth
##
# @see https://gock.net/blog/2020/nginx-subrequest-authentication-server
location = /auth/verify {
# Internal only, so /auth/verify can not be accessed from outside.
internal;
if ($ip_skip_oauth = 1) {
add_header X-Moj-Ip-Group $ip_group;
add_header Content-Type text/plain;
return 200;
}
# The subrequest handler, WordPress is not loaded in this file.
set $script_name /app/mu-plugins/moj-auth/verify.php;
fastcgi_param HTTP_X_MOJ_IP_GROUP $ip_group;
include /etc/nginx/php-fpm-auth.conf;
}
location ~ ^/auth/(401) {
# Internal only, so /auth/verify can not be accessed from outside.
internal;
# The 401 handler, WordPress is not loaded in this file.
set $script_name /app/mu-plugins/moj-auth/$1.php;
include /etc/nginx/php-fpm-auth.conf;
}
# Rewrite auth endpoints to fpm (WordPress's index.php)
location ~ ^/auth/(login|callback) {
auth_request off;
fastcgi_param HTTP_X_MOJ_IP_GROUP $ip_group;
rewrite /auth/* /index.php?$args;
}
##
# LOCATIONS - Static files & WordPress
##
location / {
# Use `auth_request` on this location.
include /etc/nginx/auth-request.conf;
# First attempt to serve request as file, then
# as a directory, then pass the request to
# WordPress's front controller.
try_files $uri $uri/ /index.php?$args;
}
# WordPress admin rate limit
location = /wp/wp-login.php {
# Use `auth_request` on this location.
include /etc/nginx/auth-request.conf;
limit_req zone=flood burst=5 nodelay;
include /etc/nginx/php-fpm.conf;
fastcgi_pass fpm;
}
# Specifically catch index.php, from the `location /` block.
location = /index.php {
# Use internal here as we don't want direct access.
internal;
# As `location /` uses `auth_request`, don't repeat it here.
# Send the IP status along, to use in in the application.
fastcgi_param HTTP_X_MOJ_IP_GROUP $ip_group;
include /etc/nginx/php-fpm.conf;
fastcgi_pass fpm;
}
# Allow cron from internal network only.
location = /wp/wp-cron.php {
if ($ip_access_cron = 0) {
add_header Content-Type text/plain;
return 401;
}
include /etc/nginx/php-fpm.conf;
fastcgi_pass fpm;
}
##
# LOCATIONS - php scripts
##
# For direct requests to php files.
location ~ \.php$ {
# Use `auth_request` on this location.
include /etc/nginx/auth-request.conf;
# Send the IP status along, to use in in the application.
fastcgi_param HTTP_X_MOJ_IP_GROUP $ip_group;
include /etc/nginx/php-fpm.conf;
fastcgi_pass fpm;
}
location = /metrics/fpm {
if ($ip_access_metrics = 0) {
return 404;
}
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_index index.php;
include fastcgi_params;
# Rewrite the request to /status?openmetrics
fastcgi_param SCRIPT_NAME "/status";
fastcgi_param QUERY_STRING "openmetrics";
fastcgi_pass fpm;
# Set content type, so we can view in a browser - without a file download.
add_header Content-Type text/plain;
}
location = /metrics/service {
if ($ip_access_metrics = 0) {
return 404;
}
set $script_name /metrics/service.php;
fastcgi_param SCRIPT_FILENAME $document_root$script_name;
fastcgi_param HTTP_X_MOJ_IP_GROUP $ip_group;
include fastcgi_params;
fastcgi_pass fpm;
}
##
# LOCATIONS - health
##
location = /liveness {
if ($ip_access_health = 0) {
return 404;
}
return 200;
}
location = /readiness {
if ($ip_access_health = 0) {
return 404;
}
# Make sure we can connect to php-fpm via the socket.
set $script_name /metrics/socket.php;
fastcgi_param SCRIPT_FILENAME $document_root$script_name;
include fastcgi_params;
fastcgi_pass fpm;
}
}