Commit 7a7db71

HPCesia <me@hpcesia.com>
2026-04-26 06:50:51
feat: tailscale service
1 parent 836709c
modules/hosts/kevin/services/default.nix
@@ -16,5 +16,7 @@ in {
     <services/mihomo>
 
     <services/podman>
+
+    (<services/tailscale> ./tailscale-authkey.age)
   ];
 }
modules/hosts/kevin/services/tailscale-authkey.age
@@ -0,0 +1,8 @@
+age-encryption.org/v1
+-> X25519 yV61r+lv9+RevECDpnkQU+0RByvKeitIfvOHGklHnXI
+/3pxciNN73Eq+qogHFsQGdEYOTJFiNa7mYVkif34M5o
+-> $B9.-grease "X4FyX d
+F3QuuFEKgyM5nMl5U9YW9nTLaaMW7nioDS5Q6dWEWiQUwyS6lJgrVlj0VStP9FqJ
+WgYy8aWSIp7k5sIOCwe7wH3NewEX
+--- ozywaguck0MtLyHe4w8grTpd1PEFrqxsn6vFTe8DSN4
+��Ln����v7,(��,�A���Zڇ��Ęֶ[O�h�EmՒ&��|�rI��e�n�
Y9\�C�$�t
)X��`��*'���+a��T�Z�	�)j�����s�P��!S��J%��"J�A�G�$
\ No newline at end of file
modules/hosts/kevin/networking.nix
@@ -5,6 +5,11 @@
       interfaces."wlp0s20f3" = {};
     };
 
+    services.mihomo.config = lib.mkIf (config.services.mihomo.enable) {
+      interface-name = "wlp0s20f3";
+      tun.auto-detect-interface = false;
+    };
+
     services.avahi = lib.mkIf config.services.desktopManager.plasma6.enable {
       enable = true;
       openFirewall = true;
modules/hosts/pardofelis/services/default.nix
@@ -34,5 +34,7 @@ in {
     <services/podman>
 
     <services/restic>
+
+    (<services/tailscale> ./tailscale-authkey.age)
   ];
 }
modules/hosts/pardofelis/services/tailscale-authkey.age
@@ -0,0 +1,8 @@
+age-encryption.org/v1
+-> X25519 N2R5r/1Fp9obURVFvzFCAXlVUgJm9f4Baw7h5OXYAwc
+KCK3RWg35eeO5Cbrkb75jI9bexlKAQuJTo+7PNVifmE
+-> h>Q-grease
+glZSfqEH6l27EK6v/fJDXVywLATyZg6KWTdnxQX981sxHhk48DzhDB7Jw83Tpk9f
+tfuh9f+7knCZut4A/aCiFQ7j4SOGJREMzIvJkr483xP8txY+uhwNujtWy3UNXS8
+--- uzWvVT1+Kx4bdcPv3+tjF34sw6mp7KKiXYbWAXpRsio
+�,��Ysp����V������$桖�@���Th�Y�C�Kܢ�X���[�T^����N!1��];Egi�:sV���t�V*oMHê�ێ�3-�͖�Y�'���Ԏz-����0�r�̧6�
\ No newline at end of file
modules/services/mihomo/config/dns.nix
@@ -26,6 +26,7 @@
         "stun.*"
         "*.sslip.io"
         "*.nip.io"
+        "headscale.hpcesia.com"
       ];
       respect-rules = true;
       nameserver = [
modules/services/mihomo/config/rules.nix
@@ -34,6 +34,7 @@
         "RULE-SET,reject_domainset,REJECT"
         "RULE-SET,reject_non_ip_drop,REJECT-DROP"
         "RULE-SET,reject_non_ip_no_drop,REJECT"
+        "RULE-SET,tailscale,DIRECT"
         "RULE-SET,cdn_domainset,🎯 节点选择"
         "RULE-SET,cdn_non_ip,🎯 节点选择"
         "RULE-SET,stream_non_ip,🇺🇸 - 自动选择"
@@ -225,6 +226,15 @@
             "DOMAIN-SUFFIX,steamcontent.com"
           ];
         };
+        tailscale = {
+          type = "inline";
+          behavior = "classical";
+          payload = [
+            "PROCESS-NAME,tailscale,DIRECT"
+            "PROCESS-NAME,tailscaled,DIRECT"
+            "PROCESS-NAME,.tailscaled-wrapped,DIRECT"
+          ];
+        };
         my_hosts = {
           type = "inline";
           behavior = "classical";
modules/services/mihomo/config/tun.nix
@@ -1,19 +1,30 @@
-{
-  den.aspects.services.provides.mihomo.nixos = {
+{lib, ...}: {
+  den.aspects.services.provides.mihomo.nixos = {config, ...}: {
     services.mihomo.tunMode = true;
 
     services.mihomo.config.tun = {
       enable = true;
-      stack = "mixed";
-      device = "ElysianRealm";
+      stack = "system";
+      device = "mihomo-tun0";
       auto-route = true;
-      auto-detect-interface = true;
+      auto-redirect = true;
+      auto-detect-interface = lib.mkDefault true;
       dns-hijack = [
         "any:53"
         "tcp://any:53"
       ];
       strict-route = true;
       mtu = 1500;
+      # Bypass Tailscale interfaces and routes to prevent routing loops and conflicts.
+      # From https://blog.ichr.me/post/tailscale-mihomo-quantumult-x/
+      exclude-interface =
+        lib.optional
+        config.services.tailscale.enable
+        config.services.tailscale.interfaceName;
+      route-exclude-address =
+        lib.optionals
+        config.services.tailscale.enable
+        ["100.64.0.0/10" "fd7a:115c:a1e0::/48"];
     };
   };
 }
modules/services/tailscale.nix
@@ -0,0 +1,48 @@
+{
+  den.aspects.services.provides.tailscale = authKeyFileAged: {
+    nixos = {
+      config,
+      pkgs,
+      ...
+    }: {
+      environment.systemPackages = [pkgs.tailscale];
+      services.tailscale = {
+        enable = true;
+        authKeyFile = config.vaultix.secrets."tailscale-auth-key".path;
+        extraUpFlags = [
+          "--login-server=https://headscale.hpcesia.com"
+          "--accept-dns=false"
+        ];
+      };
+      systemd.services.tailscaled-autoconnect = {
+        before = ["mihomo.service"];
+        unitConfig = {
+          DynamicUser = false;
+          User = "tailscaled-autoconnect";
+          Group = "tailscaled-autoconnect";
+        };
+      };
+      users.users."tailscaled-autoconnect" = {
+        isSystemUser = true;
+        useDefaultShell = true;
+        group = "tailscaled-autoconnect";
+      };
+      users.groups."tailscaled-autoconnect" = {};
+
+      networking.firewall = {
+        trustedInterfaces = [config.services.tailscale.interfaceName];
+        allowedUDPPorts = [config.services.tailscale.port];
+      };
+
+      systemd.network.wait-online.enable = false;
+      boot.initrd.systemd.network.wait-online.enable = false;
+
+      vaultix.secrets."tailscale-auth-key" = {
+        file = authKeyFileAged;
+        owner = "tailscaled-autoconnect";
+        group = "tailscaled-autoconnect";
+        mode = "0440";
+      };
+    };
+  };
+}
secrets/cache/kevin/365f8896b9d94da0a26c80f66524980137ad7226180c638ec919c6a833255ed1
@@ -0,0 +1,8 @@
+age-encryption.org/v1
+-> ssh-ed25519 WM7kiQ nMpQnE58Zt9+er/r8MiLEubiGrFuQgLpFPkoVfRkShQ
+EHdBlzpH+JBYwKqWwKiFWoxHe8ZGhYfa4UJmG39DttQ
+-> 9!G;o~e-grease vk38w+C`
+BqW/AfeTSCDyyu2Jp8ZOfVHUX21gx5UZRZ/mfUz9VbfNkDGWaeX/Knc98yp0royg
+
+--- FaIzFfFLehkWXLy1rpsmnKUO2a/dz6ghWfpbMV/zxE4
+VT�99l�4U���������|c�YG�զʽ���|$�	ur�%���w����P�-/G��C���Y�#AD�����@�k�I���Ur��=���x-�u-��=D�zA��1�/�
\ No newline at end of file
secrets/cache/pardofelis/66e6ab15d269804e06dc4fe2773c3899a98b0105d6497c4263f67db643ddf5e5
Binary file