at 23.11-beta 6.4 kB view raw
1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 cfg = config.services.crossfire-server; 7 serverPort = 13327; 8in { 9 options.services.crossfire-server = { 10 enable = mkOption { 11 type = types.bool; 12 default = false; 13 description = lib.mdDoc '' 14 If enabled, the Crossfire game server will be started at boot. 15 ''; 16 }; 17 18 package = mkOption { 19 type = types.package; 20 default = pkgs.crossfire-server; 21 defaultText = literalExpression "pkgs.crossfire-server"; 22 description = lib.mdDoc '' 23 The package to use for the Crossfire server (and map/arch data, if you 24 don't change dataDir). 25 ''; 26 }; 27 28 dataDir = mkOption { 29 type = types.str; 30 default = "${cfg.package}/share/crossfire"; 31 defaultText = literalExpression ''"''${config.services.crossfire.package}/share/crossfire"''; 32 description = lib.mdDoc '' 33 Where to load readonly data from -- maps, archetypes, treasure tables, 34 and the like. If you plan to edit the data on the live server (rather 35 than overlaying the crossfire-maps and crossfire-arch packages and 36 nixos-rebuilding), point this somewhere read-write and copy the data 37 there before starting the server. 38 ''; 39 }; 40 41 stateDir = mkOption { 42 type = types.str; 43 default = "/var/lib/crossfire"; 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 Text to append to the corresponding configuration files. Note that the 66 files given in the example are *not* the complete set of files available 67 to customize; look in /etc/crossfire after enabling the server to see 68 the available files, and read the comments in each file for detailed 69 documentation on the format and what settings are available. 70 71 Note that the motd, rules, and news files, if configured here, will 72 overwrite the example files that come with the server, rather than being 73 appended to them as the other configuration files are. 74 ''; 75 example = literalExpression '' 76 { 77 dm_file = ''' 78 admin:secret_password:localhost 79 alice:xyzzy:* 80 '''; 81 ban_file = ''' 82 # Bob is a jerk 83 bob@* 84 # So is everyone on 192.168.86.255/24 85 *@192.168.86. 86 '''; 87 metaserver2 = ''' 88 metaserver2_notification on 89 localhostname crossfire.example.net 90 '''; 91 motd = "Welcome to CrossFire!"; 92 news = "No news yet."; 93 rules = "Don't be a jerk."; 94 settings = ''' 95 # be nicer to newbies and harsher to experienced players 96 balanced_stat_loss true 97 # don't let players pick up and use admin-created items 98 real_wiz false 99 '''; 100 } 101 ''; 102 default = {}; 103 }; 104 }; 105 106 config = mkIf cfg.enable { 107 users.users.crossfire = { 108 description = "Crossfire server daemon user"; 109 home = cfg.stateDir; 110 createHome = false; 111 isSystemUser = true; 112 group = "crossfire"; 113 }; 114 users.groups.crossfire = {}; 115 116 # Merge the cfg.configFiles setting with the default files shipped with 117 # Crossfire. 118 # For most files this consists of reading ${crossfire}/etc/crossfire/${name} 119 # and appending the user setting to it; the motd, news, and rules are handled 120 # specially, with user-provided values completely replacing the original. 121 environment.etc = lib.attrsets.mapAttrs' 122 (name: value: lib.attrsets.nameValuePair "crossfire/${name}" { 123 mode = "0644"; 124 text = 125 (optionalString (!elem name ["motd" "news" "rules"]) 126 (fileContents "${cfg.package}/etc/crossfire/${name}")) 127 + "\n${value}"; 128 }) ({ 129 ban_file = ""; 130 dm_file = ""; 131 exp_table = ""; 132 forbid = ""; 133 metaserver2 = ""; 134 motd = fileContents "${cfg.package}/etc/crossfire/motd"; 135 news = fileContents "${cfg.package}/etc/crossfire/news"; 136 rules = fileContents "${cfg.package}/etc/crossfire/rules"; 137 settings = ""; 138 stat_bonus = ""; 139 } // cfg.configFiles); 140 141 systemd.services.crossfire-server = { 142 description = "Crossfire Server Daemon"; 143 wantedBy = [ "multi-user.target" ]; 144 after = [ "network.target" ]; 145 146 serviceConfig = mkMerge [ 147 { 148 ExecStart = "${cfg.package}/bin/crossfire-server -conf /etc/crossfire -local '${cfg.stateDir}' -data '${cfg.dataDir}'"; 149 Restart = "always"; 150 User = "crossfire"; 151 Group = "crossfire"; 152 WorkingDirectory = cfg.stateDir; 153 } 154 (mkIf (cfg.stateDir == "/var/lib/crossfire") { 155 StateDirectory = "crossfire"; 156 }) 157 ]; 158 159 # The crossfire server needs access to a bunch of files at runtime that 160 # are not created automatically at server startup; they're meant to be 161 # installed in $PREFIX/var/crossfire by `make install`. And those files 162 # need to be writeable, so we can't just point at the ones in the nix 163 # store. Instead we take the approach of copying them out of the store 164 # on first run. If `bookarch` already exists, we assume the rest of the 165 # files do as well, and copy nothing -- otherwise we risk ovewriting 166 # server state information every time the server is upgraded. 167 preStart = '' 168 if [ ! -e "${cfg.stateDir}"/bookarch ]; then 169 ${pkgs.rsync}/bin/rsync -a --chmod=u=rwX,go=rX \ 170 "${cfg.package}/var/crossfire/" "${cfg.stateDir}/" 171 fi 172 ''; 173 }; 174 175 networking.firewall = mkIf cfg.openFirewall { 176 allowedTCPPorts = [ serverPort ]; 177 }; 178 }; 179}