at 23.11-beta 5.7 kB view raw
1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 cfg = config.services.deliantra-server; 7 serverPort = 13327; 8in { 9 options.services.deliantra-server = { 10 enable = mkOption { 11 type = types.bool; 12 default = false; 13 description = lib.mdDoc '' 14 If enabled, the Deliantra game server will be started at boot. 15 ''; 16 }; 17 18 package = mkOption { 19 type = types.package; 20 default = pkgs.deliantra-server; 21 defaultText = literalExpression "pkgs.deliantra-server"; 22 description = lib.mdDoc '' 23 The package to use for the Deliantra server (and map/arch data, if you 24 don't change dataDir). 25 ''; 26 }; 27 28 dataDir = mkOption { 29 type = types.str; 30 default = "${pkgs.deliantra-data}"; 31 defaultText = literalExpression ''"''${pkgs.deliantra-data}"''; 32 description = lib.mdDoc '' 33 Where to store readonly data (maps, archetypes, sprites, etc). 34 Note that if you plan to use the live map editor (rather than editing 35 the maps offline and then nixos-rebuilding), THIS MUST BE WRITEABLE -- 36 copy the deliantra-data someplace writeable (say, 37 /var/lib/deliantra/data) and update this option accordingly. 38 ''; 39 }; 40 41 stateDir = mkOption { 42 type = types.str; 43 default = "/var/lib/deliantra"; 44 description = lib.mdDoc '' 45 Where to store runtime data (save files, persistent items, etc). 46 47 If left at the default, this will be automatically created on server 48 startup if it does not already exist. If changed, it is the admin's 49 responsibility to make sure that the directory exists and is writeable 50 by the `crossfire` user. 51 ''; 52 }; 53 54 openFirewall = mkOption { 55 type = types.bool; 56 default = false; 57 description = lib.mdDoc '' 58 Whether to open ports in the firewall for the server. 59 ''; 60 }; 61 62 configFiles = mkOption { 63 type = types.attrsOf types.str; 64 description = lib.mdDoc '' 65 Contents of the server configuration files. These will be appended to 66 the example configurations the server comes with and overwrite any 67 default settings defined therein. 68 69 The example here is not comprehensive. See the files in 70 /etc/deliantra-server after enabling this module for full documentation. 71 ''; 72 example = literalExpression '' 73 { 74 dm_file = ''' 75 admin:secret_password:localhost 76 alice:xyzzy:* 77 '''; 78 motd = "Welcome to Deliantra!"; 79 settings = ''' 80 # Settings for game mechanics. 81 stat_loss_on_death true 82 armor_max_enchant 7 83 '''; 84 config = ''' 85 # Settings for the server daemon. 86 hiscore_url https://deliantra.example.net/scores/ 87 max_map_reset 86400 88 '''; 89 } 90 ''; 91 default = { 92 motd = ""; 93 }; 94 }; 95 }; 96 97 config = mkIf cfg.enable { 98 users.users.deliantra = { 99 description = "Deliantra server daemon user"; 100 home = cfg.stateDir; 101 createHome = false; 102 isSystemUser = true; 103 group = "deliantra"; 104 }; 105 users.groups.deliantra = {}; 106 107 # Merge the cfg.configFiles setting with the default files shipped with 108 # Deliantra. 109 # For most files this consists of reading 110 # ${deliantra}/etc/deliantra-server/${name} and appending the user setting 111 # to it. 112 environment.etc = lib.attrsets.mapAttrs' 113 (name: value: lib.attrsets.nameValuePair "deliantra-server/${name}" { 114 mode = "0644"; 115 text = 116 # Deliantra doesn't come with a motd file, but respects it if present 117 # in /etc. 118 (optionalString (name != "motd") 119 (fileContents "${cfg.package}/etc/deliantra-server/${name}")) 120 + "\n${value}"; 121 }) ({ 122 motd = ""; 123 settings = ""; 124 config = ""; 125 dm_file = ""; 126 } // cfg.configFiles); 127 128 systemd.services.deliantra-server = { 129 description = "Deliantra Server Daemon"; 130 wantedBy = [ "multi-user.target" ]; 131 after = [ "network.target" ]; 132 133 environment = { 134 DELIANTRA_DATADIR="${cfg.dataDir}"; 135 DELIANTRA_LOCALDIR="${cfg.stateDir}"; 136 DELIANTRA_CONFDIR="/etc/deliantra-server"; 137 }; 138 139 serviceConfig = mkMerge [ 140 { 141 ExecStart = "${cfg.package}/bin/deliantra-server"; 142 Restart = "always"; 143 User = "deliantra"; 144 Group = "deliantra"; 145 WorkingDirectory = cfg.stateDir; 146 } 147 (mkIf (cfg.stateDir == "/var/lib/deliantra") { 148 StateDirectory = "deliantra"; 149 }) 150 ]; 151 152 # The deliantra server needs access to a bunch of files at runtime that 153 # are not created automatically at server startup; they're meant to be 154 # installed in $PREFIX/var/deliantra-server by `make install`. And those 155 # files need to be writeable, so we can't just point at the ones in the 156 # nix store. Instead we take the approach of copying them out of the store 157 # on first run. If `bookarch` already exists, we assume the rest of the 158 # files do as well, and copy nothing -- otherwise we risk ovewriting 159 # server state information every time the server is upgraded. 160 preStart = '' 161 if [ ! -e "${cfg.stateDir}"/bookarch ]; then 162 ${pkgs.rsync}/bin/rsync -a --chmod=u=rwX,go=rX \ 163 "${cfg.package}/var/deliantra-server/" "${cfg.stateDir}/" 164 fi 165 ''; 166 }; 167 168 networking.firewall = mkIf cfg.openFirewall { 169 allowedTCPPorts = [ serverPort ]; 170 }; 171 }; 172}