about summary refs log tree commit diff
path: root/modules/shadowsocks.nix
diff options
context:
space:
mode:
authorAzat Bahawi <azat@bahawi.net>2024-04-21 02:15:42 +0300
committerAzat Bahawi <azat@bahawi.net>2024-04-21 02:15:42 +0300
commite6ed60548397627bf10f561f9438201dbba0a36e (patch)
treef9a84c5957d2cc4fcd148065ee9365a0c851ae1c /modules/shadowsocks.nix
parent2024-04-18 (diff)
2024-04-21
Diffstat (limited to 'modules/shadowsocks.nix')
-rw-r--r--modules/shadowsocks.nix133
1 files changed, 133 insertions, 0 deletions
diff --git a/modules/shadowsocks.nix b/modules/shadowsocks.nix
new file mode 100644
index 0000000..670faec
--- /dev/null
+++ b/modules/shadowsocks.nix
@@ -0,0 +1,133 @@
+{
+  config,
+  inputs,
+  lib,
+  pkgs,
+  ...
+}:
+with lib;
+let
+  cfg = config.nixfiles.modules.shadowsocks;
+in
+{
+  options.nixfiles.modules.shadowsocks = {
+    enable = mkEnableOption "Shadowsocks";
+
+    port = mkOption {
+      type = with types; port;
+      default = 8388;
+      description = "Port.";
+    };
+  };
+
+  config = mkIf cfg.enable {
+    secrets.shadowsocks-json.file = "${inputs.self}/secrets/shadowsocks-json";
+
+    services.fail2ban.jails.shadowsocks = {
+      enabled = true;
+      settings = {
+        filter = "shadowsocks";
+        inherit (cfg) port;
+      };
+    };
+
+    systemd.services.shadowsocks = {
+      description = "Shadowsocks";
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
+      serviceConfig = {
+        DynamicUser = true;
+        RuntimeDirectory = "shadowsocks";
+        LoadCredential = "secret.json:${config.secrets.shadowsocks-json.path}";
+        ExecStartPre =
+          let
+            mergeJson =
+              let
+                configFile = pkgs.writeText "config.json" (
+                  generators.toJSON { } {
+                    server = "::";
+                    server_port = cfg.port;
+                    # Can't really use AEAD-2022[1] just yet because it's not
+                    # supported by some[2] clients.
+                    #
+                    # [1]: https://shadowsocks.org/doc/sip022.html
+                    # [2]: https://github.com/shadowsocks/ShadowsocksX-NG/issues/1480
+                    # [2]: https://github.com/shadowsocks/shadowsocks-windows/issues/3448
+                    # method = "2022-blake3-chacha20-poly1305";
+                    method = "chacha20-ietf-poly1305";
+                    password = null; # Must be set as a secret.
+                    users = null; # Muse be set as a secret.
+                    fast_open = true;
+                    acl = pkgs.writeText "block-internal-access.acl" ''
+                      [outbound_block_list]
+                      0.0.0.0/8
+                      10.0.0.0/8
+                      100.64.0.0/10
+                      127.0.0.0/8
+                      169.254.0.0/16
+                      172.16.0.0/12
+                      192.0.0.0/24
+                      192.0.2.0/24
+                      192.88.99.0/24
+                      192.168.0.0/16
+                      198.18.0.0/15
+                      198.51.100.0/24
+                      203.0.113.0/24
+                      224.0.0.0/4
+                      240.0.0.0/4
+                      255.255.255.255/32
+                      ::1/128
+                      ::ffff:127.0.0.1/104
+                      fc00::/7
+                      fe80::/10
+                    '';
+                  }
+                );
+              in
+              pkgs.writeShellScript "meregeJson" ''
+                ${getExe pkgs.jq} \
+                  -s '.[0] * .[1]' \
+                  ${configFile} \
+                  $CREDENTIALS_DIRECTORY/secret.json \
+                  >$RUNTIME_DIRECTORY/config.json
+              '';
+          in
+          mergeJson;
+        ExecStart = "${pkgs.shadowsocks-rust}/bin/ssserver --config \${RUNTIME_DIRECTORY}/config.json";
+      };
+    };
+
+    environment.etc = mkIf config.nixfiles.modules.fail2ban.enable {
+      "fail2ban/filter.d/shadowsocks.conf".text = ''
+        [Definition]
+        failregex = ^.*tcp handshake failed.*\[::ffff:<ADDR>\].*$
+        ignoreregex =
+        journalmatch = _SYSTEMD_UNIT=shadowsocks.service
+      '';
+    };
+
+    networking.firewall.allowedTCPPorts = [ cfg.port ];
+
+    # https://github.com/shadowsocks/shadowsocks/wiki/Optimizing-Shadowsocks
+    boot.kernel.sysctl = {
+      "net.core.rmem_max" = mkOverride 100 (pow 2 26);
+      "net.core.wmem_max" = mkOverride 100 (pow 2 26);
+      "net.core.netdev_max_backlog" = pow 2 18;
+      "net.core.somaxconn" = pow 2 12;
+      "net.ipv4.tcp_syncookies" = 1;
+      "net.ipv4.tcp_tw_reuse" = mkOverride 100 1;
+      "net.ipv4.tcp_tw_recycle" = mkOverride 100 0;
+      "net.ipv4.tcp_fin_timeout" = mkOverride 100 30;
+      "net.ipv4.tcp_keepalive_time" = 60 * 20;
+      "net.ipv4.ip_local_port_range" = "10000 65000";
+      "net.ipv4.tcp_max_syn_backlog" = pow 2 13;
+      "net.ipv4.tcp_max_tw_buckets" = pow 2 12;
+      "net.ipv4.tcp_fastopen" = mkOverride 100 3;
+      "net.ipv4.tcp_mem" = mkOverride 100 (mkTcpMem 15 16 17);
+      "net.ipv4.tcp_rmem" = mkOverride 100 (mkTcpMem 12 16 26);
+      "net.ipv4.tcp_wmem" = mkOverride 100 (mkTcpMem 12 16 26);
+      "net.ipv4.tcp_mtu_probing" = 1;
+      "net.ipv4.tcp_congestion_control" = "hybla";
+    };
+  };
+}

Consider giving Nix/NixOS a try! <3