at 23.11-beta 5.5 kB view raw
1{ config 2, pkgs 3, lib 4, ... 5}: 6 7let 8 cfg = config.services.xonotic; 9 10 serverCfg = pkgs.writeText "xonotic-server.cfg" ( 11 toString cfg.prependConfig 12 + "\n" 13 + builtins.concatStringsSep "\n" ( 14 lib.mapAttrsToList (key: option: 15 let 16 escape = s: lib.escape [ "\"" ] s; 17 quote = s: "\"${s}\""; 18 19 toValue = x: quote (escape (toString x)); 20 21 value = (if lib.isList option then 22 builtins.concatStringsSep 23 " " 24 (builtins.map (x: toValue x) option) 25 else 26 toValue option 27 ); 28 in 29 "${key} ${value}" 30 ) cfg.settings 31 ) 32 + "\n" 33 + toString cfg.appendConfig 34 ); 35in 36 37{ 38 options.services.xonotic = { 39 enable = lib.mkEnableOption (lib.mdDoc "Xonotic dedicated server"); 40 41 package = lib.mkPackageOption pkgs "xonotic-dedicated" {}; 42 43 openFirewall = lib.mkOption { 44 type = lib.types.bool; 45 default = false; 46 description = lib.mdDoc '' 47 Open the firewall for TCP and UDP on the specified port. 48 ''; 49 }; 50 51 dataDir = lib.mkOption { 52 type = lib.types.path; 53 readOnly = true; 54 default = "/var/lib/xonotic"; 55 description = lib.mdDoc '' 56 Data directory. 57 ''; 58 }; 59 60 settings = lib.mkOption { 61 description = lib.mdDoc '' 62 Generates the `server.cfg` file. Refer to [upstream's example][0] for 63 details. 64 65 [0]: https://gitlab.com/xonotic/xonotic/-/blob/master/server/server.cfg 66 ''; 67 default = {}; 68 type = lib.types.submodule { 69 freeformType = with lib.types; let 70 scalars = oneOf [ singleLineStr int float ]; 71 in 72 attrsOf (oneOf [ scalars (nonEmptyListOf scalars) ]); 73 74 options.sv_public = lib.mkOption { 75 type = lib.types.int; 76 default = 0; 77 example = [ (-1) 1 ]; 78 description = lib.mdDoc '' 79 Controls whether the server will be publicly listed. 80 ''; 81 }; 82 83 options.hostname = lib.mkOption { 84 type = lib.types.singleLineStr; 85 default = "Xonotic $g_xonoticversion Server"; 86 description = lib.mdDoc '' 87 The name that will appear in the server list. `$g_xonoticversion` 88 gets replaced with the current version. 89 ''; 90 }; 91 92 options.sv_motd = lib.mkOption { 93 type = lib.types.singleLineStr; 94 default = ""; 95 description = lib.mdDoc '' 96 Text displayed when players join the server. 97 ''; 98 }; 99 100 options.sv_termsofservice_url = lib.mkOption { 101 type = lib.types.singleLineStr; 102 default = ""; 103 description = lib.mdDoc '' 104 URL for the Terms of Service for playing on your server. 105 ''; 106 }; 107 108 options.maxplayers = lib.mkOption { 109 type = lib.types.int; 110 default = 16; 111 description = lib.mdDoc '' 112 Number of player slots on the server, including spectators. 113 ''; 114 }; 115 116 options.net_address = lib.mkOption { 117 type = lib.types.singleLineStr; 118 default = "0.0.0.0"; 119 description = lib.mdDoc '' 120 The address Xonotic will listen on. 121 ''; 122 }; 123 124 options.port = lib.mkOption { 125 type = lib.types.port; 126 default = 26000; 127 description = lib.mdDoc '' 128 The port Xonotic will listen on. 129 ''; 130 }; 131 }; 132 }; 133 134 # Still useful even though we're using RFC 42 settings because *some* keys 135 # can be repeated. 136 appendConfig = lib.mkOption { 137 type = with lib.types; nullOr lines; 138 default = null; 139 description = lib.mdDoc '' 140 Literal text to insert at the end of `server.cfg`. 141 ''; 142 }; 143 144 # Certain changes need to happen at the beginning of the file. 145 prependConfig = lib.mkOption { 146 type = with lib.types; nullOr lines; 147 default = null; 148 description = lib.mdDoc '' 149 Literal text to insert at the start of `server.cfg`. 150 ''; 151 }; 152 }; 153 154 config = lib.mkIf cfg.enable { 155 systemd.services.xonotic = { 156 description = "Xonotic server"; 157 wantedBy = [ "multi-user.target" ]; 158 159 environment = { 160 # Required or else it tries to write the lock file into the nix store 161 HOME = cfg.dataDir; 162 }; 163 164 serviceConfig = { 165 DynamicUser = true; 166 User = "xonotic"; 167 StateDirectory = "xonotic"; 168 ExecStart = "${cfg.package}/bin/xonotic-dedicated"; 169 170 # Symlink the configuration from the nix store to where Xonotic actually 171 # looks for it 172 ExecStartPre = [ 173 "${pkgs.coreutils}/bin/mkdir -p ${cfg.dataDir}/.xonotic/data" 174 '' 175 ${pkgs.coreutils}/bin/ln -sf ${serverCfg} \ 176 ${cfg.dataDir}/.xonotic/data/server.cfg 177 '' 178 ]; 179 180 # Cargo-culted from search results about writing Xonotic systemd units 181 ExecReload = "${pkgs.util-linux}/bin/kill -HUP $MAINPID"; 182 183 Restart = "on-failure"; 184 RestartSec = 10; 185 StartLimitBurst = 5; 186 }; 187 }; 188 189 networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall [ 190 cfg.settings.port 191 ]; 192 networking.firewall.allowedUDPPorts = lib.mkIf cfg.openFirewall [ 193 cfg.settings.port 194 ]; 195 }; 196 197 meta.maintainers = with lib.maintainers; [ CobaltCause ]; 198}