diff options
Diffstat (limited to 'modules/tunnel')
| -rw-r--r-- | modules/tunnel/egress.nix | 60 |
1 files changed, 39 insertions, 21 deletions
diff --git a/modules/tunnel/egress.nix b/modules/tunnel/egress.nix index 7211da8..c0a057b 100644 --- a/modules/tunnel/egress.nix +++ b/modules/tunnel/egress.nix @@ -7,12 +7,7 @@ }: let - inherit (lib) findFirst; - - # this is the https port, we use it to try to trick dpi into thinking - # we are just serving normal encrypted web traffic, nothing interesting! :) - # requests which fail vless authentication are forwarded to nginx via fallbacks. - port = 443; + inherit (lib) findFirst concatStringsSep; # supposedly the current gold-standard protocol for circumventing dpi! # both xray (egress-side) and sing-box (ingress-side) support various @@ -22,8 +17,12 @@ let inboundTag = "vless-in"; outboundTag = "direct-out"; - # xray falls back to nginx on this port for non-vless requests. + # nginx stream listens on port 443 and routes by sni: + # * mask domains (microsoft.com) go to xray for vless/reality. + # * everything else goes to good old nginx! + # both backends receive proxy protocol v1 with the real client ip. nginxPort = 8443; + xrayPort = 8444; definition = import ./definition.nix; inherit (definition) paths mask; @@ -32,10 +31,17 @@ let p: p.egress == me.name ) (throw "no egress information found for this server!") paths; + maskDomains = [ + "www.${mask}" + mask + ]; + xrayConfig = { inbounds = [ { - inherit port protocol; + port = xrayPort; + listen = "127.0.0.1"; + inherit protocol; tag = inboundTag; settings = { @@ -46,9 +52,6 @@ let } ]; decryption = "none"; - fallbacks = [ - { dest = "127.0.0.1:${toString nginxPort}"; xver = 1; } - ]; }; streamSettings = { @@ -57,14 +60,13 @@ let realitySettings = { show = false; dest = "www.${mask}:443"; - serverNames = [ - "www.${mask}" - mask - "${me.name}.rnrd.eu" - ]; + serverNames = maskDomains; privateKey = "@PRIVATE_KEY@"; shortIds = [ path.info.short ]; }; + sockopt = { + acceptProxyProtocol = true; + }; }; } ]; @@ -95,8 +97,6 @@ let config-file = pkgs.writeText "xray.json" (builtins.toJSON xrayConfig); in { - networking.firewall.allowedTCPPorts = [ port ]; - age.secrets.egress-key = { file = path.info.keySecret; }; @@ -137,7 +137,7 @@ in settingsFile = "/run/xray-configuration/xray.json"; }; - # don't unwrap cloudflare addresses + # don't unwrap cloudflare addresses, we get the real ip via proxy protocol. foundation.www.behindCloudflare = false; services.nginx = { @@ -145,8 +145,26 @@ in { addr = "127.0.0.1"; port = nginxPort; ssl = true; proxyProtocol = true; } ]; - # xray sends proxy protocol v1 to nginx, allowing us to - # extract the real client ip from the proxy protocol header. + # nginx stream sits on port 443 and routes traffic by sni to the two + # backends we have. + streamConfig = '' + map $ssl_preread_server_name $backend { + ${concatStringsSep "\n" (map (d: "${d} xray;") maskDomains)} + default web; + } + + upstream xray { server 127.0.0.1:${toString xrayPort}; } + upstream web { server 127.0.0.1:${toString nginxPort}; } + + server { + listen 443; + listen [::]:443; + ssl_preread on; + proxy_pass $backend; + proxy_protocol on; + } + ''; + commonHttpConfig = '' set_real_ip_from 127.0.0.1; real_ip_header proxy_protocol; |
