Skip to content

Commit fd83a80

Browse files
committed
Update nginx template to support horizontal scaling
This commit is part of bigger work to add horizontal scaling support to PeerTube.
1 parent 5dfc71a commit fd83a80

1 file changed

Lines changed: 126 additions & 37 deletions

File tree

support/nginx/peertube

Lines changed: 126 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
# Minimum Nginx version required: 1.13.0 (released Apr 25, 2017)
22
# Please check your Nginx installation features the following modules via 'nginx -V':
3-
# STANDARD HTTP MODULES: Core, Proxy, Rewrite, Access, Gzip, Headers, HTTP/2, Log, Real IP, SSL, Thread Pool, Upstream, AIO Multithreading.
3+
# STANDARD HTTP MODULES: Core, Proxy, Rewrite, Access, Gzip, Headers, HTTP/2, Log, Real IP, SSL, Thread Pool, Upstream, AIO Multithreading, Map.
44
# THIRD PARTY MODULES: None.
55

66
server {
77
listen 80;
88
listen [::]:80;
99
server_name ${WEBSERVER_HOST};
1010

11-
location /.well-known/acme-challenge/ {
11+
location ^~ /.well-known/acme-challenge/ {
1212
default_type "text/plain";
1313
root /var/www/certbot;
1414
}
@@ -19,29 +19,87 @@ upstream backend {
1919
server ${PEERTUBE_HOST};
2020
}
2121

22+
##
23+
# ---------------------------------------------------------------------------
24+
# Horizontal scalability
25+
# ---------------------------------------------------------------------------
26+
#
27+
# Horizontal scalability allows to offload some API paths to `--role=secondary` processes.
28+
# See https://docs.joinpeertube.org/maintain/horizontal-scalability for more information.
29+
#
30+
# Leave this section untouched if you run a single PeerTube process.
31+
#
32+
# If you want to enable horizontal scalability, add one `server` line per secondary to both pools below
33+
# and keep `${PEERTUBE_HOST}` as a `backup` so reads survive every secondary going down.
34+
# For example:
35+
#
36+
# upstream secondary_pool {
37+
# server 127.0.0.1:9100;
38+
# server 127.0.0.1:9101;
39+
# server ${PEERTUBE_HOST} backup;
40+
# }
41+
#
42+
# `secondary_views_pool` handles view/watch-time tracking only. It's optional since the heartbeat can be spread to any process,
43+
# but it's faster to stick a heartbeat to a single process (because of local process caching).
44+
# If a CDN or another load balancer sits in front, set `set_real_ip_from` / `real_ip_header` accordingly,
45+
# otherwise every viewer hashes to the same secondary and PeerTube counts every view against the proxy IP.
46+
##
47+
48+
upstream secondary_pool {
49+
server ${PEERTUBE_HOST};
50+
}
51+
52+
upstream secondary_views_pool {
53+
hash $remote_addr consistent;
54+
55+
server ${PEERTUBE_HOST};
56+
}
57+
58+
# Secondary servers only support a subset of API endpoints
59+
# Leave this section untouched, even if you don't use horizontal scalability
60+
#
61+
# Regexes are evaluated top to bottom, first match wins
62+
# method + path -> pool
63+
map $request_method$uri $peertube_pool {
64+
default backend;
65+
66+
# Read-only video endpoints served by `--role=secondary` processes
67+
"~^(GET|HEAD)/api/v1/videos/?$" secondary_pool;
68+
"~^(GET|HEAD)/api/v1/videos/(categories|licences|languages|privacies)$" secondary_pool;
69+
# Collections that live under /api/v1/videos/ but are not a video id: must be listed before the /api/v1/videos/<id> line below
70+
"~^(GET|HEAD)/api/v1/videos/(blacklist|comments|imports|ownership|live)(/|$)" backend;
71+
"~^(GET|HEAD)/api/v1/videos/[^/]+/?$" secondary_pool;
72+
73+
# View/watch-time tracking: sticky to one process per viewer
74+
"~^(PUT|POST)/api/v1/videos/[^/]+/(views|watching)$" secondary_views_pool;
75+
}
76+
2277
server {
2378
listen 443 ssl http2;
2479
listen [::]:443 ssl http2;
80+
81+
# On nginx >= 1.25.1 `http2` as a `listen` parameter is deprecated and logs a warning on startup
82+
# If your nginx is recent enough, replace the two lines above by `listen 443 ssl;` + `listen [::]:443 ssl;`and add `http2 on;` here
2583
server_name ${WEBSERVER_HOST};
2684

85+
server_tokens off; # don't advertise the nginx version in responses and error pages
86+
2787
access_log /var/log/nginx/peertube.access.log; # reduce I/0 with buffer=10m flush=5m
2888
error_log /var/log/nginx/peertube.error.log;
2989

3090
##
3191
# Certificates
32-
# you need a certificate to run in production. see https://letsencrypt.org/
3392
##
3493
ssl_certificate /etc/letsencrypt/live/${WEBSERVER_HOST}/fullchain.pem;
3594
ssl_certificate_key /etc/letsencrypt/live/${WEBSERVER_HOST}/privkey.pem;
3695

37-
location ^~ '/.well-known/acme-challenge' {
96+
location ^~ /.well-known/acme-challenge/ {
3897
default_type "text/plain";
3998
root /var/www/certbot;
4099
}
41100

42101
##
43-
# Security hardening (as of Nov 15, 2020)
44-
# based on Mozilla Guideline v5.6
102+
# Security hardening (as of Nov 15, 2020) based on Mozilla Guideline v5.6
45103
##
46104

47105
ssl_protocols TLSv1.2 TLSv1.3;
@@ -55,20 +113,48 @@ server {
55113

56114
##
57115
# Application
116+
# ---------------------------------------------------------------------------
117+
#
118+
# IMPORTANT, read before editing a `location` below.
119+
#
120+
# `try_files /dev/null @named` performs an internal redirect that adds subtleties:
121+
# * `client_max_body_size` and the `add_header` that are read from the location matching the URI, i.e., the `location ~ ...` block.
122+
# * `proxy_*` directives and `add_header` on a proxied response are read from the final configuration, i.e. from the `@named` block
58123
##
59124

60125
location @api {
61126
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
62127
proxy_set_header Host $host; # Use $http_host if you use a non standard HTTP port
63128
proxy_set_header X-Real-IP $remote_addr;
64129

65-
client_max_body_size 100k; # default is 1M
130+
proxy_connect_timeout 10m;
131+
proxy_send_timeout 10m;
132+
proxy_read_timeout 10m;
133+
send_timeout 10m;
134+
135+
proxy_pass http://$peertube_pool;
136+
}
137+
138+
# Same as @api, but streams the request body go directly to PeerTube instead of being written to /var/lib/nginx first
139+
# Used by the upload endpoints, which are always served by the primary
140+
location @api_unbuffered {
141+
# Required for `proxy_request_buffering off`
142+
proxy_http_version 1.1;
143+
144+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
145+
proxy_set_header Host $host; # Use $http_host if you use a non standard HTTP port
146+
proxy_set_header X-Real-IP $remote_addr;
66147

67148
proxy_connect_timeout 10m;
68149
proxy_send_timeout 10m;
69150
proxy_read_timeout 10m;
70151
send_timeout 10m;
71152

153+
proxy_request_buffering off;
154+
# Only applies to chunked request bodies
155+
# A body with a Content-Length is checked against the `client_max_body_size` of the location that matched the URI, before we get here
156+
client_max_body_size 0;
157+
72158
proxy_pass http://backend;
73159
}
74160

@@ -77,17 +163,15 @@ server {
77163
}
78164

79165
location ~ ^/api/v1/videos/(upload-resumable|([^/]+/source/replace-resumable))$ {
80-
client_max_body_size 0;
81-
proxy_request_buffering off;
166+
client_max_body_size 0;
82167

83-
try_files /dev/null @api;
168+
try_files /dev/null @api_unbuffered;
84169
}
85170

86171
location ~ ^/api/v1/users/[^/]+/imports/import-resumable$ {
87-
client_max_body_size 0;
88-
proxy_request_buffering off;
172+
client_max_body_size 0;
89173

90-
try_files /dev/null @api;
174+
try_files /dev/null @api_unbuffered;
91175
}
92176

93177
location ~ ^/api/v1/videos/(upload|([^/]+/studio/edit))$ {
@@ -98,22 +182,28 @@ server {
98182
# This data gets stored in /var/lib/nginx by default, so you may want to put this directory
99183
# on a dedicated filesystem.
100184
client_max_body_size 12G; # default is 1M
101-
add_header X-File-Maximum-Size 8G always; # inform backend of the set value in bytes before mime-encoding (x * 1.4 >= client_max_body_size)
102-
proxy_request_buffering off;
185+
add_header X-File-Maximum-Size 8G always; # inform the client of the set value in bytes before mime-encoding (x * 1.4 >= client_max_body_size)
103186

104-
try_files /dev/null @api;
187+
try_files /dev/null @api_unbuffered;
105188
}
106189

107190
location ~ ^/api/v1/runners/jobs/[^/]+/(update|success)$ {
108-
client_max_body_size 0;
109-
proxy_request_buffering off;
191+
client_max_body_size 0;
192+
193+
try_files /dev/null @api_unbuffered;
194+
}
195+
196+
# View tracking (PUT|POST /views and /watching)
197+
location ~ ^/api/v1/videos/[^/]+/(views|watching)$ {
198+
client_max_body_size 100k; # default is 1M
110199

111200
try_files /dev/null @api;
112201
}
113202

114-
location ~ ^/api/v1/(videos|video-playlists|video-channels|users/me) {
203+
# Endpoints that accept an image (avatar, banner, thumbnail, preview, channel logo, instance logo)
204+
location ~ ^/api/v1/(videos|video-playlists|video-channels|users/me|config/instance-(avatar|banner|logo)) {
115205
client_max_body_size 12M; # default is 1M
116-
add_header X-File-Maximum-Size 8M always; # inform backend of the set value in bytes before mime-encoding (x * 1.4 >= client_max_body_size)
206+
add_header X-File-Maximum-Size 8M always; # inform the client of the set value in bytes before mime-encoding (x * 1.4 >= client_max_body_size)
117207

118208
try_files /dev/null @api;
119209
}
@@ -152,14 +242,13 @@ server {
152242

153243
##
154244
# Performance optimizations
155-
# For extra performance please refer to https://github.com/denji/nginx-tuning
156245
##
157246

158247
root /var/www/peertube/storage;
159248

160-
# Enable compression for JS/CSS/HTML, for improved client load times.
161-
# It might be nice to compress JSON/XML as returned by the API, but
162-
# leaving that out to protect against potential BREACH attack.
249+
# Compress the static client assets and the public XML feeds, for improved client load times.
250+
#
251+
# `application/json` is deliberately left out to prevent BREACH (CVE-2013-3587)
163252
gzip on;
164253
gzip_vary on;
165254
gzip_types # text/html is always compressed by HttpGzipModule
@@ -169,7 +258,11 @@ server {
169258
font/opentype
170259
application/vnd.ms-fontobject
171260
image/svg+xml
172-
application/xml;
261+
# PeerTube negotiates any of these for /feeds/* and /sitemap.xml
262+
text/xml
263+
application/xml
264+
application/rss+xml
265+
application/atom+xml;
173266
gzip_min_length 1000; # default is 20 bytes
174267
gzip_buffers 16 8k;
175268
gzip_comp_level 2; # default is 1
@@ -231,22 +324,18 @@ server {
231324
# Or this line with nginx < 1.17.0
232325
# set $limit_rate $peertube_limit_rate;
233326

327+
# These files are public and unauthenticated, so they can be read cross origin.
328+
add_header Access-Control-Allow-Origin '*' always;
329+
add_header Access-Control-Allow-Methods 'GET, OPTIONS' always;
330+
add_header Access-Control-Allow-Headers 'Range,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type' always;
331+
add_header Access-Control-Max-Age 1728000 always; # Preflight request can be cached 20 days
332+
333+
# Keep this `if` free of `add_header`: a taken `if` block replaces the whole add_header set of
334+
# the enclosing location, which would strip the CORS headers above from preflight responses.
234335
if ($request_method = 'OPTIONS') {
235-
add_header Access-Control-Allow-Origin '*';
236-
add_header Access-Control-Allow-Methods 'GET, OPTIONS';
237-
add_header Access-Control-Allow-Headers 'Range,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
238-
add_header Access-Control-Max-Age 1728000; # Preflight request can be cached 20 days
239-
add_header Content-Type 'text/plain; charset=UTF-8';
240-
add_header Content-Length 0;
241336
return 204;
242337
}
243338

244-
if ($request_method = 'GET') {
245-
add_header Access-Control-Allow-Origin '*';
246-
add_header Access-Control-Allow-Methods 'GET, OPTIONS';
247-
add_header Access-Control-Allow-Headers 'Range,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
248-
}
249-
250339
# Enabling the sendfile directive eliminates the step of copying the data into the buffer
251340
# and enables direct copying data from one file descriptor to another.
252341
sendfile on;

0 commit comments

Comments
 (0)