{ config, lib, ... }: let inherit (lib) mkIf; metricsEnable = false; domain = "hs.ccnlc.eu"; stunPort = 3478; in { imports = [ ./dns.nix ./acls.nix ]; config = mkIf config.services.headscale.enable { environment.systemPackages = [ config.services.headscale.package ]; networking.firewall.allowedUDPPorts = [ stunPort # DERP ]; services = { headscale = { address = "127.0.0.1"; port = 8521; settings = { server_url = "https://${domain}"; tls_cert_path = null; tls_key_path = null; ip_prefixes = [ "100.64.0.0/10" "fd7a:115c:a1e0::/48" ]; ephemeral_node_inactivity_timeout = "30m"; node_update_check_interval = "10s"; metrics_listen_addr = mkIf metricsEnable "127.0.0.1:8086"; # logging log = { format = "text"; level = "info"; }; logtail.enabled = false; derp = { # Reference: https://github.com/juanfont/headscale/issues/1326#issuecomment-1505487881 server = { enabled = true; stun_listen_addr = "0.0.0.0:${toString stunPort}"; # Region code and name are displayed in the Tailscale UI to identify a DERP region region_code = "headscale"; region_name = "Headscale Embedded DERP"; region_id = 999; }; urls = [ ]; paths = [ ]; auto_update_enabled = false; update_frequency = "6h"; }; }; }; nginx.virtualHosts.${domain} = { forceSSL = true; enableACME = true; quic = true; http3 = true; locations = { "/" = { proxyPass = "http://localhost:${toString config.services.headscale.port}"; proxyWebsockets = true; }; "/metrics" = mkIf metricsEnable { proxyPass = "http://${toString config.services.headscale.settings.metrics_listen_addr}/metrics"; }; }; extraConfig = '' add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; ''; }; }; systemd.services = { tailscaled.after = [ "headscale.service" ]; headscale = { environment = { # required to use ssh HEADSCALE_EXPERIMENTAL_FEATURE_SSH = "1"; }; }; }; }; }