worker_processes auto; worker_rlimit_nofile 65535; events { worker_connections 8192; multi_accept on; } http { server_tokens off; resolver 8.8.8.8 ipv6=off valid=300s; resolver_timeout 10s; # 默认站点分流:本机/私网直连返回伪装页;其余 Host(正向代理目标)走 /__proxy 转发 # 公网 IP 无需手改:cron(sync-nginx-local-ips.sh)自动写入 local_ip_rules.conf; # 另有 /__proxy 自代理环保护兜底,即使公网 IP 变更也不会死循环。 map $host $is_local { default 0; "~^(10\.|127\.|169\.254\.|192\.168\.|172\.(1[6-9]|2[0-9]|3[01])\.)" 1; } # UoT v2(UDP over TCP):CONNECT 目标为 sing-box UoT v2 magic 地址 # (sp.v2.udp-over-tcp.arpa)时转发到本机 UoT relay(127.0.0.1:15201), # 其余 CONNECT 走默认解析($connect_addr)。 # 注意(实测结论,勿踩坑): # 1. 必须用 $request 匹配——此模块版本未注册 $connect_host 变量; # 2. proxy_connect_address 必须放在 default_server 块——nginx 按 Host 头 # 选虚拟主机,CONNECT 的 Host 是目标域名,永远落在 default_server; # 3. 客户端 CONNECT magic 地址时端口必须非 0(模块拒绝 port<1,返回 400)。 map $request $rrpp_uot_connect_address { default $connect_addr; "~^CONNECT sp\.v2\.udp-over-tcp\.arpa" 127.0.0.1:15201; } include mime.types; default_type application/octet-stream; sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; keepalive_requests 100; # :主域名 HTTPS 站点 + 认证 CONNECT 代理 server { listen ssl; http2 on; server_name <节点域名>; root /var/www/html; ssl_certificate /etc/nginx/ssl/<节点域名>/fullchain.pem; ssl_certificate_key /etc/nginx/ssl/<节点域名>/privkey.pem; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; # 仅 CONNECT/正向代理需要认证,普通页面不需要 auth_basic "Restricted"; auth_basic_user_file /etc/nginx/.htpasswd; proxy_connect; proxy_connect_allow all; proxy_connect_address $rrpp_uot_connect_address; # 出站连接超时须小于客户端超时(lite 客户端 15s): # 目标黑洞时快速返回 502,避免客户端"read operation timed out"干等 proxy_connect_connect_timeout 10s; # 注:此模块版本 proxy_connect_data_timeout 与 proxy_connect_read_timeout # 写同一字段(同时配置报 duplicate),长连接超时用 read/send timeout 设置 proxy_connect_read_timeout 10m; proxy_connect_send_timeout 10m; location / { auth_basic off; if ($host != "<节点域名>") { rewrite ^ /__proxy last; } index index.html; try_files $uri $uri/ =404; } location /__proxy { internal; proxy_intercept_errors on; error_page 502 503 504 =444 @drop; resolver 8.8.8.8 ipv6=off valid=300s; proxy_pass $scheme://$host$request_uri; proxy_set_header Host $host; proxy_ssl_name $host; proxy_ssl_server_name on; } location @drop { return 444; } } # fallback:其他 SNI 也可用 CONNECT 代理;普通 GET 只返回伪装页 server { listen ssl default_server; http2 on; server_name _; ssl_certificate /etc/nginx/ssl/<节点域名>/fullchain.pem; ssl_certificate_key /etc/nginx/ssl/<节点域名>/privkey.pem; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; # 仅 CONNECT/正向代理需要认证,普通页面不需要 auth_basic "Restricted"; auth_basic_user_file /etc/nginx/.htpasswd; proxy_connect; proxy_connect_allow all; proxy_connect_address $rrpp_uot_connect_address; # 出站连接超时须小于客户端超时(lite 客户端 15s): # 目标黑洞时快速返回 502,避免客户端"read operation timed out"干等 proxy_connect_connect_timeout 10s; # 注:此模块版本 proxy_connect_data_timeout 与 proxy_connect_read_timeout # 写同一字段(同时配置报 duplicate),长连接超时用 read/send timeout 设置 proxy_connect_read_timeout 10m; proxy_connect_send_timeout 10m; location / { auth_basic off; # 自动判定本机:连接本地地址 / 无 Host / 私网回环 / cron 维护的公网 IP 规则 # 命中则 rewrite 到 /__local<原路径>(保留 $uri),其余走 /__proxy 转发 if ($host = $server_addr) { rewrite ^(.*)$ /__local$1 last; } if ($host = "_") { rewrite ^(.*)$ /__local$1 last; } if ($is_local) { rewrite ^(.*)$ /__local$1 last; } include /etc/nginx/local_ip_rules.conf; rewrite ^ /__proxy last; } # 本机 IP/域名直连:剥掉前缀后按原路径服务伪装页(保持原有行为) location /__local { internal; auth_basic off; rewrite ^/__local(.*)$ $1 break; root /var/www/html; index index.html; try_files $uri $uri/ =404; } # 明文 HTTP 正向代理:绝对形式请求(Host=目标域名)在此转发 location /__proxy { internal; # 自代理环保护:转发请求带标记头,二次进入说明代理目标指向本机(未知/新公网 IP), # 返回 508 Loop Detected 而非死循环 if ($http_x_proxy_loop_guard = "1") { return 508; } proxy_set_header X-Proxy-Loop-Guard "1"; resolver 8.8.8.8 ipv6=off valid=300s; proxy_pass http://$http_host$request_uri; proxy_set_header Host $http_host; proxy_http_version 1.1; proxy_set_header Connection ""; proxy_connect_timeout 10s; proxy_read_timeout 120s; proxy_intercept_errors on; # 目标不可达/无法解析:直接断开连接(444),不返回任何页面 error_page 502 503 504 =444 @drop; } location @drop { return 444; } } include /etc/nginx/conf.d/*.conf; }