dispenser/nix/module.nix
2025-08-06 21:29:39 +02:00

212 lines
5.9 KiB
Nix

{
config,
lib,
pkgs,
...
}:
with lib; let
cfg = config.services.dispenser;
format = pkgs.formats.toml {};
configFile = format.generate "dispenser.toml" (filterAttrs (n: v: v != null) {
inherit (cfg) server vultr dyndns schedule;
digital_ocean = cfg.digitalocean;
});
in {
options.services.dispenser = {
enable = mkEnableOption "Enables the dispenser service";
server = mkOption {
type = types.submodule {
options = {
rcon = mkOption {
type = types.str;
description = "Rcon password for created server";
};
password = mkOption {
type = types.str;
description = "Server password for created server";
};
demostf_key = mkOption {
type = types.str;
description = "Api key for demos.tf";
};
logstf_key = mkOption {
type = types.str;
description = "Api key for logs.tf";
};
config_league = mkOption {
type = types.str;
default = "etf2l";
description = "League of the config to load on startup";
};
config_mode = mkOption {
type = types.str;
default = "6v6";
description = "Gamemode of the config to load on startup";
};
name = mkOption {
type = types.str;
default = "Spire";
description = "Server name for the created server";
};
tv_name = mkOption {
type = types.str;
default = "SpireTV";
description = "STV name for the created server";
};
image = mkOption {
type = types.str;
default = "spiretf/docker-spire-server";
description = "Docker image to use for the server";
};
ssh_keys = mkOption {
type = types.listOf types.str;
description = "ssh keys to allow on the server";
};
manage_existing = mkOption {
type = types.bool;
description = "Take control of existing server";
};
extra_cfg = mkOption {
type = types.str;
description = "Extra config lines to set in the tf2 config";
default = "";
};
};
};
};
vultr = mkOption {
type = types.nullOr (types.submodule {
options = {
api_key = mkOption {
type = types.str;
description = "Vultr api key";
};
region = mkOption {
type = types.str;
default = "ams";
description = "Vultr region to deploy the server in";
};
plan = mkOption {
type = types.str;
default = "vc2-1c-2gb";
description = "Vultr plan to deploy";
};
};
});
default = null;
};
digitalocean = mkOption {
type = types.nullOr (types.submodule {
options = {
api_key = mkOption {
type = types.str;
description = "DO api key";
};
region = mkOption {
type = types.str;
default = "ams3";
description = "DO region to deploy the server in";
};
plan = mkOption {
type = types.str;
default = "s-1vcpu-2gb";
description = "DO plan to deploy";
};
};
});
default = null;
};
dyndns = mkOption {
type = types.nullOr (types.submodule {
options = {
update_url = mkOption {
type = types.str;
description = "dyndns update url";
};
hostname = mkOption {
type = types.str;
description = "hostname to update";
};
username = mkOption {
type = types.str;
description = "username for the update";
};
password = mkOption {
type = types.str;
description = "password for the update";
};
};
});
default = null;
};
schedule = mkOption {
type = types.submodule {
options = {
start = mkOption {
type = types.str;
description = "start schedule in cron format";
};
stop = mkOption {
type = types.str;
description = "start schedule in cron format";
};
};
};
};
package = mkOption {
type = types.package;
defaultText = literalExpression "pkgs.dispenser";
description = "package to use";
};
};
config = mkIf cfg.enable {
systemd.services.dispenser = {
wantedBy = ["multi-user.target"];
serviceConfig = {
ExecStart = "${cfg.package}/bin/dispenser ${configFile}";
Restart = "on-failure";
DynamicUser = true;
PrivateTmp = true;
ProtectSystem = "strict";
ProtectHome = true;
NoNewPrivileges = true;
PrivateDevices = true;
ProtectClock = true;
CapabilityBoundingSet = true;
ProtectKernelLogs = true;
ProtectControlGroups = true;
SystemCallArchitectures = "native";
ProtectKernelModules = true;
RestrictNamespaces = true;
MemoryDenyWriteExecute = true;
ProtectHostname = true;
LockPersonality = true;
ProtectKernelTunables = true;
RestrictAddressFamilies = "AF_INET AF_INET6";
RestrictRealtime = true;
ProtectProc = "noaccess";
SystemCallFilter = ["@system-service" "~@resources" "~@privileged"];
IPAddressDeny = "localhost link-local multicast";
};
};
environment.systemPackages = [
(pkgs.writeShellApplication {
name = "dispenser-cli";
runtimeInputs = [cfg.package];
text = ''
${cfg.package}/bin/dispenser ${configFile} "$@"
'';
})
];
};
}