yep, more dotfiles
1{ pkgs
2, config
3, ...
4}:
5
6let
7 json-format = pkgs.formats.json { };
8
9 headscale-port = 3006;
10 headscale-derp-port = 3478;
11 headscale-hostname = "headscale.wiro.world";
12
13 headscale-metrics-port = 9003;
14in
15{
16 config = {
17 networking.firewall.allowedUDPPorts = [ headscale-derp-port ];
18
19 age.secrets.headscale-oidc-secret = { file = secrets/headscale-oidc-secret.age; owner = config.services.headscale.user; };
20 services.headscale = {
21 enable = true;
22
23 port = headscale-port;
24 settings = {
25 server_url = "https://${headscale-hostname}";
26 metrics_listen_addr = "127.0.0.1:${toString headscale-metrics-port}";
27
28 policy.path = json-format.generate "policy.json" {
29 acls = [
30 {
31 action = "accept";
32 src = [ "autogroup:member" ];
33 dst = [ "autogroup:self:*" ];
34 }
35 ];
36 ssh = [
37 {
38 action = "accept";
39 src = [ "autogroup:member" ];
40 dst = [ "autogroup:self" ];
41 # Adding root here is privilege escalation as a feature :)
42 users = [ "autogroup:nonroot" ];
43 }
44 ];
45 };
46
47 # disable TLS
48 tls_cert_path = null;
49 tls_key_path = null;
50
51 dns = {
52 magic_dns = true;
53 base_domain = "net.wiro.world";
54
55 override_local_dns = true;
56 # Quad9 nameservers
57 nameservers.global = [ "9.9.9.9" "149.112.112.112" "2620:fe::fe" "2620:fe::9" ];
58 };
59
60 oidc = {
61 only_start_if_oidc_is_available = true;
62 issuer = "https://auth.wiro.world";
63 client_id = "headscale";
64 client_secret_path = config.age.secrets.headscale-oidc-secret.path;
65 scope = [ "openid" "profile" "email" "groups" ];
66 pkce.enabled = true;
67 };
68
69 derp.server = {
70 enable = true;
71 stun_listen_addr = "0.0.0.0:${toString headscale-derp-port}";
72 };
73 };
74 };
75 # headscale only starts if oidc is available
76 systemd.services.headscale.after = [ "authelia-main.service" ];
77
78 services.caddy = {
79 virtualHosts.${headscale-hostname}.extraConfig = ''
80 reverse_proxy http://localhost:${toString headscale-port}
81 '';
82 };
83 };
84}