{ pkgs, config, lib, ... }: let service = "cs2"; cfg = config.gameservers.${service}; in { options.gameservers.${service} = { enable = lib.mkEnableOption "Counter Strike 2 server"; data_dir = lib.mkOption { type = lib.types.str; default = "/var/lib/gameservers/cs2"; }; port = lib.mkOption { type = lib.types.int; default = 27015; }; tv_port = lib.mkOption { type = lib.types.int; default = 27016; }; hostname = lib.mkOption { type = lib.types.str; default = "recoil.pro CS2"; }; map = lib.mkOption { type = lib.types.str; default = "de_dust2"; }; max_players = lib.mkOption { type = lib.types.int; default = 10; }; backup = lib.mkOption { type = lib.types.bool; default = true; }; backup_repo = lib.mkOption { type = lib.types.path; default = "/holocron/archives/gameservers/cs2"; }; }; config = lib.mkIf cfg.enable { users.users.cs2 = { isSystemUser = true; group = "cs2"; home = cfg.data_dir; createHome = true; }; users.groups.cs2 = {}; environment.systemPackages = with pkgs; [ steamcmd steam-run rcon ]; systemd.tmpfiles.rules = [ "d ${cfg.data_dir} 0770 cs2 cs2 -" "d ${cfg.data_dir}/server 0770 cs2 cs2 -" ]; environment.etc."cs2/server.cfg".text = '' hostname "${cfg.hostname}" sv_lan 0 rcon_password "$(<${config.sops.secrets."cs2/rcon".path})" mp_autoteambalance 1 mp_limitteams 2 ''; systemd.services.cs2-update = { description = "Update CS2 server"; serviceConfig = { Type = "oneshot"; User = "cs2"; }; script = '' ${pkgs.steamcmd}/bin/steamcmd \ +force_install_dir ${cfg.data_dir}/server \ +login anonymous \ +app_update 730 validate \ +quit ''; }; systemd.services.cs2-server = { description = "Counter Strike 2 Dedicated Server"; after = [ "network.target" "cs2-update.service" ]; requires = [ "cs2-update.service" ]; wantedBy = ["multi-user.target"]; serviceConfig = { User = "cs2"; Group = "cs2"; WorkingDirectory = "${cfg.data_dir}"; Restart = "always"; ExecStart = pkgs.writeShellScript "cs2-start" '' export GSLT=$(cat ${config.sops.secrets."cs2/gslt".path}) exec ${pkgs.steam-run}/bin/steam-run -- \ ${cfg.data_dir}/server/game/bin/linuxsteamrt64/cs2 \ -dedicated \ -usercon \ -console \ -port ${toString cfg.port} \ -tv_port ${toString cfg.tv_port} \ -maxplayers_override ${toString cfg.max_players} \ +game_type 0 \ +game_mode 1 \ +mapgroup mg_active \ +map ${cfg.map} \ +sv_setsteamaccount "$GSLT" \ +exec /etc/gameserver/cs2/server.cfg ''; }; }; networking.firewall.allowedTCPPorts = [cfg.port cfg.tv_port]; networking.firewall.allowedUDPPorts = [cfg.port cfg.tv_port]; # backups cs2 server with borg! services.borgbackup.jobs.${service} = { archiveBaseName = service; repo = cfg.backup_repo; paths = cfg.data_dir; compression = "auto,zstd"; #preHook = "systemctl start mysql-backup.service"; startAt = "*-*-* *:00:00"; group = "archives"; encryption.mode = "repokey-blake2"; encryption.passCommand = "cat ${config.sops.secrets."borg_passwd".path}"; extraArgs = ["--verbose" "--show-rc" "--umask" "0007"]; extraCreateArgs = ["--list" "--stats" "--filter" "AME"]; prune.keep = { within = "1d"; # Keep all archives from the last day hourly = 24; daily = 7; weekly = 12; monthly = -1; # Keep at least one archive for each month }; }; # manage secrets with sops sops.secrets = { "${service}/gslt" = { owner = service; group = service; }; "${service}/rcon" = { owner = service; group = service; }; }; }; }