peertube 10.2 KB
Newer Older
1
# Minimum Nginx version required:  1.13.0 (released Apr 25, 2017)
2
# 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.
4
# THIRD PARTY MODULES:   None.
5

Chocobozzz's avatar
Chocobozzz committed
6
7
8
9
10
11
12
13
14
15
16
server {
  listen 80;
  listen [::]:80;
  server_name ${WEBSERVER_HOST};

  location /.well-known/acme-challenge/ {
    default_type "text/plain";
    root /var/www/certbot;
  }
  location / { return 301 https://$host$request_uri; }
}
Chocobozzz's avatar
Chocobozzz committed
17

18
19
20
21
upstream backend {
  server ${PEERTUBE_HOST};
}

Chocobozzz's avatar
Chocobozzz committed
22
server {
23
  listen 443 ssl http2;
24
  listen [::]:443 ssl http2;
25
  server_name ${WEBSERVER_HOST};
Chocobozzz's avatar
Chocobozzz committed
26

27
28
29
30
31
32
33
  access_log /var/log/nginx/peertube.access.log; # reduce I/0 with buffer=10m flush=5m
  error_log  /var/log/nginx/peertube.error.log;

  ##
  # Certificates
  # you need a certificate to run in production. see https://letsencrypt.org/
  ##
Chocobozzz's avatar
Chocobozzz committed
34
35
  ssl_certificate     /etc/letsencrypt/live/${WEBSERVER_HOST}/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/${WEBSERVER_HOST}/privkey.pem;
36
37
38
39
40
41
42
43
44
45

  location ^~ '/.well-known/acme-challenge' {
    default_type "text/plain";
    root /var/www/certbot;
  }

  ##
  # Security hardening (as of Nov 15, 2020)
  # based on Mozilla Guideline v5.6
  ##
Chocobozzz's avatar
Chocobozzz committed
46

47
  ssl_protocols             TLSv1.2 TLSv1.3;
48
  ssl_prefer_server_ciphers on;
49
50
51
52
53
54
  ssl_ciphers               ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256; # add ECDHE-RSA-AES256-SHA if you want compatibility with Android 4
  ssl_session_timeout       1d; # defaults to 5m
  ssl_session_cache         shared:SSL:10m; # estimated to 40k sessions
  ssl_session_tickets       off;
  ssl_stapling              on;
  ssl_stapling_verify       on;
55
56
  # HSTS (https://hstspreload.org), requires to be copied in 'location' sections that have add_header directives
  #add_header Strict-Transport-Security "max-age=63072000; includeSubDomains";
Chocobozzz's avatar
Chocobozzz committed
57

58
59
60
  ##
  # Application
  ##
Chocobozzz's avatar
Chocobozzz committed
61

62
  location @api {
63
64
65
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host            $host;
    proxy_set_header X-Real-IP       $remote_addr;
66

67
68
69
70
71
72
73
74
75
76
77
78
79
80
    client_max_body_size  100k; # default is 1M

    proxy_connect_timeout 10m;
    proxy_send_timeout    10m;
    proxy_read_timeout    10m;
    send_timeout          10m;

    proxy_pass http://backend;
  }

  location / {
    try_files /dev/null @api;
  }

81
  location = /api/v1/videos/upload-resumable {
Chocobozzz's avatar
Chocobozzz committed
82
83
    client_max_body_size    0;
    proxy_request_buffering off;
84
85
86
87

    try_files /dev/null @api;
  }

88
  location = /api/v1/videos/upload {
89
90
91
    limit_except POST HEAD { deny all; }

    # This is the maximum upload size, which roughly matches the maximum size of a video file.
92
93
94
    # Note that temporary space is needed equal to the total size of all concurrent uploads.
    # This data gets stored in /var/lib/nginx by default, so you may want to put this directory
    # on a dedicated filesystem.
Rigel Kent's avatar
Rigel Kent committed
95
96
    client_max_body_size                      12G; # default is 1M
    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)
Chocobozzz's avatar
Chocobozzz committed
97

98
    try_files /dev/null @api;
99
100
  }

Chocobozzz's avatar
Chocobozzz committed
101
  location ~ ^/api/v1/(videos|video-playlists|video-channels|users/me) {
102
103
    client_max_body_size                      6M; # default is 1M
    add_header            X-File-Maximum-Size 4M always; # inform backend of the set value in bytes before mime-encoding (x * 1.4 >= client_max_body_size)
Chocobozzz's avatar
Chocobozzz committed
104
105
106
107

    try_files /dev/null @api;
  }

108
109
110
111
  ##
  # Websocket
  ##

112
  location @api_websocket {
113
114
115
116
117
118
119
120
121
122
123
    proxy_http_version 1.1;
    proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header   Host            $host;
    proxy_set_header   X-Real-IP       $remote_addr;
    proxy_set_header   Upgrade         $http_upgrade;
    proxy_set_header   Connection      "upgrade";

    proxy_pass http://backend;
  }

  location /socket.io {
124
125
    try_files /dev/null @api_websocket;
  }
126

127
128
129
130
131
132
  location /tracker/socket {
    # Peers send a message to the tracker every 15 minutes
    # Don't close the websocket before then
    proxy_read_timeout 15m; # default is 60s

    try_files /dev/null @api_websocket;
133
  }
Chocobozzz's avatar
Chocobozzz committed
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
  ##
  # Performance optimizations
  # For extra performance please refer to https://github.com/denji/nginx-tuning
  ##

  root /var/www/peertube/storage;

  # Enable compression for JS/CSS/HTML, for improved client load times.
  # It might be nice to compress JSON/XML as returned by the API, but
  # leaving that out to protect against potential BREACH attack.
  gzip              on;
  gzip_vary         on;
  gzip_types        # text/html is always compressed by HttpGzipModule
                    text/css
                    application/javascript
                    font/truetype
                    font/opentype
                    application/vnd.ms-fontobject
                    image/svg+xml;
  gzip_min_length   1000; # default is 20 bytes
  gzip_buffers      16 8k;
  gzip_comp_level   2; # default is 1

  client_body_timeout       30s; # default is 60
  client_header_timeout     10s; # default is 60
  send_timeout              10s; # default is 60
  keepalive_timeout         10s; # default is 75
  resolver_timeout          10s; # default is 30
  reset_timedout_connection on;
164
  proxy_ignore_client_abort on;
165
166
167
168
169
170
171
172

  tcp_nopush                on; # send headers in one piece
  tcp_nodelay               on; # don't buffer data sent, good for small data bursts in real time

  # If you have a small /var/lib partition, it could be interesting to store temp nginx uploads in a different place
  # See https://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_temp_path
  #client_body_temp_path /var/www/peertube/storage/nginx/;

173
  # Bypass PeerTube for performance reasons. Optional.
174
175
  # Should be consistent with client-overrides assets list in /server/controllers/client.ts
  location ~ ^/client/(assets/images/(icons/icon-36x36\.png|icons/icon-48x48\.png|icons/icon-72x72\.png|icons/icon-96x96\.png|icons/icon-144x144\.png|icons/icon-192x192\.png|icons/icon-512x512\.png|logo\.svg|favicon\.png))$ {
176
    add_header Cache-Control "public, max-age=31536000, immutable"; # Cache 1 year
177

178
179
    root /var/www/peertube;

180
    try_files /storage/client-overrides/$1 /peertube-latest/client/dist/$1 @api;
181
182
  }

183
  # Bypass PeerTube for performance reasons. Optional.
Chocobozzz's avatar
Chocobozzz committed
184
  location ~ ^/client/(.*\.(js|css|png|svg|woff2|otf|ttf|woff|eot))$ {
185
    add_header Cache-Control "public, max-age=31536000, immutable"; # Cache 1 year
Chocobozzz's avatar
Chocobozzz committed
186

187
    alias /var/www/peertube/peertube-latest/client/dist/$1;
Chocobozzz's avatar
Chocobozzz committed
188
189
  }

190
  # Bypass PeerTube for performance reasons. Optional.
Chocobozzz's avatar
Chocobozzz committed
191
  location ~ ^/static/(thumbnails|avatars)/ {
192
    if ($request_method = 'OPTIONS') {
193
194
195
196
197
198
      add_header Access-Control-Allow-Origin  '*';
      add_header Access-Control-Allow-Methods 'GET, OPTIONS';
      add_header Access-Control-Allow-Headers 'Range,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
      add_header Access-Control-Max-Age       1728000; # Preflight request can be cached 20 days
      add_header Content-Type                 'text/plain charset=UTF-8';
      add_header Content-Length               0;
199
200
201
      return 204;
    }

202
203
204
205
    add_header Access-Control-Allow-Origin    '*';
    add_header Access-Control-Allow-Methods   'GET, OPTIONS';
    add_header Access-Control-Allow-Headers   'Range,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
    add_header Cache-Control                  "public, max-age=7200"; # Cache response 2 hours
Chocobozzz's avatar
Chocobozzz committed
206

207
    rewrite ^/static/(.*)$ /$1 break;
Chocobozzz's avatar
Chocobozzz committed
208

209
    try_files $uri @api;
Chocobozzz's avatar
Chocobozzz committed
210
211
  }

212
  # Bypass PeerTube for performance reasons. Optional.
213
  location ~ ^/static/(webseed|redundancy|streaming-playlists)/ {
214
215
    limit_rate_after            5M;

Chocobozzz's avatar
Chocobozzz committed
216
    # Clients usually have 4 simultaneous webseed connections, so the real limit is 3MB/s per client
217
    set $peertube_limit_rate    800k;
Chocobozzz's avatar
Chocobozzz committed
218
219
220

    # Increase rate limit in HLS mode, because we don't have multiple simultaneous connections
    if ($request_uri ~ -fragmented.mp4$) {
221
      set $peertube_limit_rate  5M;
Chocobozzz's avatar
Chocobozzz committed
222
223
    }

224
225
226
    # Use this line with nginx >= 1.17.0
    #limit_rate $peertube_limit_rate;
    # Or this line if your nginx < 1.17.0
Chocobozzz's avatar
Chocobozzz committed
227
    set $limit_rate $peertube_limit_rate;
228

Chocobozzz's avatar
Chocobozzz committed
229
    if ($request_method = 'OPTIONS') {
230
231
232
233
234
235
      add_header Access-Control-Allow-Origin  '*';
      add_header Access-Control-Allow-Methods 'GET, OPTIONS';
      add_header Access-Control-Allow-Headers 'Range,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
      add_header Access-Control-Max-Age       1728000; # Preflight request can be cached 20 days
      add_header Content-Type                 'text/plain charset=UTF-8';
      add_header Content-Length               0;
Chocobozzz's avatar
Chocobozzz committed
236
237
238
239
      return 204;
    }

    if ($request_method = 'GET') {
240
241
242
      add_header Access-Control-Allow-Origin  '*';
      add_header Access-Control-Allow-Methods 'GET, OPTIONS';
      add_header Access-Control-Allow-Headers 'Range,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
Chocobozzz's avatar
Chocobozzz committed
243
244
245

      # Don't spam access log file with byte range requests
      access_log off;
Chocobozzz's avatar
Chocobozzz committed
246
247
    }

248
249
250
251
252
    # Enabling the sendfile directive eliminates the step of copying the data into the buffer
    # and enables direct copying data from one file descriptor to another.
    sendfile on;
    sendfile_max_chunk 1M; # prevent one fast connection from entirely occupying the worker process. should be > 800k.
    aio threads;
Chocobozzz's avatar
Chocobozzz committed
253

Chocobozzz's avatar
Chocobozzz committed
254
    # Use this in tandem with fuse-mounting i.e. https://docs.joinpeertube.org/admin-remote-storage
255
256
257
258
    # to serve files directly from a public bucket without proxying.
    # Assumes you have buckets named after the storage subdirectories, i.e. 'videos', 'redundancy', etc.
    #set $cdn <your S3-compatiable bucket public url mounted via fuse>;
    #rewrite ^/static/webseed/(.*)$ $cdn/videos/$1 redirect;
259
    #rewrite ^/static/(.*)$         $cdn/$1        redirect;
Chocobozzz's avatar
Chocobozzz committed
260
    rewrite ^/static/webseed/(.*)$ /videos/$1 break;
261
    rewrite ^/static/(.*)$         /$1        break;
Chocobozzz's avatar
Chocobozzz committed
262

263
    try_files $uri @api;
Chocobozzz's avatar
Chocobozzz committed
264
265
  }
}