at master 2.9 kB view raw
1{ pkgs, lib, ... }: 2let 3 tls-cert = pkgs.runCommand "selfSignedCerts" { buildInputs = [ pkgs.openssl ]; } '' 4 openssl req \ 5 -x509 -newkey rsa:4096 -sha256 -days 365 \ 6 -nodes -out cert.pem -keyout key.pem \ 7 -subj '/CN=headscale' -addext "subjectAltName=DNS:headscale" 8 9 mkdir -p $out 10 cp key.pem cert.pem $out 11 ''; 12in 13{ 14 name = "headscale"; 15 meta.maintainers = with lib.maintainers; [ 16 kradalby 17 misterio77 18 ]; 19 20 nodes = 21 let 22 headscalePort = 8080; 23 stunPort = 3478; 24 peer = { 25 services.tailscale.enable = true; 26 security.pki.certificateFiles = [ "${tls-cert}/cert.pem" ]; 27 }; 28 in 29 { 30 peer1 = peer; 31 peer2 = peer; 32 33 headscale = { 34 services = { 35 headscale = { 36 enable = true; 37 port = headscalePort; 38 settings = { 39 server_url = "https://headscale"; 40 ip_prefixes = [ "100.64.0.0/10" ]; 41 derp.server = { 42 enabled = true; 43 region_id = 999; 44 stun_listen_addr = "0.0.0.0:${toString stunPort}"; 45 }; 46 dns = { 47 base_domain = "tailnet"; 48 extra_records = [ 49 { 50 name = "foo.bar"; 51 type = "A"; 52 value = "100.64.0.2"; 53 } 54 ]; 55 override_local_dns = false; 56 }; 57 }; 58 }; 59 nginx = { 60 enable = true; 61 virtualHosts.headscale = { 62 addSSL = true; 63 sslCertificate = "${tls-cert}/cert.pem"; 64 sslCertificateKey = "${tls-cert}/key.pem"; 65 locations."/" = { 66 proxyPass = "http://127.0.0.1:${toString headscalePort}"; 67 proxyWebsockets = true; 68 }; 69 }; 70 }; 71 }; 72 networking.firewall = { 73 allowedTCPPorts = [ 74 80 75 443 76 ]; 77 allowedUDPPorts = [ stunPort ]; 78 }; 79 environment.systemPackages = [ pkgs.headscale ]; 80 }; 81 }; 82 83 testScript = '' 84 start_all() 85 headscale.wait_for_unit("headscale") 86 headscale.wait_for_open_port(443) 87 88 # Create headscale user and preauth-key 89 headscale.succeed("headscale users create test") 90 authkey = headscale.succeed("headscale preauthkeys -u 1 create --reusable") 91 92 # Connect peers 93 up_cmd = f"tailscale up --login-server 'https://headscale' --auth-key {authkey}" 94 peer1.execute(up_cmd) 95 peer2.execute(up_cmd) 96 97 # Check that they are reachable from the tailnet 98 peer1.wait_until_succeeds("tailscale ping peer2") 99 peer2.wait_until_succeeds("tailscale ping peer1.tailnet") 100 assert (res := peer1.wait_until_succeeds("${lib.getExe pkgs.dig} +short foo.bar").strip()) == "100.64.0.2", f"Domain {res} did not match 100.64.0.2" 101 ''; 102}