Commit c950f21

HPCesia <me@hpcesia.com>
2026-06-30 13:43:44
Add DNS01 TLS cert for headscale subnet
1 parent 119b7dc
Changed files (6)
modules/hosts/mobius/services/services.nix
@@ -2,6 +2,7 @@
   den.hosts.mobius = {
     settings = {
       services.webserver.external = false;
+      services.webserver.caddy.tailscaleUseHttps = true;
 
       services.navidrome = {
         domain = "navidrome.net.trin.one";
@@ -25,6 +26,47 @@
 
       services.navidrome
       services.woodpecker.agent
+
+      {
+        nixos = {
+          config,
+          pkgs,
+          ...
+        }: {
+          # TODO: Remove this workaround if Headscale land it's tailscale cert support.
+          # See: https://github.com/juanfont/headscale/issues/2527
+          services.caddy = {
+            package = pkgs.caddy.withPlugins {
+              plugins = [
+                "github.com/caddy-dns/cloudflare@v0.2.4"
+              ];
+              hash = "sha256-bzMqxWTqrJ1skZmRTXyEMCKStXpljbqe5r0Ve2cnBfM=";
+            };
+            virtualHosts.headscale = {
+              hostName = "*.net.trin.one";
+              extraConfig = ''
+                tls {
+                  dns cloudflare {env.CF_API_TOKEN}
+                  resolvers 1.1.1.1 1.0.0.1
+                }
+                abort
+              '';
+            };
+          };
+
+          systemd.services.caddy.serviceConfig.EnvironmentFile = [config.vaultix.templates.caddy-headscale-env.path];
+
+          vaultix.secrets.headscale-subnet-tls-cf-token.file = ./tailscale-cloudflare-token.age;
+          vaultix.templates.caddy-headscale-env = {
+            content = ''
+              CF_API_TOKEN=${config.vaultix.placeholder.headscale-subnet-tls-cf-token}
+            '';
+            owner = config.services.caddy.user;
+            group = config.services.caddy.group;
+            mode = "0400";
+          };
+        };
+      }
     ];
   };
 }
modules/hosts/mobius/services/tailscale-cloudflare-token.age
Binary file
modules/services/proxy/dae.nix
@@ -118,6 +118,7 @@
             }
             routing {
               request {
+                qname(keyword: _acme-challenge) -> googledns
                 qname(suffix: ts.net, suffix: net.trin.one) -> tailscale
                 qname(geosite:category-ads-all) -> reject
                 qtype(https) -> reject
modules/services/webserver/caddy.nix
@@ -8,6 +8,10 @@
       den.aspects.services.webserver.caddy.reverse-proxy-collector
     ];
 
+    settings = {
+      tailscaleUseHttps = lib.mkEnableOption "Whether to use https for tailscale internal virtual hosts";
+    };
+
     persist = {
       directories = [
         {
@@ -191,7 +195,7 @@
       # (Tailscale/WireGuard already encrypts the transport). Public vhosts keep
       # automatic HTTPS.
       siteName = e:
-        if e.tailscale
+        if e.tailscale && !host.settings.services.webserver.caddy.tailscaleUseHttps
         then "http://${e.domain}"
         else e.domain;
 
modules/services/forgejo.nix
@@ -73,7 +73,7 @@
               then host.settings.core.openssh.access.port
               else 22;
             PROTOCOL = "http";
-            ROOT_URL = "http${lib.optionalString hostCfg.external "s"}://${hostCfg.domain}/";
+            ROOT_URL = "https://${hostCfg.domain}/";
           };
           service = {
             DISABLE_REGISTRATION = true;
@@ -86,7 +86,7 @@
           };
           actions = {
             ENABLED = true;
-            DEFAULT_ACTIONS_URL = "http${lib.optionalString hostCfg.external "s"}://${hostCfg.domain}";
+            DEFAULT_ACTIONS_URL = "https://${hostCfg.domain}";
           };
           webhook = {
             ALLOWED_HOST_LIST = "external,loopback";
secrets/cache/mobius/7cb3cb9d311407cc2934003c86a7d208bcd3fdf243692540d3502aae0c80f57a
@@ -0,0 +1,8 @@
+age-encryption.org/v1
+-> ssh-ed25519 qzANJQ 9n8DytAUZx3d32qruEgWHhRFc6qZyte4NPiTn1QfFXk
+vqXiR+vfg6LfemKjwUW/OkZmpFC251wX1gG3z5299MM
+-> "$_@S-grease Nu~*=c ,SmLC #n}H wmvZRA9
+TdoKOBC85bXiFR/nHRglK73uMyHx6loIfHQB0gRLEMuAVxFH8ZRNSv/oA5V+E9xj
+jX0Gc9cWN1ljYa3z+xemPHWAa1z76bXTWNeImNz2TLwyQuBJU2Q8R0qvJo/e
+--- FpiPA/pagD9baKB/mJdeE9Fh3dCSXnyBPRXF0eAJjG8
+�	O�m��	�#��#�<w�ۚ�C��K�#U;�2m�������†>E@z�Q�pX�F{/1�S�&��ͥ��z�c��8�j��
\ No newline at end of file