From c87ba277c45cc7e912b1ec2ad0b5490a7bae7476 Mon Sep 17 00:00:00 2001 From: oqyude Date: Thu, 17 Sep 2026 01:48:05 +0300 Subject: [PATCH] dop fix --- configurations/vds.nix | 7 +++-- modules/server/nginx.nix | 68 +++++++++++++++++++++++++++------------- modules/vds/nginx.nix | 4 +++ 3 files changed, 56 insertions(+), 23 deletions(-) diff --git a/configurations/vds.nix b/configurations/vds.nix index 6972ef3..3efbf39 100644 --- a/configurations/vds.nix +++ b/configurations/vds.nix @@ -79,8 +79,11 @@ ct state established,related accept # РЕЖЕМ SYN СРАЗУ - tcp flags syn tcp dport {80,443} limit rate 20/second burst 40 packets accept - tcp flags syn tcp dport {80,443} drop + # 2096 — 3x-ui subscription endpoint (subPort): /subs/, + # /subsjs/, /clash/ раздаёт сама панель, ссылки содержат + # этот порт, пока в x-ui.db не задан subURI без порта. + tcp flags syn tcp dport {80,443,2096} limit rate 20/second burst 40 packets accept + tcp flags syn tcp dport {80,443,2096} drop # остальное по необходимости } diff --git a/modules/server/nginx.nix b/modules/server/nginx.nix index 34d36cf..321e9dd 100644 --- a/modules/server/nginx.nix +++ b/modules/server/nginx.nix @@ -12,17 +12,19 @@ # so all existing services behave exactly as before. # # Routing: -# x.zeroq.su → 127.0.0.1:2049 (3x-ui controller panel; TLS is -# terminated inside the container by the mounted LE -# cert, exactly like pubray1.zeroq.su on the VDS) -# immich/git/... → 127.0.0.1:8443 (nginx's own http {} listener: -# TLS termination + proxyPass unchanged) +# x.zeroq.su → 127.0.0.1:8443 (nginx's own https listener: +# TLS terminated by nginx, then path-routed: +# "/" → panel web server 2049, "/subs/…" etc → +# panel subscription server 2096, so subscription +# links can be plain https://x.zeroq.su/subs/) +# immich/git/... → 127.0.0.1:8443 (nginx's own http {} listener) # default → 127.0.0.1:15380 (Xray REALITY; podman DNATs # host:15380 → container:443 so Xray sees its real # configured port 443) # # ssl_preread reads SNI from the ClientHello; every SNI matching a known -# vhost goes to the internal web listener, x.zeroq.su goes to the panel, +# vhost goes to the internal web listener, x.zeroq.su goes to the panel +# (via the web listener so nginx can split /subs/ off the panel paths), # and anything else (REALITY fronting domains, direct-IP) goes to Xray. let server = "192.168.1.20"; @@ -127,22 +129,19 @@ let ]; # Goes inside the auto-generated `stream {}` block (services.nginx.streamConfig). - # x.zeroq.su → 3x-ui panel; known vhosts → nginx's own https listener; - # everything else (any SNI a REALITY client uses, e.g. - # media.mediavitrina.ru, or direct-IP) → Xray. + # x.zeroq.su → nginx's own https listener (8443), where nginx path-routes + # /subs/... → panel subscription server 2096 and / → panel web 2049; + # known vhosts → web listener; everything else (any SNI a REALITY client + # uses, e.g. media.mediavitrina.ru, or direct-IP) → Xray. streamConfig = '' ssl_preread on; map $ssl_preread_server_name $sni_backend { default xray; - ${panelDomain} panel; + ${panelDomain} web; ${"\n" + lib.concatMapStringsSep "\n" (d: " ${d} web;") (extraWebDomains ++ (map (s: s.domain) sites))} } - upstream panel { - server 127.0.0.1:2049; - } - upstream web { server 127.0.0.1:8443; } @@ -216,14 +215,41 @@ in extraConfig = bigUploads; }; "x.zeroq.su" = { - # ACME only — no https listener here: 443 is owned by the stream - # block, which routes the x.zeroq.su SNI to the panel inside the - # container (127.0.0.1:2049). 3x-ui terminates TLS itself using - # the cert this vhost renews (mounted at /root/cert/), and serves - # /subs/, /subsjs/, /clash/ straight from the panel, like the VDS. - # Don't add forceSSL: it would generate an HTTPS server block that - # conflicts with the stream listener. + # Panel domain. TLS is terminated HERE by nginx (stream routes this + # SNI to the web listener), and paths are split: + # /subs/, /subsjs/, /clash/, /sub/ → panel subscription server + # (127.0.0.1:2096, TLS inside the container) so links like + # https://x.zeroq.su/subs/ work without :2096; + # everything else → panel web server + # (127.0.0.1:2049, TLS inside the container). + # The panel serves both on TLS with the mounted LE cert. enableACME = true; + forceSSL = true; + listen = webListen; + locations = { + "/subs/" = { + proxyPass = "https://127.0.0.1:2096"; + proxyWebsockets = true; + extraConfig = "proxy_ssl_verify off;"; + }; + "/subsjs/" = { + proxyPass = "https://127.0.0.1:2096"; + extraConfig = "proxy_ssl_verify off;"; + }; + "/clash/" = { + proxyPass = "https://127.0.0.1:2096"; + extraConfig = "proxy_ssl_verify off;"; + }; + "/sub/" = { + proxyPass = "https://127.0.0.1:2096"; + extraConfig = "proxy_ssl_verify off;"; + }; + "/" = { + proxyPass = "https://127.0.0.1:2049"; + proxyWebsockets = true; + extraConfig = "proxy_ssl_verify off;"; + }; + }; }; "zeroq.su" = { forceSSL = true; diff --git a/modules/vds/nginx.nix b/modules/vds/nginx.nix index 9f494eb..83fc6a3 100644 --- a/modules/vds/nginx.nix +++ b/modules/vds/nginx.nix @@ -71,5 +71,9 @@ in networking.firewall.allowedTCPPorts = [ 80 443 + # 3x-ui subscription endpoint (subPort): /subs/, /subsjs/, /clash/ + # раздаёт сама панель; порт должен быть открыт, пока ссылки подписки + # содержат :2096 (см. также nftables-ruleset в configurations/vds.nix). + 2096 ]; }