From 1bd31bd8d73db4e3ebef69e4001fe01f410f770b Mon Sep 17 00:00:00 2001 From: weidenwiesel Date: Sun, 21 Dec 2025 13:35:22 +0100 Subject: [PATCH] Update nginx config --- nginx/sites-enabled/invidious.vhost | 623 +++++++++++++++++----------- 1 file changed, 390 insertions(+), 233 deletions(-) diff --git a/nginx/sites-enabled/invidious.vhost b/nginx/sites-enabled/invidious.vhost index ddc9cdc..fda95ea 100644 --- a/nginx/sites-enabled/invidious.vhost +++ b/nginx/sites-enabled/invidious.vhost @@ -1,291 +1,448 @@ upstream invidious { - server 192.42.6.2:3000 fail_timeout=3s; - keepalive 21; + server 192.42.6.2:3000 fail_timeout=3s; + keepalive 30; } -# This is routed over a HAProxy that looks for the cookie +# HAProxy frontend companion upstream invidious_companion { - server 192.42.6.1:8118 fail_timeout=3s; + server 192.42.6.1:8118 fail_timeout=3s; } -map $upstream_addr $server_instance { - default "invidious"; +# HAProxy frontend proxy +upstream invidious_proxy { + server 192.42.6.1:8119 fail_timeout=3s; +} + +upstream invidious_worker { + server 192.42.6.2:3000; + keepalive 1; } geo $upstream_server { - default invidious; + default invidious; +} + +map $remote_addr $api_whitelist_ip { + default "Authentication required"; + + # locahost + 127.0.0.1/32 "off"; + + # Public IPs + 62.182.81.28/32 "off"; + 2a09:2dc0:0:100::/64 "off"; + + # Docker network + 192.42.0.0/16 "off"; +} + +map $http_user_agent $api_invidious_auth { + default $api_whitelist_ip; } map "$http_origin" $cors { - default ''; + default ''; } geo $feeds_whitelist { - default 0; - # CIDR in the list below are not limited + default 0; + # CIDR in the list below are not limited - # Google - 8.34.208.0/20 1; - 8.35.192.0/20 1; - 23.236.48.0/20 1; - 23.251.128.0/19 1; - 34.0.0.0/15 1; - 34.2.0.0/16 1; - 34.3.0.0/23 1; - 34.3.3.0/24 1; - 34.3.4.0/24 1; - 34.3.8.0/21 1; - 34.3.16.0/20 1; - 34.3.32.0/19 1; - 34.3.64.0/18 1; - 34.4.0.0/14 1; - 34.8.0.0/13 1; - 34.16.0.0/12 1; - 34.32.0.0/11 1; - 34.64.0.0/10 1; - 34.128.0.0/10 1; - 35.184.0.0/13 1; - 35.192.0.0/14 1; - 35.196.0.0/15 1; - 35.198.0.0/16 1; - 35.199.0.0/17 1; - 35.199.128.0/18 1; - 35.200.0.0/13 1; - 35.208.0.0/12 1; - 35.224.0.0/12 1; - 35.240.0.0/13 1; - 64.15.112.0/20 1; - 64.233.160.0/19 1; - 66.22.228.0/23 1; - 66.102.0.0/20 1; - 66.249.64.0/19 1; - 70.32.128.0/19 1; - 72.14.192.0/18 1; - 74.125.0.0/16 1; - 104.154.0.0/15 1; - 104.196.0.0/14 1; - 104.237.160.0/19 1; - 107.167.160.0/19 1; - 107.178.192.0/18 1; - 108.59.80.0/20 1; - 108.170.192.0/18 1; - 108.177.0.0/17 1; - 130.211.0.0/16 1; - 142.250.0.0/15 1; - 146.148.0.0/17 1; - 162.216.148.0/22 1; - 162.222.176.0/21 1; - 172.110.32.0/21 1; - 172.217.0.0/16 1; - 172.253.0.0/16 1; - 173.194.0.0/16 1; - 173.255.112.0/20 1; - 193.186.4.0/24 1; - 199.36.154.0/23 1; - 199.36.156.0/24 1; - 199.192.112.0/22 1; - 199.223.232.0/21 1; - 207.223.160.0/20 1; - 208.65.152.0/22 1; - 208.68.108.0/22 1; - 208.81.188.0/22 1; - 208.117.224.0/19 1; - 209.85.128.0/17 1; - 216.58.192.0/19 1; - 216.73.80.0/20 1; - 216.239.32.0/19 1; - 2001:4860::/32 1; - 2404:6800::/32 1; - 2404:f340::/32 1; - 2600:1900::/28 1; - 2606:73c0::/32 1; - 2607:f8b0::/32 1; - 2620:11a:a000::/40 1; - 2620:120:e000::/40 1; - 2800:3f0::/32 1; - 2a00:1450::/32 1; - 2c0f:fb50::/32 1; + # Google + 8.34.208.0/20 1; + 8.35.192.0/20 1; + 23.236.48.0/20 1; + 23.251.128.0/19 1; + 34.0.0.0/15 1; + 34.2.0.0/16 1; + 34.3.0.0/23 1; + 34.3.3.0/24 1; + 34.3.4.0/24 1; + 34.3.8.0/21 1; + 34.3.16.0/20 1; + 34.3.32.0/19 1; + 34.3.64.0/18 1; + 34.4.0.0/14 1; + 34.8.0.0/13 1; + 34.16.0.0/12 1; + 34.32.0.0/11 1; + 34.64.0.0/10 1; + 34.128.0.0/10 1; + 35.184.0.0/13 1; + 35.192.0.0/14 1; + 35.196.0.0/15 1; + 35.198.0.0/16 1; + 35.199.0.0/17 1; + 35.199.128.0/18 1; + 35.200.0.0/13 1; + 35.208.0.0/12 1; + 35.224.0.0/12 1; + 35.240.0.0/13 1; + 64.15.112.0/20 1; + 64.233.160.0/19 1; + 66.22.228.0/23 1; + 66.102.0.0/20 1; + 66.249.64.0/19 1; + 70.32.128.0/19 1; + 72.14.192.0/18 1; + 74.125.0.0/16 1; + 104.154.0.0/15 1; + 104.196.0.0/14 1; + 104.237.160.0/19 1; + 107.167.160.0/19 1; + 107.178.192.0/18 1; + 108.59.80.0/20 1; + 108.170.192.0/18 1; + 108.177.0.0/17 1; + 130.211.0.0/16 1; + 142.250.0.0/15 1; + 146.148.0.0/17 1; + 162.216.148.0/22 1; + 162.222.176.0/21 1; + 172.110.32.0/21 1; + 172.217.0.0/16 1; + 172.253.0.0/16 1; + 173.194.0.0/16 1; + 173.255.112.0/20 1; + 193.186.4.0/24 1; + 199.36.154.0/23 1; + 199.36.156.0/24 1; + 199.192.112.0/22 1; + 199.223.232.0/21 1; + 207.223.160.0/20 1; + 208.65.152.0/22 1; + 208.68.108.0/22 1; + 208.81.188.0/22 1; + 208.117.224.0/19 1; + 209.85.128.0/17 1; + 216.58.192.0/19 1; + 216.73.80.0/20 1; + 216.239.32.0/19 1; + 2001:4860::/32 1; + 2404:6800::/32 1; + 2404:f340::/32 1; + 2600:1900::/28 1; + 2606:73c0::/32 1; + 2607:f8b0::/32 1; + 2620:11a:a000::/40 1; + 2620:120:e000::/40 1; + 2800:3f0::/32 1; + 2a00:1450::/32 1; + 2c0f:fb50::/32 1; } map $feeds_whitelist $feeds_limit { - 1 ""; - 0 $binary_remote_addr; + 0 $binary_remote_addr; + 1 ""; } - -limit_req_zone $binary_remote_addr zone=invidious_login:5m rate=5r/m; limit_req_zone $binary_remote_addr zone=invidious_requests:5m rate=5r/s; +limit_req_zone $binary_remote_addr zone=invidious_login:5m rate=5r/m; +limit_req_zone $binary_remote_addr zone=invidious_api_requests:5m rate=30r/m; limit_req_zone $feeds_limit zone=invidious_feeds:5m rate=3r/s; server { - listen 80; - listen [::]:80; + listen 80; + listen [::]:80; - server_name invidious.nerdvpn.de www.invidious.nerdvpn.de; - root /srv/nginx/public/invidious; + server_name invidious.nerdvpn.de www.invidious.nerdvpn.de; + root /srv/nginx/public/invidious; - include snippets/malicious.conf; + include snippets/malicious.conf; + include /etc/nginx/bots.d/ddos.conf; + include /etc/nginx/bots.d/blockbots.conf; - location /.well-known/acme-challenge/ { - allow all; - default_type "text/plain"; - alias /srv/nginx/public/acme/; - } + location /.well-known/acme-challenge/ { + allow all; + default_type "text/plain"; + alias /srv/nginx/public/acme/; + } - location / { - return 301 https://invidious.nerdvpn.de$request_uri; - } + location / { + return 301 https://invidious.nerdvpn.de$request_uri; + } } server { - listen 443 ssl; - listen [::]:443 ssl; + listen 443 ssl; + listen [::]:443 ssl; - http2 on; + http2 on; - server_name www.invidious.nerdvpn.de; - root /srv/nginx/public/invidious; + server_name www.invidious.nerdvpn.de; + root /srv/nginx/public/invidious; - include snippets/malicious.conf; + include snippets/malicious.conf; + include /etc/nginx/bots.d/ddos.conf; + include /etc/nginx/bots.d/blockbots.conf; - ssl_certificate /srv/letsencrypt/certs/invidious.nerdvpn.de/fullchain.pem; - ssl_certificate_key /srv/letsencrypt/certs/invidious.nerdvpn.de/privkey.pem; - include snippets/htst.conf; + ssl_certificate /srv/letsencrypt/certs/invidious.nerdvpn.de/fullchain.pem; + ssl_certificate_key /srv/letsencrypt/certs/invidious.nerdvpn.de/privkey.pem; + include snippets/htst.conf; - access_log off; - error_log /dev/null emerg; + access_log off; + error_log /dev/null emerg; - location / { - return 301 https://invidious.nerdvpn.de$request_uri; - } + location / { + return 301 https://invidious.nerdvpn.de$request_uri; + } } server { - listen 443 ssl; - listen 443 default_server quic reuseport; - listen [::]:443 ssl; - listen [::]:443 default_server quic reuseport; + listen 443 ssl; + listen [::]:443 ssl; - http2 on; - http3 on; - quic_retry on; + http2 on; - server_name invidious.nerdvpn.de; - root /srv/nginx/public/invidious; + server_name invidious.nerdvpn.de; + root /srv/nginx/public/invidious; - add_header Alt-Svc 'h3=":443"; ma=86400'; - add_header X-server-instance $server_instance always; - add_header X-server-proto $server_protocol always; - add_header Onion-Location http://nerdvpneaggggfdiurknszkbmhvjndks5z5k3g5yp4nhphflh3n3boad.onion$request_uri; + add_header X-server-proto $server_protocol always; - ssl_session_cache shared:nginx_TLS_invidious:10m; + ssl_session_cache shared:nginx_TLS_invidious:10m; - add_header X-Robots-Tag "index, follow, noai, noimageai"; + add_header X-Robots-Tag "index, follow, noai, noimageai"; - ssl_certificate /srv/letsencrypt/certs/invidious.nerdvpn.de/fullchain.pem; - ssl_certificate_key /srv/letsencrypt/certs/invidious.nerdvpn.de/privkey.pem; - include snippets/htst.conf; + ssl_certificate /srv/letsencrypt/certs/invidious.nerdvpn.de/fullchain.pem; + ssl_certificate_key /srv/letsencrypt/certs/invidious.nerdvpn.de/privkey.pem; + include snippets/htst.conf; - access_log off; - error_log /dev/null emerg; - - include snippets/invidious_errorpages.conf; - include snippets/malicious.conf; + access_log off; + error_log /dev/null emerg; - limit_rate 4000k; + include snippets/invidious_errorpages.conf; + include snippets/malicious.conf; - include snippets/favicon.conf; - include snippets/robots.conf; - - error_page 503 @maintenance; - location @maintenance { - auth_request off; - root /srv/nginx/public/maintenance/; - rewrite ^ "/index.html" break; - } - location = /css/default.css { - auth_request off; - root /srv/nginx/public/invidious; - } - location ~ (^/feed/webhook) { - 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; + include /etc/nginx/bots.d/blockbots.conf; - auth_request off; - limit_req zone=invidious_feeds burst=240 delay=80; - #access_log /var/log/nginx/access/invidious.webfeed.log; - #error_log /var/log/nginx/errors/invidious.webfeed.log error; - proxy_http_version 1.1; - proxy_set_header Connection ""; - proxy_pass http://invidious; - } - location /.within.website/ { - 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; + # For public API usage and CORS, currently disabled + #proxy_hide_header Access-Control-Allow-Origin; + #add_header Access-Control-Allow-Origin $cors always; + #add_header Access-Control-Allow-Methods "GET, OPTIONS" always; + #add_header Access-Control-Allow-Headers 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization' always; - proxy_pass http://anubis; - proxy_pass_request_body off; - proxy_set_header content-length ""; - auth_request off; - } - location @redirectToAnubis { - return 307 /.within.website/?redir=$request_uri; - auth_request off; - } - location / { - 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; + # Limit all connections to 50 MBit/s + limit_rate 6144k; - limit_req zone=invidious_requests burst=240 delay=80; + include snippets/favicon.conf; + include snippets/robots.conf; - if ($invidious_access != 1) { - return 503; - } - if ($request_method = OPTIONS) { - return 204; - } + error_page 503 @maintenance; + location @maintenance { + auth_request off; + include /etc/nginx/bots.d/ddos.conf; + root /srv/nginx/public/maintenance/; + rewrite ^ "/index.html" break; + } - auth_request /.within.website/x/cmd/anubis/api/check; - error_page 401 = @redirectToAnubis; - - #error_page 503 = @maintenance; + # Custom style + location = /css/default.css { + auth_request off; + root /srv/nginx/public/invidious; + } - proxy_http_version 1.1; - proxy_set_header Connection ""; - proxy_pass http://$upstream_server; - } - - # Maintenance routes - #location ~ /(login) { - # auth_request off; - # limit_req zone=invidious_login burst=4 nodelay; - # proxy_http_version 1.1; - # proxy_set_header Connection ""; - # proxy_pass http://invidious_zero; - #} - #location ~ /(css|js|fonts|delete_account|data_control|subscription_manager|signout) { - # auth_request off; - # limit_req zone=invidious_requests burst=240 delay=80; - # proxy_http_version 1.1; - # proxy_set_header Connection ""; - # proxy_pass http://invidious_zero; - #} - - # Companion routes - location /companion { - 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; + # Disable anubis for api stats + location = /api/v1/stats { + 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_pass http://invidious_companion; - proxy_http_version 1.1; - proxy_set_header Connection ""; - } + auth_request off; + proxy_http_version 1.1; + proxy_set_header Connection ""; + proxy_pass http://invidious/api/v1/stats; + } + + # Anubis + location /.within.website/ { + 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-Anubis-Path $arg_redir; + + proxy_pass http://anubis; + proxy_pass_request_body off; + proxy_set_header content-length ""; + auth_request off; + } + location @redirectToAnubis { + return 307 /.within.website/?redir=$request_uri; + auth_request off; + } + location @botHoneypot { + 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_buffering off; + proxy_set_header X-Prefix $x_prefix; + + proxy_pass http://bot_honeypot; + proxy_pass_request_body off; + proxy_set_header content-length ""; + auth_request off; + } + + ########## + # Root ### + ########## + + location / { + auth_request /.within.website/x/cmd/anubis/api/check; + error_page 401 = @redirectToAnubis; + error_page 403 = @botHoneypot; + + 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; + + limit_req zone=invidious_requests burst=300 delay=100; + + if ($invidious_access != 1) { + return 503; + } + if ($request_method = OPTIONS) { + return 204; + } + + error_page 503 = @maintenance; + + proxy_http_version 1.1; + proxy_set_header Connection ""; + proxy_pass http://$upstream_server; + } + + # Login rate limit + location ^~ /login { + auth_request /.within.website/x/cmd/anubis/api/check; + error_page 401 = @redirectToAnubis; + error_page 403 = @botHoneypot; + + limit_req zone=invidious_login burst=4 nodelay; + + 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_http_version 1.1; + proxy_set_header Connection ""; + proxy_pass http://$upstream_server; + } + + # Switchbackend hotfix for browsers that remove referers + location ^~ /switchbackend { + 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_http_version 1.1; + proxy_set_header Connection ""; + proxy_pass http://$upstream_server; + } + + # Rewrite Trending feed + location ^~ /feed/trending { + alias /srv/nginx/public/invidious/trending.html; + add_header Content-Type text/html; + expires -1; + add_header Cache-Control "no-store, must-revalidate"; + } + + # Google Feedfetcher + location ^~ ^/feed/webhook { + 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; + + auth_request off; + limit_req zone=invidious_feeds burst=240 delay=80; + proxy_http_version 1.1; + proxy_set_header Connection ""; + proxy_pass http://invidious_worker; + } + + # API lockdown + location ~ (^/api/v1/videos|^/api/v1/channels|^/api/v1/search|^/api/v1/mixes|^/api/v1/trending|^/api/v1/popular) { + #return 204; + limit_req zone=invidious_api_requests burst=30 delay=1; + #limit_req zone=invidious_api_requests burst=120 delay=12; + + 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; + + auth_request off; + + auth_basic $api_invidious_auth; + auth_basic_user_file /etc/nginx/auth/invidious; + + # Redirect all API users to tarpit + #error_page 401 = @botHoneypot; + + if ($request_method = OPTIONS) { + add_header Access-Control-Allow-Origin $cors always; + add_header Access-Control-Allow-Methods "GET, OPTIONS" always; + add_header Access-Control-Allow-Headers 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization' always; + add_header Content-Type text/plain; + add_header Content-Length 0; + return 204; + } + + rewrite ^(?:api/v1/videos|api/v1/channels|api/v1/search|api/v1/mixes|/api/v1/trending|/api/v1/popular|/api/v1/playlists)/(.*)$ /$1 break; + + proxy_http_version 1.1; + proxy_set_header Connection ""; + proxy_pass http://$upstream_server; + } + + # Proxy route + location ~ (^/companion/videoplayback|^/videoplayback|^/companion/ggpht/|^/ggpht/) { + rewrite ^/companion/(.*)$ /$1 break; + + sendfile on; + sendfile_max_chunk 512k; + tcp_nopush on; + aio threads=default; + aio_write on; + directio 16m; + + #proxy_buffering on; + #proxy_buffers 1024 16k; + proxy_set_header CF-Connecting-IP ""; + proxy_hide_header "alt-svc"; + proxy_hide_header Cache-Control; + proxy_hide_header etag; + proxy_http_version 1.1; + proxy_set_header Connection keep-alive; + proxy_max_temp_file_size 32m; + + # These headers will be stripped by HAProxy so that they never reach the actual proxy, but HAProxy needs them for rate limits + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + auth_request off; + + proxy_pass http://invidious_proxy; + add_header Cache-Control private always; + } + + # Companion routes + location /companion { + 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_http_version 1.1; + proxy_set_header Connection ""; + proxy_pass http://invidious_companion; + } }