diff --git a/compose.yml b/compose.yml index 6c5d1fd..02f006e 100644 --- a/compose.yml +++ b/compose.yml @@ -22,7 +22,7 @@ services: - nginx-cache:/var/cache/nginx/peertube-media-cache:rw configs: - source: nginx_config - target: /etc/nginx/conf.d/default.conf + target: /etc/nginx/nginx.conf deploy: restart_policy: condition: on-failure diff --git a/nginx.conf.tmpl b/nginx.conf.tmpl index 968ee67..6aedd97 100644 --- a/nginx.conf.tmpl +++ b/nginx.conf.tmpl @@ -1,242 +1,250 @@ -upstream backend { - server app:9000; +user www-data; + +events { + worker_connections 768; } -proxy_cache_path /var/cache/nginx/peertube-media-cache levels=1:2 keys_zone=peertube_media_cache:5m max_size=40g inactive=72h use_temp_path=off; - -server { - listen 80; - server_name {{ env "DOMAIN" }}; - - ## - # Application - ## - - location @api { - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - - 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; +http { + upstream backend { + server app:9000; } - location / { - try_files /dev/null @api; - } + proxy_cache_path /var/cache/nginx/peertube-media-cache levels=1:2 keys_zone=peertube_media_cache:5m max_size=40g inactive=72h use_temp_path=off; - location = /api/v1/videos/upload { - limit_except POST HEAD { deny all; } + server { + listen 80; + server_name {{ env "DOMAIN" }}; - # This is the maximum upload size, which roughly matches the maximum size of a video file. - # 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. - 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) + ## + # Application + ## - try_files /dev/null @api; - } + location @api { + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; - location ~ ^/api/v1/(videos|video-playlists|video-channels|users/me) { - client_max_body_size 3M; # default is 1M - add_header X-File-Maximum-Size 2M always; # inform backend of the set value in bytes before mime-encoding (x * 1.4 >= client_max_body_size) + client_max_body_size 100k; # default is 1M - try_files /dev/null @api; - } + proxy_connect_timeout 10m; + proxy_send_timeout 10m; + proxy_read_timeout 10m; + send_timeout 10m; - ## - # Websocket - ## - - location @api_websocket { - 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 { - try_files /dev/null @api_websocket; - } - - 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; - } - - ## - # 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; - proxy_ignore_client_abort on; - - 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/lib/nginx/client-tmp; - - # Bypass PeerTube for performance reasons. Optional. - # 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))$ { - add_header Cache-Control "public, max-age=31536000, immutable"; # Cache 1 year - - root /var/www/peertube; - - try_files /storage/client-overrides/$1 /peertube-latest/client/dist/$1 @api; - } - - # Bypass PeerTube for performance reasons. Optional. - location ~ ^/client/(.*\.(js|css|png|svg|woff2|otf|ttf|woff|eot))$ { - add_header Cache-Control "public, max-age=31536000, immutable"; # Cache 1 year - - alias /var/www/peertube/peertube-latest/client/dist/$1; - } - - # Bypass PeerTube for performance reasons. Optional. - location ~ ^/static/(thumbnails|avatars)/ { - if ($request_method = 'OPTIONS') { - 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; - return 204; + proxy_pass http://backend; } - 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 - - rewrite ^/static/(.*)$ /$1 break; - - try_files $uri @api; - } - - # Bypass PeerTube for performance reasons. Optional. - location ~ ^/static/(webseed|redundancy|streaming-playlists)/ { - limit_rate_after 5M; - - # Clients usually have 4 simultaneous webseed connections, so the real limit is 3MB/s per client - set $peertube_limit_rate 800k; - - # Increase rate limit in HLS mode, because we don't have multiple simultaneous connections - if ($request_uri ~ -fragmented.mp4$) { - set $peertube_limit_rate 5M; + location / { + try_files /dev/null @api; } - # Use this line with nginx >= 1.17.0 - limit_rate $peertube_limit_rate; - # Or this line if your nginx < 1.17.0 - #set $limit_rate $peertube_limit_rate; + location = /api/v1/videos/upload { + limit_except POST HEAD { deny all; } - if ($request_method = 'OPTIONS') { - 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; - return 204; + # This is the maximum upload size, which roughly matches the maximum size of a video file. + # 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. + 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) + + try_files /dev/null @api; } - if ($request_method = 'GET') { - 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 X-Cache-Status $upstream_cache_status; - add_header X-Cache-Range $slice_range; - add_header X-Fuuu ok; + location ~ ^/api/v1/(videos|video-playlists|video-channels|users/me) { + client_max_body_size 3M; # default is 1M + add_header X-File-Maximum-Size 2M always; # inform backend of the set value in bytes before mime-encoding (x * 1.4 >= client_max_body_size) - add_header X-Accel-Expires 604800; - - # Don't spam access log file with byte range requests - access_log off; + try_files /dev/null @api; } - aio threads; + ## + # Websocket + ## - # 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. + location @api_websocket { + 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"; -{{ if (env "NGINX_WEBSEED_PROXY_ENABLE") }} - proxy_connect_timeout 70; - proxy_read_timeout 1200; - proxy_send_timeout 1200; + proxy_pass http://backend; + } - proxy_buffering on; - proxy_buffers 8 128k; - proxy_cache peertube_media_cache; + location /socket.io { + try_files /dev/null @api_websocket; + } - slice 64k; - proxy_cache_key $host$uri$is_args$args$slice_range; - proxy_set_header Range $slice_range; - proxy_cache_valid 200 206 1h; - proxy_cache_revalidate on; + 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 - proxy_http_version 1.1; - proxy_redirect off; + try_files /dev/null @api_websocket; + } - proxy_pass {{ env "NGINX_WEBSEED_PROXY_URI" }}; -{{ else }} - {{ if (env "NGINX_WEBSEED_CDN_ENABLE") }} - # Use this in tandem with fuse-mounting i.e. https://docs.joinpeertube.org/admin-remote-storage - # 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 {{ env "NGINX_WEBSEED_CDN_URI" }}; - rewrite ^/static/webseed/(.*)$ $cdn/videos/$1 redirect; - rewrite ^/static/(.*)$ $cdn/$1 redirect; + ## + # Performance optimizations + # For extra performance please refer to https://github.com/denji/nginx-tuning + ## - {{ else }} - rewrite ^/static/webseed/(.*)$ /videos/$1 break; - rewrite ^/static/(.*)$ /$1 break; - try_files $uri @api; - {{ end }} -{{ end }} + 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; + proxy_ignore_client_abort on; + + 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/lib/nginx/client-tmp; + + # Bypass PeerTube for performance reasons. Optional. + # 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))$ { + add_header Cache-Control "public, max-age=31536000, immutable"; # Cache 1 year + + root /var/www/peertube; + + try_files /storage/client-overrides/$1 /peertube-latest/client/dist/$1 @api; + } + + # Bypass PeerTube for performance reasons. Optional. + location ~ ^/client/(.*\.(js|css|png|svg|woff2|otf|ttf|woff|eot))$ { + add_header Cache-Control "public, max-age=31536000, immutable"; # Cache 1 year + + alias /var/www/peertube/peertube-latest/client/dist/$1; + } + + # Bypass PeerTube for performance reasons. Optional. + location ~ ^/static/(thumbnails|avatars)/ { + if ($request_method = 'OPTIONS') { + 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; + return 204; + } + + 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 + + rewrite ^/static/(.*)$ /$1 break; + + try_files $uri @api; + } + + # Bypass PeerTube for performance reasons. Optional. + location ~ ^/static/(webseed|redundancy|streaming-playlists)/ { + limit_rate_after 5M; + + # Clients usually have 4 simultaneous webseed connections, so the real limit is 3MB/s per client + set $peertube_limit_rate 800k; + + # Increase rate limit in HLS mode, because we don't have multiple simultaneous connections + if ($request_uri ~ -fragmented.mp4$) { + set $peertube_limit_rate 5M; + } + + # Use this line with nginx >= 1.17.0 + limit_rate $peertube_limit_rate; + # Or this line if your nginx < 1.17.0 + #set $limit_rate $peertube_limit_rate; + + if ($request_method = 'OPTIONS') { + 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; + return 204; + } + + if ($request_method = 'GET') { + 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 X-Cache-Status $upstream_cache_status; + add_header X-Cache-Range $slice_range; + add_header X-Fuuu ok; + + add_header X-Accel-Expires 604800; + + # Don't spam access log file with byte range requests + access_log off; + } + + aio threads; + + # 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. + + {{ if (env "NGINX_WEBSEED_PROXY_ENABLE") }} + proxy_connect_timeout 70; + proxy_read_timeout 1200; + proxy_send_timeout 1200; + + proxy_buffering on; + proxy_buffers 8 128k; + proxy_cache peertube_media_cache; + + slice 64k; + proxy_cache_key $host$uri$is_args$args$slice_range; + proxy_set_header Range $slice_range; + proxy_cache_valid 200 206 1h; + proxy_cache_revalidate on; + + proxy_http_version 1.1; + proxy_redirect off; + + proxy_pass {{ env "NGINX_WEBSEED_PROXY_URI" }}; + {{ else }} + {{ if (env "NGINX_WEBSEED_CDN_ENABLE") }} + # Use this in tandem with fuse-mounting i.e. https://docs.joinpeertube.org/admin-remote-storage + # 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 {{ env "NGINX_WEBSEED_CDN_URI" }}; + rewrite ^/static/webseed/(.*)$ $cdn/videos/$1 redirect; + rewrite ^/static/(.*)$ $cdn/$1 redirect; + + {{ else }} + rewrite ^/static/webseed/(.*)$ /videos/$1 break; + rewrite ^/static/(.*)$ /$1 break; + try_files $uri @api; + {{ end }} + {{ end }} + } } }