Skip to content

Commit ca52502

Browse files
committed
Add nginx config file and support for outlets
The nginx config file used to be copied from the discourse/discourse repository, but it has been now moved in this project, closer to the place where it is used. The config has several 'include' statements that implement support for outlets that templates can then use to extend the default configuration for various features. This is an alternative to the "find & replace" hacks.
1 parent b345430 commit ca52502

File tree

14 files changed

+373
-116
lines changed

14 files changed

+373
-116
lines changed
Lines changed: 289 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,289 @@
1+
# Additional MIME types that you'd like nginx to handle go in here
2+
types {
3+
text/csv csv;
4+
application/wasm wasm;
5+
}
6+
7+
upstream discourse {
8+
server 127.0.0.1:3000;
9+
}
10+
11+
# inactive means we keep stuff around for 1440m minutes regardless of last access (1 week)
12+
# levels means it is a 2 deep hierarchy cause we can have lots of files
13+
# max_size limits the size of the cache
14+
proxy_cache_path /var/nginx/cache inactive=1440m levels=1:2 keys_zone=one:10m max_size=600m;
15+
16+
# Increased from the default value to acommodate large cookies during oAuth2 flows
17+
# like in https://meta.discourse.org/t/x/74060 and large CSP and Link (preload) headers
18+
proxy_buffer_size 32k;
19+
proxy_buffers 4 32k;
20+
21+
# Increased from the default value to allow for a large volume of cookies in request headers
22+
# Discourse itself tries to minimise cookie size, but we cannot control other cookies set by other tools on the same domain.
23+
large_client_header_buffers 4 32k;
24+
25+
# attempt to preserve the proto, must be in http context
26+
map $http_x_forwarded_proto $thescheme {
27+
default $scheme;
28+
"~https$" https;
29+
}
30+
31+
log_format log_discourse '[$time_local] "$http_host" $remote_addr "$request" "$http_user_agent" "$sent_http_x_discourse_route" $status $bytes_sent "$http_referer" $upstream_response_time $request_time "$upstream_http_x_discourse_username" "$upstream_http_x_discourse_trackview" "$upstream_http_x_queue_time" "$upstream_http_x_redis_calls" "$upstream_http_x_redis_time" "$upstream_http_x_sql_calls" "$upstream_http_x_sql_time"';
32+
33+
# Allow bypass cache from localhost
34+
geo $bypass_cache {
35+
default 0;
36+
127.0.0.1 1;
37+
::1 1;
38+
}
39+
40+
include conf.d/outlets/before-server/*.conf;
41+
42+
server {
43+
access_log /var/log/nginx/access.log log_discourse;
44+
45+
include conf.d/outlets/server/*.conf;
46+
47+
gzip on;
48+
gzip_vary on;
49+
gzip_min_length 1000;
50+
gzip_comp_level 5;
51+
gzip_types application/json text/css text/javascript application/x-javascript application/javascript image/svg+xml application/wasm;
52+
gzip_proxied any;
53+
54+
server_name _;
55+
server_tokens off;
56+
57+
sendfile on;
58+
59+
keepalive_timeout 65;
60+
61+
# maximum file upload size (keep up to date when changing the corresponding site setting)
62+
client_max_body_size 10m;
63+
64+
# path to discourse's public directory
65+
set $public /var/www/discourse/public;
66+
67+
# without weak etags we get zero benefit from etags on dynamically compressed content
68+
# further more etags are based on the file in nginx not sha of data
69+
# use dates, it solves the problem fine even cross server
70+
etag off;
71+
72+
# prevent direct download of backups
73+
location ^~ /backups/ {
74+
internal;
75+
}
76+
77+
# bypass rails stack with a cheap 204 for favicon.ico requests
78+
location /favicon.ico {
79+
return 204;
80+
access_log off;
81+
log_not_found off;
82+
}
83+
84+
location / {
85+
root $public;
86+
add_header ETag "";
87+
88+
# auth_basic on;
89+
# auth_basic_user_file /etc/nginx/htpasswd;
90+
91+
location ~ ^/uploads/short-url/ {
92+
proxy_set_header Host $http_host;
93+
proxy_set_header X-Real-IP $remote_addr;
94+
proxy_set_header X-Request-Start "t=${msec}";
95+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
96+
proxy_set_header X-Forwarded-Proto $thescheme;
97+
proxy_set_header X-Sendfile-Type "";
98+
proxy_set_header X-Accel-Mapping "";
99+
proxy_pass http://discourse;
100+
break;
101+
}
102+
103+
location ~ ^/(secure-media-uploads/|secure-uploads)/ {
104+
proxy_set_header Host $http_host;
105+
proxy_set_header X-Real-IP $remote_addr;
106+
proxy_set_header X-Request-Start "t=${msec}";
107+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
108+
proxy_set_header X-Forwarded-Proto $thescheme;
109+
proxy_set_header X-Sendfile-Type "";
110+
proxy_set_header X-Accel-Mapping "";
111+
proxy_pass http://discourse;
112+
break;
113+
}
114+
115+
location ~* (fonts|assets|plugins|uploads)/.*\.(eot|ttf|woff|woff2|ico|otf)$ {
116+
expires 1y;
117+
add_header Cache-Control public,immutable;
118+
add_header Access-Control-Allow-Origin *;
119+
}
120+
121+
location = /srv/status {
122+
access_log off;
123+
log_not_found off;
124+
proxy_set_header Host $http_host;
125+
proxy_set_header X-Real-IP $remote_addr;
126+
proxy_set_header X-Request-Start "t=${msec}";
127+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
128+
proxy_set_header X-Forwarded-Proto $thescheme;
129+
proxy_set_header X-Sendfile-Type "";
130+
proxy_set_header X-Accel-Mapping "";
131+
proxy_pass http://discourse;
132+
break;
133+
}
134+
135+
# some minimal caching here so we don't keep asking
136+
# longer term we should increase probably to 1y
137+
location ~ ^/javascripts/ {
138+
expires 1d;
139+
add_header Cache-Control public,immutable;
140+
add_header Access-Control-Allow-Origin *;
141+
}
142+
143+
location ~ ^/assets/(?<asset_path>.+)$ {
144+
expires 1y;
145+
# asset pipeline enables this
146+
brotli_static on;
147+
gzip_static on;
148+
add_header Cache-Control public,immutable;
149+
# HOOK in asset location (used for extensibility)
150+
# TODO I don't think this break is needed, it just breaks out of rewrite
151+
break;
152+
}
153+
154+
location ~ ^/plugins/ {
155+
expires 1y;
156+
add_header Cache-Control public,immutable;
157+
add_header Access-Control-Allow-Origin *;
158+
}
159+
160+
# cache emojis
161+
location ~ /images/emoji/ {
162+
expires 1y;
163+
add_header Cache-Control public,immutable;
164+
add_header Access-Control-Allow-Origin *;
165+
}
166+
167+
location ~ ^/uploads/ {
168+
# NOTE: it is really annoying that we can't just define headers
169+
# at the top level and inherit.
170+
#
171+
# proxy_set_header DOES NOT inherit, by design, we must repeat it,
172+
# otherwise headers are not set correctly
173+
proxy_set_header Host $http_host;
174+
proxy_set_header X-Real-IP $remote_addr;
175+
proxy_set_header X-Request-Start "t=${msec}";
176+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
177+
proxy_set_header X-Forwarded-Proto $thescheme;
178+
proxy_set_header X-Sendfile-Type X-Accel-Redirect;
179+
proxy_set_header X-Accel-Mapping $public/=/downloads/;
180+
expires 1y;
181+
add_header Cache-Control public,immutable;
182+
183+
## optional upload anti-hotlinking rules
184+
#valid_referers none blocked mysite.com *.mysite.com;
185+
#if ($invalid_referer) { return 403; }
186+
187+
# custom CSS
188+
location ~ /stylesheet-cache/ {
189+
add_header Access-Control-Allow-Origin *;
190+
try_files $uri =404;
191+
}
192+
193+
# this allows us to bypass rails
194+
location ~* \.(gif|png|jpg|jpeg|bmp|tif|tiff|ico|webp|avif)$ {
195+
add_header Access-Control-Allow-Origin *;
196+
try_files $uri =404;
197+
}
198+
199+
# SVG needs an extra header attached
200+
location ~* \.(svg)$ {
201+
}
202+
203+
# thumbnails & optimized images
204+
location ~ /_?optimized/ {
205+
add_header Access-Control-Allow-Origin *;
206+
try_files $uri =404;
207+
}
208+
209+
proxy_pass http://discourse;
210+
break;
211+
}
212+
213+
location ~ ^/admin/backups/ {
214+
proxy_set_header Host $http_host;
215+
proxy_set_header X-Real-IP $remote_addr;
216+
proxy_set_header X-Request-Start "t=${msec}";
217+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
218+
proxy_set_header X-Forwarded-Proto $thescheme;
219+
proxy_set_header X-Sendfile-Type X-Accel-Redirect;
220+
proxy_set_header X-Accel-Mapping $public/=/downloads/;
221+
proxy_pass http://discourse;
222+
break;
223+
}
224+
225+
# This big block is needed so we can selectively enable
226+
# acceleration for backups, avatars, sprites and so on.
227+
# see note about repetition above
228+
location ~ ^/(svg-sprite/|letter_avatar/|letter_avatar_proxy/|user_avatar|highlight-js|stylesheets|theme-javascripts|favicon/proxied|service-worker|extra-locales/(mf|overrides)) {
229+
proxy_set_header Host $http_host;
230+
proxy_set_header X-Real-IP $remote_addr;
231+
proxy_set_header X-Request-Start "t=${msec}";
232+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
233+
proxy_set_header X-Forwarded-Proto $thescheme;
234+
proxy_set_header X-Sendfile-Type "";
235+
proxy_set_header X-Accel-Mapping "";
236+
237+
# if Set-Cookie is in the response nothing gets cached
238+
# this is double bad cause we are not passing last modified in
239+
proxy_ignore_headers "Set-Cookie";
240+
proxy_hide_header "Set-Cookie";
241+
proxy_hide_header "X-Discourse-Username";
242+
proxy_hide_header "X-Runtime";
243+
244+
# note x-accel-redirect can not be used with proxy_cache
245+
proxy_cache one;
246+
proxy_cache_key "$scheme,$host,$request_uri";
247+
proxy_cache_valid 200 301 302 7d;
248+
proxy_cache_bypass $bypass_cache;
249+
proxy_pass http://discourse;
250+
break;
251+
}
252+
253+
# we need buffering off for message bus
254+
location /message-bus/ {
255+
proxy_set_header X-Request-Start "t=${msec}";
256+
proxy_set_header Host $http_host;
257+
proxy_set_header X-Real-IP $remote_addr;
258+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
259+
proxy_set_header X-Forwarded-Proto $thescheme;
260+
proxy_set_header X-Sendfile-Type "";
261+
proxy_set_header X-Accel-Mapping "";
262+
proxy_http_version 1.1;
263+
proxy_buffering off;
264+
proxy_pass http://discourse;
265+
break;
266+
}
267+
268+
# this means every file in public is tried first
269+
try_files $uri @discourse;
270+
}
271+
272+
location /downloads/ {
273+
internal;
274+
alias $public/;
275+
}
276+
277+
location @discourse {
278+
include conf.d/outlets/discourse/*.conf;
279+
280+
proxy_set_header Host $http_host;
281+
proxy_set_header X-Request-Start "t=${msec}";
282+
proxy_set_header X-Real-IP $remote_addr;
283+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
284+
proxy_set_header X-Forwarded-Proto $thescheme;
285+
proxy_set_header X-Sendfile-Type "";
286+
proxy_set_header X-Accel-Mapping "";
287+
proxy_pass http://discourse;
288+
}
289+
}

image/base/etc/nginx/conf.d/outlets/before-server/.gitkeep

Whitespace-only changes.

image/base/etc/nginx/conf.d/outlets/discourse/.gitkeep

Whitespace-only changes.

image/base/etc/nginx/conf.d/outlets/server/.gitkeep

Whitespace-only changes.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
listen 80;

samples/standalone.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ templates:
1111
- "templates/postgres.template.yml"
1212
- "templates/redis.template.yml"
1313
- "templates/web.template.yml"
14-
## Uncomment the next line to enable the IPv6 listener
15-
#- "templates/web.ipv6.template.yml"
1614
- "templates/web.ratelimited.template.yml"
1715
## Uncomment these two lines if you wish to add Lets Encrypt (https)
1816
#- "templates/web.ssl.template.yml"

samples/web_only.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33

44
templates:
55
- "templates/web.template.yml"
6-
## Uncomment the next line to enable the IPv6 listener
7-
#- "templates/web.ipv6.template.yml"
86
- "templates/web.ratelimited.template.yml"
97
## Uncomment these two lines if you wish to add Lets Encrypt (https)
108
#- "templates/web.ssl.template.yml"

templates/offline-page.template.yml

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,9 @@ params:
77
offline_page_repository: https://github.com/discourse/discourse-offline-page.git
88

99
run:
10-
- replace:
11-
filename: "/etc/nginx/conf.d/discourse.conf"
12-
global: true
13-
from: /server.+{/
14-
to: |
10+
- file:
11+
path: "/etc/nginx/conf.d/outlets/server/offline-page.conf"
12+
contents: |
1513
server {
1614
error_page 502 /error_page.html;
1715
location /error_page.html {

templates/web.ipv6.template.yml

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,2 @@
1+
# This file is deprecated; you can remove it from your app.yml
12
run:
2-
- exec: echo "Enabling IPv6 listener"
3-
- replace:
4-
filename: "/etc/nginx/conf.d/discourse.conf"
5-
from: listen 80;
6-
to: |
7-
listen 80;
8-
listen [::]:80;

templates/web.letsencrypt.ssl.template.yml

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -106,28 +106,22 @@ hooks:
106106
107107
/usr/sbin/nginx -c /etc/nginx/letsencrypt.conf -s stop
108108
109-
- replace:
110-
filename: "/etc/nginx/conf.d/discourse.conf"
111-
from: /ssl_certificate.+/
112-
to: |
113-
ssl_certificate /shared/ssl/$$ENV_DISCOURSE_HOSTNAME.cer;
114-
ssl_certificate /shared/ssl/$$ENV_DISCOURSE_HOSTNAME_ecc.cer;
115-
116109
- replace:
117110
filename: /shared/letsencrypt/account.conf
118111
from: /#?ACCOUNT_EMAIL=.+/
119112
to: |
120113
ACCOUNT_EMAIL=$$ENV_LETSENCRYPT_ACCOUNT_EMAIL
121114
122115
- replace:
123-
filename: "/etc/nginx/conf.d/discourse.conf"
124-
from: /ssl_certificate_key.+/
116+
filename: "/etc/nginx/conf.d/outlets/server/https.conf"
117+
from: /ssl_certificate.+/
125118
to: |
126-
ssl_certificate_key /shared/ssl/$$ENV_DISCOURSE_HOSTNAME.key;
127-
ssl_certificate_key /shared/ssl/$$ENV_DISCOURSE_HOSTNAME_ecc.key;
119+
ssl_certificate /shared/ssl/$$ENV_DISCOURSE_HOSTNAME.cer;
120+
ssl_certificate /shared/ssl/$$ENV_DISCOURSE_HOSTNAME_ecc.cer;
128121
129122
- replace:
130-
filename: "/etc/nginx/conf.d/discourse.conf"
131-
from: /add_header.+/
123+
filename: "/etc/nginx/conf.d/outlets/server/https.conf"
124+
from: /ssl_certificate_key.+/
132125
to: |
133-
add_header Strict-Transport-Security 'max-age=63072000';
126+
ssl_certificate_key /shared/ssl/$$ENV_DISCOURSE_HOSTNAME.key;
127+
ssl_certificate_key /shared/ssl/$$ENV_DISCOURSE_HOSTNAME_ecc.key;

0 commit comments

Comments
 (0)