{ lib, pkgs, config, ... }: let cfg = config.services.headscale; server-url = "head.pbsds.net"; derpPort = 3478; inherit (lib) mkIf getExe; in { environment.systemPackages = mkIf cfg.enable [ cfg.package ]; services.headscale = { enable = true; address = "127.0.0.1"; port = 4987; # https://github.com/juanfont/headscale/blob/main/config-example.yaml # https://search.nixos.org/options?query=services.headscale.settings settings = { server_url = "https://${server-url}:443"; logtail.enabled = false; log.level = "warn"; # https://tailscale.com/kb/1054/dns dns_config.override_local_dns = true; # force clients to use our dns #dns_config.nameservers = [ "1.1.1.1" ]; dns_config.magic_dns = true; # put our dns first in search dns_config.domains = [ "ts.pbsds.net" ]; # search domains to inject into clients dns_config.base_domain = "pbsds.net"; # clients become {hostname}.namespace.{base_domain} # List of IP prefixes to allocate tailaddresses from. ip_prefixes = [ "100.64.0.0/10" "fd7a:115c:a1e0::/48" ]; # DERP is a relay system that Tailscale uses when a direct connection cannot be established. # https://tailscale.com/blog/how-tailscale-works/#encrypted-tcp-relays-derp # headscale needs a list of DERP servers that can be presented to the clients. derp.server.enable = true; # run embedded DERP server derp.server.region_id = 999; derp.server.stun_listen_addr = "0.0.0.0:${toString derpPort}"; # UDP #derp.server.private_key_path # autogenerated if it's missing. #derp.urls = [] # List of externally available DERP maps }; }; systemd.services."headscale-provisioning" = mkIf cfg.enable { serviceConfig.Type = "oneshot"; after = [ "headscale.service" ]; wantedBy = [ "headscale.service" ]; script = '' sleep 60 # Wait for headscale to be ready ${getExe cfg.package} namespaces create ts || true ''; }; # The DERP server networking.firewall.allowedUDPPorts = mkIf (cfg.enable && cfg.settings.derp.server.enable) [ derpPort ]; # https reverse proxy networking.firewall.allowedTCPPorts = mkIf cfg.enable [ 80 443 ]; services.nginx.enable = mkIf cfg.enable true; services.nginx.virtualHosts."${server-url}" = mkIf cfg.enable { forceSSL = true; # addSSL = true; enableACME = true; #useACMEHost = acmeDomain; locations."/" = { proxyPass = "http://localhost:${toString cfg.port}"; proxyWebsockets = true; }; #locations."/metrics".proxyPass = "http://${cfg.settings.metrics_listen_addr}/metrics"; }; }