{ config, lib, tailscalesdPackage ? null, ... }: let inherit (lib) mkEnableOption mkIf mkOption types ; cfg = config.services.tailscalesd; execStart = lib.concatStringsSep " " ( [ (lib.getExe' cfg.package "tailscalesd") ] ++ map lib.escapeShellArg cfg.extraArgs ); in { options.services.tailscalesd = { enable = mkEnableOption "tailscalesd Prometheus HTTP service discovery daemon"; package = mkOption { type = types.nullOr types.package; default = tailscalesdPackage; defaultText = "self.packages..tailscalesd"; description = "Package that provides the tailscalesd executable."; }; user = mkOption { type = types.str; default = "tailscalesd"; description = "System user for the tailscalesd process."; }; group = mkOption { type = types.str; default = "tailscalesd"; description = "System group for the tailscalesd process."; }; environmentFile = mkOption { type = types.nullOr types.str; default = null; example = "/run/secrets/tailscalesd.env"; description = "Optional EnvironmentFile with TAILSCALESD_* values, including secrets."; }; environment = mkOption { type = types.attrsOf types.str; default = { }; description = "Extra environment variables for tailscalesd."; }; host = mkOption { type = types.str; default = "127.0.0.1"; description = "Bind address for tailscalesd."; }; port = mkOption { type = types.port; default = 9242; description = "Bind port for tailscalesd."; }; interval = mkOption { type = types.ints.positive; default = 60; description = "Polling interval in seconds."; }; extraArgs = mkOption { type = types.listOf types.str; default = [ ]; description = "Extra CLI arguments appended to the tailscalesd command."; }; openFirewall = mkOption { type = types.bool; default = false; description = "Open the service port in the host firewall."; }; }; config = mkIf cfg.enable { assertions = [ { assertion = cfg.package != null; message = "services.tailscalesd.package must be set when services.tailscalesd.enable = true."; } ]; users.groups = mkIf (cfg.group == "tailscalesd") { tailscalesd = { }; }; users.users = mkIf (cfg.user == "tailscalesd") { tailscalesd = { isSystemUser = true; group = cfg.group; }; }; networking.firewall.allowedTCPPorts = lib.optionals cfg.openFirewall [ cfg.port ]; systemd.services.tailscalesd = { description = "tailscalesd"; wantedBy = [ "multi-user.target" ]; wants = [ "network-online.target" ]; after = [ "network-online.target" ]; serviceConfig = { Type = "simple"; User = cfg.user; Group = cfg.group; ExecStart = execStart; Restart = "on-failure"; RestartSec = "5s"; NoNewPrivileges = true; PrivateTmp = true; ProtectHome = true; ProtectSystem = "strict"; WorkingDirectory = "/var/lib/tailscalesd"; StateDirectory = "tailscalesd"; } // lib.optionalAttrs (cfg.environmentFile != null) { EnvironmentFile = cfg.environmentFile; }; environment = cfg.environment // { TAILSCALESD_HOST = cfg.host; TAILSCALESD_PORT = toString cfg.port; TAILSCALESD_INTERVAL = toString cfg.interval; }; }; }; }