discourse-nginx.conf 8.28 KB
Newer Older
1
2
3
# Additional MIME types that you'd like nginx to handle go in here
types {
 text/csv csv;
4
 application/wasm wasm;
5
6
7
8
9
10
}

upstream discourse {
  server webapp:3000;
}

11
12
13
# inactive means we keep stuff around for 1440m minutes regardless of last access (1 week)
# levels means it is a 2 deep hierarchy cause we can have lots of files
# max_size limits the size of the cache
14
15
16
17
18
19
20
21
22
23
24
proxy_cache_path /var/cache/nginx keys_zone=one:10m max_size=200m;

# see: https://meta.discourse.org/t/x/74060
proxy_buffer_size 8k;

# attempt to preserve the proto, must be in http context
map $http_x_forwarded_proto $thescheme {
  default $scheme;
  https https;
}

25
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"';
26
27
28
29
30
31
32
33
34
35
36
37
38

server {
  listen 8080 default_server;  
  
  server_tokens off;
  
  access_log /dev/stdout;
  error_log /dev/stdout;
  
  gzip on;
  gzip_vary on;
  gzip_min_length 1000;
  gzip_comp_level 5;
39
  gzip_types application/json text/css text/javascript application/x-javascript application/javascript image/svg+xml application/wasm;
40
41
42
43
44
45
46
  gzip_proxied any;  
  
  sendfile on;

  keepalive_timeout 25;

  # maximum file upload size (keep up to date when changing the corresponding site setting)
47
  client_max_body_size 100m;
48
49
50
51
52
53
54
55
56
57
58

  # path to discourse's public directory
  set $public /discourse/public;

  # without weak etags we get zero benefit from etags on dynamically compressed content
  # further more etags are based on the file in nginx not sha of data
  # use dates, it solves the problem fine even cross server
  etag off;

  # prevent direct download of backups
  location ^~ /backups/ {
59
    internal;
60
61
62
63
  }

  # bypass rails stack with a cheap 204 for favicon.ico requests
  location /favicon.ico {
64
65
66
    return 204;
    access_log off;
    log_not_found off;
67
68
69
  }

  location / {
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
    root $public;
    add_header ETag "";

    # auth_basic on;
    # auth_basic_user_file /etc/nginx/htpasswd;

    location ~ ^/uploads/short-url/ {
      proxy_set_header Host $http_host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Request-Start "t=${msec}";
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto $thescheme;
      proxy_pass http://discourse;
      break;
    }

86
87
88
89
90
91
92
93
94
95
    location ~ ^/secure-media-uploads/ {
      proxy_set_header Host $http_host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Request-Start "t=${msec}";
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto $thescheme;
      proxy_pass http://discourse;
      break;
    }

96
    location ~* (fonts|assets|plugins|uploads)/.*\.(eot|ttf|woff|woff2|ico|otf)$ {
97
98
      expires 1y;
      add_header Cache-Control public,immutable;
99
      add_header Access-Control-Allow-Origin *;
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
    }

    location = /srv/status {
      access_log off;
      log_not_found off;
      proxy_set_header Host $http_host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Request-Start "t=${msec}";
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto $thescheme;
      proxy_pass http://discourse;
      break;
    }

    # some minimal caching here so we don't keep asking
115
    # longer term we should increase probably to 1y
116
117
118
    location ~ ^/javascripts/ {
      expires 1d;
      add_header Cache-Control public,immutable;
119
      add_header Access-Control-Allow-Origin *;
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
    }

    location ~ ^/assets/(?<asset_path>.+)$ {
      expires 1y;
      # asset pipeline enables this
      brotli_static on;
      gzip_static on;
      add_header Cache-Control public,immutable;
      # HOOK in asset location (used for extensibility)
      # TODO I don't think this break is needed, it just breaks out of rewrite
      break;
    }

    location ~ ^/plugins/ {
      expires 1y;
      add_header Cache-Control public,immutable;
136
      add_header Access-Control-Allow-Origin *;
137
138
139
140
141
142
    }

    # cache emojis
    location ~ /images/emoji/ {
      expires 1y;
      add_header Cache-Control public,immutable;
143
      add_header Access-Control-Allow-Origin *;
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
    }

    location ~ ^/uploads/ {

      # NOTE: it is really annoying that we can't just define headers
      # at the top level and inherit.
      #
      # proxy_set_header DOES NOT inherit, by design, we must repeat it,
      # otherwise headers are not set correctly
      proxy_set_header Host $http_host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Request-Start "t=${msec}";
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto $thescheme;
      proxy_set_header X-Sendfile-Type X-Accel-Redirect;
      proxy_set_header X-Accel-Mapping $public/=/downloads/;
      expires 1y;
      add_header Cache-Control public,immutable;

      ## optional upload anti-hotlinking rules
      #valid_referers none blocked mysite.com *.mysite.com;
      #if ($invalid_referer) { return 403; }

      # custom CSS
      location ~ /stylesheet-cache/ {
169
        add_header Access-Control-Allow-Origin *;
170
171
172
        try_files $uri =404;
      }
      # this allows us to bypass rails
173
      location ~* \.(gif|png|jpg|jpeg|bmp|tif|tiff|ico|webp)$ {
174
        add_header Access-Control-Allow-Origin *;
175
176
        try_files $uri =404;
      }
177
178
179
      # SVG needs an extra header attached
      location ~* \.(svg)$ {
      }
180
181
      # thumbnails & optimized images
      location ~ /_?optimized/ {
182
        add_header Access-Control-Allow-Origin *;
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
        try_files $uri =404;
      }

      proxy_pass http://discourse;
      break;
    }

    location ~ ^/admin/backups/ {
      proxy_set_header Host $http_host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Request-Start "t=${msec}";
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto $thescheme;
      proxy_set_header X-Sendfile-Type X-Accel-Redirect;
      proxy_set_header X-Accel-Mapping $public/=/downloads/;
      proxy_pass http://discourse;
      break;
    }

    # This big block is needed so we can selectively enable
    # acceleration for backups and avatars
    # see note about repetition above
    location ~ ^/(svg-sprite/|letter_avatar/|letter_avatar_proxy/|user_avatar|highlight-js|stylesheets|theme-javascripts|favicon/proxied|service-worker) {
      proxy_set_header Host $http_host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Request-Start "t=${msec}";
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto $thescheme;

      # if Set-Cookie is in the response nothing gets cached
      # this is double bad cause we are not passing last modified in
      proxy_ignore_headers "Set-Cookie";
      proxy_hide_header "Set-Cookie";
      proxy_hide_header "X-Discourse-Username";
      proxy_hide_header "X-Runtime";

      # note x-accel-redirect can not be used with proxy_cache
      proxy_cache one;
      proxy_cache_key "$scheme,$host,$request_uri";
      proxy_cache_valid 200 301 302 7d;
      proxy_cache_valid any 1m;
      proxy_pass http://discourse;
      break;
    }

    # we need buffering off for message bus
    location /message-bus/ {
      proxy_set_header X-Request-Start "t=${msec}";
      proxy_set_header Host $http_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 $thescheme;
      proxy_http_version 1.1;
      proxy_buffering off;
      proxy_pass http://discourse;
      break;
    }

    # this means every file in public is tried first
    try_files $uri @discourse;
243
244
245
  }

  location /downloads/ {
246
247
    internal;
    alias $public/;
248
249
250
  }

  location @discourse {
251
252
253
254
255
256
    proxy_set_header Host $http_host;
    proxy_set_header X-Request-Start "t=${msec}";
    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 $thescheme;
    proxy_pass http://discourse;
257
258
259
  }

}