#---------------- # Documentation | #---------------- # Directive directory https://nginx.org/en/docs/dirindex.html # Reverse proxy https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/ # Server https://docs.nginx.com/nginx/admin-guide/web-server/web-server/ #------- # Main | #------- # Defines worker processes' user + group credentials user www-data; # Quantity = CPU cores worker_processes 2; # Location + logging level error_log /var/log/nginx/error_main.log debug; # Defines file containing main PID pid /run/nginx.pid; events { # Max simultaneous connections per worker process worker_connections 1024; } http { #------- # Logs | #------- log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; # Jellyfin: Censor sensitive logs log_format stripsecrets '$remote_addr $host - $remote_user [$time_local] ' '"$secretfilter" $status $body_bytes_sent ' '$request_length $request_time $upstream_response_time ' '"$http_referer" "$http_user_agent"'; # Jellyfin map $request $secretfilter { ~*^(?.*[\?&]api_key=)([^&]*)(?.*)$ "${prefix1}***$suffix1"; default $request; } error_log /var/log/nginx/error_http.log debug; # main applies pre-defined log_format access_log /var/log/nginx/access_http.log main; #------- # MIME | #------- include /etc/nginx/mime.types; default_type application/octet-stream; #----------------------------- # File transfer optimization | #----------------------------- sendfile on; # Provide client file w/out buffering. Improves static content transfer rate. Utilize w/ static content servers. tcp_nopush off; # Limits data transer amount per sendfile() call. Prevents individual call completely seizing worker processes. sendfile_max_chunk 2m; #------------------------------ # TCP connection optimization | #------------------------------ # Low traffic site. Low value minimizes idle connections. keepalive_timeout 30; # Max requests per keepalive connection keepalive_requests 100; #------------ # Nextcloud | #------------ upstream php-handler { server unix:/var/run/php/php8.3-fpm.sock; } # Set the `immutable` cache control options only for assets with a cache busting `v` argument map $arg_v $asset_immutable { "" ""; default ", immutable"; } #---------------- # Reverse proxy | Redifining request headers unnecessary. Proxied services located locally. #---------------- #include /etc/nginx/sites-enabled/reverse_proxy.conf; server { listen 443 ssl; http2 on; #---------- # SSL/TLS | https://docs.nginx.com/nginx/admin-guide/security-controls/terminating-ssl-http/ #---------- ssl_certificate /etc/ssl/certs/oller-net-selfsigned.crt; ssl_certificate_key /etc/ssl/private/oller-net-selfsigned.key; ssl_protocols TLSv1.3; # Reuse in Nextcloud config add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; #----------------------- # SSL/TLS optimization | https://docs.nginx.com/nginx/admin-guide/security-controls/terminating-ssl-http/#optimize #----------------------- # 1m = 4k sessions ssl_session_cache shared:SSL-TLS:1m; ssl_session_timeout 10m; location /charlie { allow 192.168.1.0/24; deny all; proxy_pass http://localhost:81; } #----------- # Jellyfin | #----------- # Censor sensitive logs access_log /var/log/nginx/access.log stripsecrets; ## The default `client_max_body_size` is 1M, this might not be enough for some posters, etc. client_max_body_size 20M; # Security / XSS Mitigation Headers add_header X-Content-Type-Options "nosniff"; # Permissions policy. May cause issues with some clients add_header Permissions-Policy "accelerometer=(), ambient-light-sensor=(), battery=(), bluetooth=(), camera=(), clipboard-read=(), display-capture=(), document-domain=(), encrypted-media=(), gamepad=(), geolocation=(), gyroscope=(), hid=(), idle-detection=(), interest-cohort=(), keyboard-map=(), local-fonts=(), magnetometer=(), microphone=(), payment=(), publickey-credentials-get=(), serial=(), sync-xhr=(), usb=(), xr-spatial-tracking=()" always; # Content Security Policy # See: https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP # Enforces https content and restricts JS/CSS to origin # External Javascript (such as cast_sender.js for Chromecast) must be whitelisted. add_header Content-Security-Policy "default-src https: data: blob: ; img-src 'self' https://* ; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' https://www.gstatic.com https://www.youtube.com blob:; worker-src 'self' blob:; connect-src 'self'; object-src 'none'; frame-ancestors 'self'; font-src 'self'"; location /jellyfin { allow 192.168.1.0/24; deny all; # Proxy main Jellyfin traffic proxy_pass http://localhost:8096; 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 $scheme; proxy_set_header X-Forwarded-Protocol $scheme; proxy_set_header X-Forwarded-Host $http_host; # Disable buffering when the nginx proxy gets very resource heavy upon streaming proxy_buffering off; } location /socket { allow 192.168.1.0/24; deny all; # Proxy Jellyfin Websockets traffic proxy_pass http://localhost:8096; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; 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 $scheme; proxy_set_header X-Forwarded-Protocol $scheme; proxy_set_header X-Forwarded-Host $http_host; } #------------ # Nextcloud | #------------ location /nextcloud { allow 192.168.1.0/24; deny all; proxy_pass http://localhost:82; 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 $scheme; add_header Front-End-Https on; } location /.well-known/carddav { allow 192.168.1.0/24; deny all; return 301 $scheme://$host/remote.php/dav; } location /.well-known/caldav { allow 192.168.1.0/24; deny all; return 301 $scheme://$host/remote.php/dav; } location ^~ /.well-known { allow 192.168.1.0/24; deny all; return 301 $scheme://$host/index.php$uri; } } #------------------- # Proxied services | #------------------- server { listen 127.0.0.1:81; http2 on; include /etc/nginx/sites-available/charlie.conf; } server { listen 127.0.0.1:82; http2 on; include /etc/nginx/sites-enabled/nextcloud.conf; } }