diff --git a/README.md b/README.md index c72ac47..04718d9 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,12 @@ This configuration will allow you to serve Plex via Nginx. ## Minimal Requirements Nginx - + +```bash +# for Debian based systems: +apt-get install -y nginx subversion ssl-cert socat +``` + Plex: * Remote Access - Disable * Network - Custom server access URLs = `https://:443,http://:80` diff --git a/nginx.conf b/nginx.conf index bd6cb6e..c6f126d 100644 --- a/nginx.conf +++ b/nginx.conf @@ -1,104 +1,207 @@ -#Must be set in the global scope see: https://forum.nginx.org/read.php?2,152294,152294 -#Why this is important especially with Plex as it makes a lot of requests http://vincent.bernat.im/en/blog/2011-ssl-session-reuse-rfc5077.html / https://www.peterbe.com/plog/ssl_session_cache-ab -ssl_session_cache shared:SSL:10m; -ssl_session_timeout 10m; +sendfile on; +tcp_nopush on; +tcp_nodelay on; +keepalive_timeout 65; +types_hash_max_size 2048; +server_names_hash_bucket_size 512; +server_names_hash_max_size 512; +proxy_headers_hash_bucket_size 512; +proxy_headers_hash_max_size 512; +include /etc/nginx/mime.types; +default_type application/octet-stream; + +# SSL Config from https://ssl-config.mozilla.org/#server=nginx&version=1.17.7&config=intermediate&openssl=1.1.1k&guideline=5.6 +ssl_session_cache shared:MozSSL:10m; +ssl_session_timeout 1d; #Upstream to Plex upstream plex_backend { - #Set this to the IP address that appears in `ifconfig` (NATTED LAN IP or Public IP address) if you want the bandwidth meter in the server status page to work + # Set the port and server to your plex server. server 127.0.0.1:32400; keepalive 32; } +map $http_upgrade $connection_upgrade { + default upgrade; + '' close; +} + +# For better Plex logging. +log_format plex '$remote_addr - $remote_user [$time_local]' + '"$request" $status $body_bytes_sent' + '"$http_referer" $host "$http_user_agent"' + '"$request_time" "$upstream_connect_time"' + '"$geoip_city" "$geoip_city_country_code"'; + server { listen 80; - #Enabling http2 can cause some issues with some devices, see #29 - Disable it if you experience issues - listen 443 ssl http2; #http2 can provide a substantial improvement for streaming: https://blog.cloudflare.com/introducing-http2/ + listen [::]:80; + listen 443 ssl http2; + listen [::]:443 ssl http2; + # Set this A / AAAA / CNAME record prior to starting. server_name plex.EXAMPLE.COM; - - send_timeout 100m; #Some players don't reopen a socket and playback stops totally instead of resuming after an extended pause (e.g. Chrome) - - #Faster resolving, improves stapling time. Timeout and nameservers may need to be adjusted for your location Google's have been used here. - resolver 8.8.4.4 8.8.8.8 valid=300s; - resolver_timeout 10s; - - #Use letsencrypt.org to get a free and trusted ssl certificate - ssl_certificate /path/to/fullchain.pem; - ssl_certificate_key /path/to/privkey.pem; - - ssl_protocols TLSv1 TLSv1.1 TLSv1.2; - ssl_prefer_server_ciphers on; - #Intentionally not hardened for security for player support and encryption video streams has a lot of overhead with something like AES-256-GCM-SHA384. - ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA'; - - #Why this is important: https://blog.cloudflare.com/ocsp-stapling-how-cloudflare-just-made-ssl-30/ + access_log /var/log/nginx/access.log plex; # You can disable this. + root /srv/; + + ## + # ACME SSL Cert Generation Method: + # + # curl https://get.acme.sh | sh + # mkdir -p /etc/nginx/ssl/${hostname} + # chmod 700 /etc/nginx/ssl + # /root/.acme.sh/acme.sh --set-default-ca --server letsencrypt # No personal data needed to setup + # Standalone Method + # /root/.acme.sh/acme.sh --force --issue --standalone -d ${hostname} + # DNS API Verification Method + # Reference: https://github.com/acmesh-official/acme.sh/wiki/dnsapi + # /root/.acme.sh/acme.sh --force --issue --dns dns_cf -d ${hostname} -d "*.${hostname}" + # Deploy to nginx + # /root/.acme.sh/acme.sh --force --install-cert -d ${hostname} --key-file /etc/nginx/ssl/${hostname}/key.pem --fullchain-file /etc/nginx/ssl/${hostname}/fullchain.pem --ca-file /etc/nginx/ssl/${hostname}/chain.pem --reloadcmd "systemctl reload nginx" + # Change the below. + ## + + ssl_certificate /etc/nginx/ssl/plex.EXAMPLE.COM/fullchain.pem; + ssl_key /etc/nginx/ssl/plex.EXAMPLE.COM/key.pem; + ssl_trusted_certificate /etc/nginx/ssl/plex.EXAMPLE.COM/fullchain.pem; + # Generate by doing openssl dhparam -out /etc/nginx/ssl/dhparam.pem 2048 + ssl_dhparam /etc/nginx/ssl/dhparam.pem; + + # https://ssl-config.mozilla.org/#server=nginx&version=1.17.7&config=intermediate&openssl=1.1.1k&guideline=5.6 + ssl_session_cache shared:MozSSL:10m; + ssl_session_timeout 1d; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; + ssl_prefer_server_ciphers off; ssl_stapling on; ssl_stapling_verify on; - #For letsencrypt.org you can get your chain like this: https://esham.io/2016/01/ocsp-stapling - ssl_trusted_certificate /path/to/chain.pem; - - #Reuse ssl sessions, avoids unnecessary handshakes - #Turning this on will increase performance, but at the cost of security. Read below before making a choice. - #https://github.com/mozilla/server-side-tls/issues/135 - #https://wiki.mozilla.org/Security/Server_Side_TLS#TLS_tickets_.28RFC_5077.29 - #ssl_session_tickets on; - ssl_session_tickets off; - - #Use: openssl dhparam -out dhparam.pem 2048 - 4096 is better but for overhead reasons 2048 is enough for Plex. - ssl_dhparam /path/to/dhparam.pem; - ssl_ecdh_curve secp384r1; - - #Will ensure https is always used by supported browsers which prevents any server-side http > https redirects, as the browser will internally correct any request to https. - #Recommended to submit to your domain to https://hstspreload.org as well. - #!WARNING! Only enable this if you intend to only serve Plex over https, until this rule expires in your browser it WONT BE POSSIBLE to access Plex via http, remove 'includeSubDomains;' if you only want it to effect your Plex (sub-)domain. - #This is disabled by default as it could cause issues with some playback devices it's advisable to test it with a small max-age and only enable if you don't encounter issues. (Haven't encountered any yet) - #add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always; - - #Plex has A LOT of javascript, xml and html. This helps a lot, but if it causes playback issues with devices turn it off. (Haven't encountered any yet) - gzip on; - gzip_vary on; - gzip_min_length 1000; - gzip_proxied any; - gzip_types text/plain text/css text/xml application/xml text/javascript application/x-javascript image/svg+xml; - gzip_disable "MSIE [1-6]\."; - - #Nginx default client_max_body_size is 1MB, which breaks Camera Upload feature from the phones. - #Increasing the limit fixes the issue. Anyhow, if 4K videos are expected to be uploaded, the size might need to be increased even more - client_max_body_size 100M; - - #Forward real ip and host to Plex - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - #When using ngx_http_realip_module change $proxy_add_x_forwarded_for to '$http_x_forwarded_for,$realip_remote_addr' - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header Sec-WebSocket-Extensions $http_sec_websocket_extensions; - proxy_set_header Sec-WebSocket-Key $http_sec_websocket_key; - proxy_set_header Sec-WebSocket-Version $http_sec_websocket_version; - - #Websockets - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "Upgrade"; - - #Disables compression between Plex and Nginx, required if using sub_filter below. - #May also improve loading time by a very marginal amount, as nginx will compress anyway. - #proxy_set_header Accept-Encoding ""; - - #Buffering off send to the client as soon as the data is received from Plex. - proxy_redirect off; - proxy_buffering off; + ssl_buffer_size 4k; + ssl_early_data on; + + # Security + add_header X-Frame-Options SAMEORIGIN; + add_header X-Content-Type-Options "nosniff" always; + add_header X-XSS-Protection "1; mode=block" always; + add_header X-Robots-Tag "none" always; + add_header Referrer-Policy same-origin always; + proxy_set_header Early-Data $ssl_early_data; + + # Set resolver to Cloudflare + resolver 1.1.1.1 1.0.0.1 [2606:4700:4700::1111] [2606:4700:4700::1001] valid=300s; + resolver_timeout 5s; + # Some players don't reopen a socket and playback stops totally instead of resuming after an extended pause (e.g. Chrome) + # You should really just be timing out using plex if the stream is inactive this long. + send_timeout 100m; + proxy_headers_hash_bucket_size 128; + proxy_headers_hash_max_size 1024; + proxy_buffers 32 4k; + # Increase body size + client_max_body_size 1G; + + # If using cloudflare this will resolve user ips correctly. + set_real_ip_from 103.21.244.0/22; + set_real_ip_from 103.22.200.0/22; + set_real_ip_from 103.31.4.0/22; + set_real_ip_from 104.16.0.0/13; + set_real_ip_from 104.24.0.0/14; + set_real_ip_from 108.162.192.0/18; + set_real_ip_from 131.0.72.0/22; + set_real_ip_from 141.101.64.0/18; + set_real_ip_from 162.158.0.0/15; + set_real_ip_from 172.64.0.0/13; + set_real_ip_from 173.245.48.0/20; + set_real_ip_from 188.114.96.0/20; + set_real_ip_from 190.93.240.0/20; + set_real_ip_from 197.234.240.0/22; + set_real_ip_from 198.41.128.0/17; + set_real_ip_from 2400:cb00::/32; + set_real_ip_from 2606:4700::/32; + set_real_ip_from 2803:f800::/32; + set_real_ip_from 2405:b500::/32; + set_real_ip_from 2405:8100::/32; + set_real_ip_from 2c0f:f248::/32; + set_real_ip_from 2a06:98c0::/29; + real_ip_header X-Forwarded-For; location / { - #Example of using sub_filter to alter what Plex displays, this disables Plex News. - #sub_filter ',news,' ','; - #sub_filter_once on; - #sub_filter_types text/xml; + # Example of using sub_filter to alter what Plex displays, this disables Plex News. + # sub_filter ',news,' ','; + # sub_filter_once on; + # sub_filter_types text/xml; + # Websockets + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "Upgrade"; + proxy_redirect off; + proxy_buffering off; + proxy_set_header Sec-WebSocket-Extensions $http_sec_websocket_extensions; + proxy_set_header Sec-WebSocket-Key $http_sec_websocket_key; + proxy_set_header Sec-WebSocket-Version $http_sec_websocket_version; + # Plex Headers + proxy_set_header X-Plex-Client-Identifier $http_x_plex_client_identifier; + proxy_set_header X-Plex-Container-Size $http_x_plex_container_size; + proxy_set_header X-Plex-Container-Start $http_x_plex_container_start; + proxy_set_header X-Plex-Device $http_x_plex_device; + proxy_set_header X-Plex-Device-Name $http_x_plex_device_name; + proxy_set_header X-Plex-Platform $http_x_plex_platform; + proxy_set_header X-Plex-Platform-Version $http_x_plex_platform_version; + proxy_set_header X-Plex-Product $http_x_plex_product; + proxy_set_header X-Plex-Token $http_x_plex_token; + proxy_set_header X-Plex-Version $http_x_plex_version; + proxy_set_header X-Plex-Nocache $http_x_plex_nocache; + proxy_set_header X-Plex-Provides $http_x_plex_provides; + proxy_set_header X-Plex-Device-Vendor $http_x_plex_device_vendor; + proxy_set_header X-Plex-Model $http_x_plex_model; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $http_x_forwarded_for; + proxy_set_header X-Forwarded-For $remote_addr; + proxy_set_header X-Forwarded-Proto $scheme; + # Allows All Encodings + proxy_set_header Accept-Encoding ""; + proxy_ssl_verify off; + proxy_http_version 1.1; + proxy_read_timeout 86400; proxy_pass http://plex_backend; } - - #PlexPy forward example, works the same for other services. - #location /plexpy { - # proxy_pass http://127.0.0.1:8181; - #} + + ## + # Forward Tautulli over same domain + ## + + # location /tautulli { + # proxy_pass http://127.0.0.1:24200/tautulli; + # # Advanced Proxy Config + # proxy_read_timeout 240; + # proxy_send_timeout 240; + # proxy_connect_timeout 240; + # proxy_headers_hash_bucket_size 128; + # proxy_headers_hash_max_size 1024; + # proxy_buffers 32 4k; + # # Basic Proxy Config + # proxy_set_header Host $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 https; + # #proxy_redirect http:// $scheme://; + # proxy_http_version 1.1; + # proxy_set_header Connection ""; + # proxy_cache_bypass $cookie_session; + # proxy_no_cache $cookie_session; + # } + + ## + # Host Librespeed on same domain + # If you want librespeed, install php-fpm libfcgi0ldbl php-cli php-dev php-xml php-curl php-xmlrpc php-json php-mbstring php-opcache php-geoip php-xml + # Check your php version and modify below accordingly. + ## + # location /librespeed { + # alias /srv/librespeed; + # client_max_body_size 50M; + # client_body_buffer_size 128k; + + # location ~ \.php$ { + # include snippets/fastcgi-php.conf; + # fastcgi_pass unix:/run/php/php7.4-fpm.sock; + # fastcgi_param SCRIPT_FILENAME $request_filename; + # include fastcgi_params; + # } + # } }