summary refs log tree commit diff
path: root/modules/tunnel/egress.nix
diff options
context:
space:
mode:
authorMel <mel@rnrd.eu>2026-04-24 03:10:11 +0200
committerMel <mel@rnrd.eu>2026-04-24 03:18:05 +0200
commitfa38ea010957a98e778c32b23a8f133b14afdef1 (patch)
tree2548538141908ceafa25c5f8ac7371d054b7bd87 /modules/tunnel/egress.nix
parent97e935e0ff718cbec86605bf584a5660812bdce9 (diff)
downloadnetwork-fa38ea010957a98e778c32b23a8f133b14afdef1.tar.zst
network-fa38ea010957a98e778c32b23a8f133b14afdef1.zip
Give the VPN its final name 'Tunnel'
Signed-off-by: Mel <mel@rnrd.eu>
Diffstat (limited to 'modules/tunnel/egress.nix')
-rw-r--r--modules/tunnel/egress.nix133
1 files changed, 133 insertions, 0 deletions
diff --git a/modules/tunnel/egress.nix b/modules/tunnel/egress.nix
new file mode 100644
index 0000000..7858751
--- /dev/null
+++ b/modules/tunnel/egress.nix
@@ -0,0 +1,133 @@
+{
+  me,
+  config,
+  pkgs,
+  lib,
+  ...
+}:
+
+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! :)
+  # this does mean that our egress servers are unable to support normal www
+  # services which we put on machines by default, which is okay.
+  port = 443;
+
+  # supposedly the current gold-standard protocol for circumventing dpi!
+  # both xray (egress-side) and sing-box (ingress-side) support various
+  # other protocols, if roskomnadzor learns to sniff out vless fully.
+  protocol = "vless";
+
+  inboundTag = "vless-in";
+  outboundTag = "direct-out";
+
+  definition = import ./definition.nix;
+  inherit (definition) paths mask;
+
+  path = findFirst (
+    p: p.egress == me.name
+  ) (throw "no egress information found for this server!") paths;
+
+  xrayConfig = {
+    inbounds = [
+      {
+        inherit port protocol;
+        tag = inboundTag;
+
+        settings = {
+          clients = [
+            {
+              id = path.info.uuid;
+              flow = "xtls-rprx-vision";
+            }
+          ];
+          decryption = "none";
+        };
+
+        streamSettings = {
+          network = "tcp";
+          security = "reality";
+          realitySettings = {
+            show = false;
+            dest = "www.${mask}:443";
+            serverNames = [
+              "www.${mask}"
+              mask
+            ];
+            privateKey = "@PRIVATE_KEY@";
+            shortIds = [ path.info.short ];
+          };
+        };
+      }
+    ];
+
+    # and we're out!
+    outbounds = [
+      {
+        protocol = "freedom";
+        tag = outboundTag;
+      }
+    ];
+
+    routing = {
+      rules = [
+        {
+          type = "field";
+          inboundTag = [ inboundTag ];
+          inherit outboundTag;
+        }
+      ];
+    };
+
+    log = {
+      loglevel = "debug";
+    };
+  };
+
+  config-file = pkgs.writeText "xray.json" (builtins.toJSON xrayConfig);
+in
+{
+  networking.firewall.allowedTCPPorts = [ port ];
+
+  age.secrets.egress-key = {
+    file = path.info.keySecret;
+  };
+
+  systemd.services = {
+    # we have to make an xray config on the fly because
+    # xray does not like reading secrets from specific files,
+    # it wants them in plain-text!
+    generate-xray-config = {
+      description = "Generate Xray configuration";
+      wantedBy = [ "multi-user.target" ];
+      before = [ "xray.service" ];
+      partOf = [ "xray.service" ];
+      serviceConfig = {
+        Type = "oneshot";
+        RemainAfterExit = true;
+      };
+      script = ''
+        mkdir -p /run/xray-configuration
+        cp ${config-file} /run/xray-configuration/xray.json
+
+        egress_key=$(cat ${config.age.secrets.egress-key.path})
+
+        # use sd for replacement as a fancy new tool for this
+        ${pkgs.sd}/bin/sd "@PRIVATE_KEY@" "$egress_key" /run/xray-configuration/xray.json
+      '';
+    };
+
+    xray = {
+      requires = [ "generate-xray-config.service" ];
+      after = [ "generate-xray-config.service" ];
+      restartTriggers = [ config-file ];
+    };
+  };
+
+  services.xray = {
+    enable = true;
+    settingsFile = "/run/xray-configuration/xray.json";
+  };
+}