at 23.05-pre 3.2 kB view raw
1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 cfg = config.services.tailscale; 7 firewallOn = config.networking.firewall.enable; 8 rpfMode = config.networking.firewall.checkReversePath; 9 isNetworkd = config.networking.useNetworkd; 10 rpfIsStrict = rpfMode == true || rpfMode == "strict"; 11in { 12 meta.maintainers = with maintainers; [ danderson mbaillie twitchyliquid64 ]; 13 14 options.services.tailscale = { 15 enable = mkEnableOption (lib.mdDoc "Tailscale client daemon"); 16 17 port = mkOption { 18 type = types.port; 19 default = 41641; 20 description = lib.mdDoc "The port to listen on for tunnel traffic (0=autoselect)."; 21 }; 22 23 interfaceName = mkOption { 24 type = types.str; 25 default = "tailscale0"; 26 description = lib.mdDoc ''The interface name for tunnel traffic. Use "userspace-networking" (beta) to not use TUN.''; 27 }; 28 29 permitCertUid = mkOption { 30 type = types.nullOr types.nonEmptyStr; 31 default = null; 32 description = lib.mdDoc "Username or user ID of the user allowed to to fetch Tailscale TLS certificates for the node."; 33 }; 34 35 package = mkOption { 36 type = types.package; 37 default = pkgs.tailscale; 38 defaultText = literalExpression "pkgs.tailscale"; 39 description = lib.mdDoc "The package to use for tailscale"; 40 }; 41 }; 42 43 config = mkIf cfg.enable { 44 warnings = optional (firewallOn && rpfIsStrict) '' 45 Strict reverse path filtering breaks Tailscale exit node use and some subnet routing setups. Consider setting: 46 47 networking.firewall.checkReversePath = "loose"; 48 ''; 49 environment.systemPackages = [ cfg.package ]; # for the CLI 50 systemd.packages = [ cfg.package ]; 51 systemd.services.tailscaled = { 52 wantedBy = [ "multi-user.target" ]; 53 path = [ 54 config.networking.resolvconf.package # for configuring DNS in some configs 55 pkgs.procps # for collecting running services (opt-in feature) 56 pkgs.glibc # for `getent` to look up user shells 57 ]; 58 serviceConfig.Environment = [ 59 "PORT=${toString cfg.port}" 60 ''"FLAGS=--tun ${lib.escapeShellArg cfg.interfaceName}"'' 61 ] ++ (lib.optionals (cfg.permitCertUid != null) [ 62 "TS_PERMIT_CERT_UID=${cfg.permitCertUid}" 63 ]); 64 # Restart tailscaled with a single `systemctl restart` at the 65 # end of activation, rather than a `stop` followed by a later 66 # `start`. Activation over Tailscale can hang for tens of 67 # seconds in the stop+start setup, if the activation script has 68 # a significant delay between the stop and start phases 69 # (e.g. script blocked on another unit with a slow shutdown). 70 # 71 # Tailscale is aware of the correctness tradeoff involved, and 72 # already makes its upstream systemd unit robust against unit 73 # version mismatches on restart for compatibility with other 74 # linux distros. 75 stopIfChanged = false; 76 }; 77 78 networking.dhcpcd.denyInterfaces = [ cfg.interfaceName ]; 79 80 systemd.network.networks."50-tailscale" = mkIf isNetworkd { 81 matchConfig = { 82 Name = cfg.interfaceName; 83 }; 84 linkConfig = { 85 Unmanaged = true; 86 ActivationPolicy = "manual"; 87 }; 88 }; 89 }; 90}