diff options
author | sinanmohd <sinan@sinanmohd.com> | 2025-10-14 18:12:15 +0530 |
---|---|---|
committer | sinanmohd <sinan@sinanmohd.com> | 2025-10-17 08:19:58 +0530 |
commit | 8c3ada3cdb868150be288223b9524fb152db26bc (patch) | |
tree | 663b47032106be6e44c646359b2ee0d707136db8 /os/kay/modules | |
parent | e9e51be6d7a149fbd122db51d6a2bf2673f12827 (diff) |
feat(os/kay): init headscale
Diffstat (limited to 'os/kay/modules')
-rw-r--r-- | os/kay/modules/dns/sinanmohd.com.zone | 27 | ||||
-rw-r--r-- | os/kay/modules/headscale.nix | 112 | ||||
-rw-r--r-- | os/kay/modules/www.nix | 11 |
3 files changed, 137 insertions, 13 deletions
diff --git a/os/kay/modules/dns/sinanmohd.com.zone b/os/kay/modules/dns/sinanmohd.com.zone index 0307cd6..dcbdf6c 100644 --- a/os/kay/modules/dns/sinanmohd.com.zone +++ b/os/kay/modules/dns/sinanmohd.com.zone @@ -2,7 +2,7 @@ $ORIGIN sinanmohd.com. $TTL 2d @ IN SOA ns1 hostmaster ( - 2025062100 ; serial + 2025101400 ; serial 2h ; refresh 5m ; retry 1d ; expire @@ -37,17 +37,18 @@ mta-sts IN CNAME @ _mta-sts IN TXT "v=STSv1; id=2024022500" _smtp._tls IN TXT "v=TLSRPTv1; rua=mailto:reports@sinanmohd.com" -www IN CNAME @ -git IN CNAME @ -bin IN CNAME @ -static IN CNAME @ -home IN CNAME @ -nixbin IN CNAME @ -immich IN CNAME @ -sliding IN CNAME @ -grafana IN CNAME @ -stalwart IN CNAME @ -minio IN CNAME @ -s3 IN CNAME @ +www IN CNAME @ +git IN CNAME @ +bin IN CNAME @ +static IN CNAME @ +home IN CNAME @ +nixbin IN CNAME @ +immich IN CNAME @ +sliding IN CNAME @ +grafana IN CNAME @ +stalwart IN CNAME @ +minio IN CNAME @ +s3 IN CNAME @ +headscale IN CNAME @ _acme-challenge IN NS ns1 diff --git a/os/kay/modules/headscale.nix b/os/kay/modules/headscale.nix new file mode 100644 index 0000000..24df170 --- /dev/null +++ b/os/kay/modules/headscale.nix @@ -0,0 +1,112 @@ +{ + config, + pkgs, + lib, + ... +}: +let + domain = "headscale.${config.global.userdata.domain}"; + stunPort = 3478; + + # A workaround generate a valid Headscale config accepted by Headplane when `config_strict == true`. + settings = lib.recursiveUpdate config.services.headscale.settings { + tls_cert_path = "/dev/null"; + tls_key_path = "/dev/null"; + policy.path = "/dev/null"; + }; + format = pkgs.formats.yaml { }; + headscaleConfig = format.generate "headscale.yml" settings; + + policyFormat = pkgs.formats.json { }; + policy = { + groups = { + "group:owner" = [ "sinan@" ]; + "group:bud" = [ + "sinan@" + "ann@" + ]; + }; + tagOwners = { + "tag:bud_clients" = [ "group:bud" ]; + "tag:internal" = [ "group:owner" ]; + "tag:cusat" = [ "group:owner" ]; + "tag:gaijin" = [ "group:owner" ]; + }; + acls = [ + { + action = "accept"; + src = [ "group:owner" ]; + dst = [ "*:*" ]; + } + + { + action = "accept"; + src = [ "group:bud" ]; + dst = [ "tag:bud_clients:*" ]; + } + ]; + }; +in +{ + sops.secrets = { + "headplane/cookie_secret".owner = config.services.headscale.user; + "headplane/preauth_key".owner = config.services.headscale.user; + "headscale/noise_private_key".owner = config.services.headscale.user; + "headscale/derp_private_key".owner = config.services.headscale.user; + }; + + networking.firewall.interfaces.ppp0.allowedUDPPorts = [ stunPort ]; + + services = { + headscale = { + enable = true; + port = 8139; + + settings = { + logtail.enabled = false; + server_url = "https://${domain}"; + noise.private_key_path = config.sops.secrets."headscale/noise_private_key".path; + dns = { + base_domain = "tsnet.${config.global.userdata.domain}"; + override_local_dns = false; + }; + derp = { + server = { + enabled = true; + private_key_path = config.sops.secrets."headscale/derp_private_key".path; + region_code = config.networking.hostName; + region_name = config.networking.hostName; + stun_listen_addr = "0.0.0.0:${toString stunPort}"; + region_id = 6969; + automatically_add_embedded_derp_region = true; + }; + urls = [ ]; + }; + policy = { + mode = "file"; + path = policyFormat.generate "acl.json" policy; + }; + }; + }; + + headplane = { + enable = true; + settings = { + server = { + port = 8140; + cookie_secret_path = config.sops.secrets."headplane/cookie_secret".path; + }; + headscale = { + url = "https://${domain}"; + config_path = "${headscaleConfig}"; + }; + integration.agent = { + enabled = true; + pre_authkey_path = config.sops.secrets."headplane/preauth_key".path; + }; + }; + }; + }; + + environment.systemPackages = [ config.services.headscale.package ]; +} diff --git a/os/kay/modules/www.nix b/os/kay/modules/www.nix index 6b8e285..e64c65c 100644 --- a/os/kay/modules/www.nix +++ b/os/kay/modules/www.nix @@ -112,6 +112,17 @@ in }; }; + "headscale.${domain}" = defaultOpts // { + locations = { + "/" = { + proxyWebsockets = true; + proxyPass = "http://localhost:${toString config.services.headscale.port}"; + }; + "= /".return = "307 https://headscale.${domain}/admin"; + "/admin".proxyPass = "http://localhost:${toString config.services.headplane.settings.server.port}"; + }; + }; + "${config.services.grafana.settings.server.domain}" = defaultOpts // { extraConfig = '' proxy_buffering off; |