1 { config, pkgs, lib, ... }:
4 inherit (lib) literalMD mkEnableOption mkIf mkOption types;
5 cfg = config.services.quake3-server;
7 configFile = pkgs.writeText "q3ds-extra.cfg" ''
8 set net_port ${builtins.toString cfg.port}
13 defaultBaseq3 = pkgs.requireFile rec {
15 hashMode = "recursive";
16 sha256 = "5dd8ee09eabd45e80450f31d7a8b69b846f59738726929298d8a813ce5725ed3";
18 Unfortunately, we cannot download ${name} automatically.
19 Please purchase a legitimate copy of Quake 3 and change into the installation directory.
21 You can either add all relevant files to the nix-store like this:
23 cp baseq3/pak*.pk3 /tmp/baseq3
24 nix-store --add-fixed sha256 --recursive /tmp/baseq3
26 Alternatively you can set services.quake3-server.baseq3 to a path and copy the baseq3 directory into
27 $services.quake3-server.baseq3/.q3a/
31 home = pkgs.runCommand "quake3-home" {} ''
32 mkdir -p $out/.q3a/baseq3
34 for file in ${cfg.baseq3}/*; do
35 ln -s $file $out/.q3a/baseq3/$(basename $file)
38 ln -s ${configFile} $out/.q3a/baseq3/nix.cfg
42 services.quake3-server = {
43 enable = mkEnableOption "Quake 3 dedicated server";
44 package = lib.mkPackageOption pkgs "ioquake3" { };
50 UDP Port the server should listen on.
54 openFirewall = mkOption {
62 extraConfig = mkOption {
66 seta rconPassword "superSecret" // sets RCON password for remote console
67 seta sv_hostname "My Quake 3 server" // name that appears in server list
70 Extra configuration options. Note that options changed via RCON will not be persisted. To list all possible
71 options, use "cvarlist 1" via RCON.
76 type = types.either types.package types.path;
77 default = defaultBaseq3;
78 defaultText = literalMD "Manually downloaded Quake 3 installation directory.";
79 example = "/var/lib/q3ds";
81 Path to the baseq3 files (pak*.pk3). If this is on the nix store (type = package) all .pk3 files should be saved
82 in the top-level directory. If this is on another filesystem (e.g /var/lib/baseq3) the .pk3 files are searched in
90 baseq3InStore = builtins.typeOf cfg.baseq3 == "set";
92 networking.firewall.allowedUDPPorts = mkIf cfg.openFirewall [ cfg.port ];
94 systemd.services.q3ds = {
95 description = "Quake 3 dedicated server";
96 wantedBy = [ "multi-user.target" ];
97 after = [ "networking.target" ];
99 environment.HOME = if baseq3InStore then home else cfg.baseq3;
101 serviceConfig = with lib; {
104 WorkingDirectory = home;
106 # It is possible to alter configuration files via RCON. To ensure reproducibility we have to prevent this
107 ReadOnlyPaths = if baseq3InStore then home else cfg.baseq3;
108 ExecStartPre = optionalString (!baseq3InStore) "+${pkgs.coreutils}/bin/cp ${configFile} ${cfg.baseq3}/.q3a/baseq3/nix.cfg";
110 ExecStart = "${cfg.package}/bin/ioq3ded +exec nix.cfg";
115 meta.maintainers = with lib.maintainers; [ f4814n ];