1 { config, lib, pkgs, ... }:
6 cfg = config.services.mchprs;
7 settingsFormat = pkgs.formats.toml { };
9 whitelistFile = pkgs.writeText "whitelist.json"
11 (mapAttrsToList (n: v: { name = n; uuid = v; }) cfg.whitelist.list));
14 (removeAttrs cfg.settings [ "address" "port" ]) //
16 bind_address = cfg.settings.address + ":" + toString cfg.settings.port;
17 whitelist = cfg.whitelist.enable;
20 configTomlFile = settingsFormat.generate "Config.toml" configToml;
25 enable = mkEnableOption "MCHPRS, a Minecraft server";
27 declarativeSettings = mkOption {
31 Whether to use a declarative configuration for MCHPRS.
35 declarativeWhitelist = mkOption {
39 Whether to use a declarative whitelist.
40 The options {option}`services.mchprs.whitelist.list`
41 will be applied if and only if set to `true`.
47 default = "/var/lib/mchprs";
49 Directory to store MCHPRS database and other state/data files.
53 openFirewall = mkOption {
57 Whether to open ports in the firewall for the server.
59 {option}`services.mchprs.declarativeSettings` is `true`.
63 maxRuntime = mkOption {
68 Automatically restart the server after
69 {option}`services.mchprs.maxRuntime`.
70 The time span format is described here:
71 https://www.freedesktop.org/software/systemd/man/systemd.time.html#Parsing%20Time%20Spans.
72 If `null`, then the server is not restarted automatically.
76 package = mkPackageOption pkgs "mchprs" { };
79 type = types.submodule {
80 freeformType = settingsFormat.type;
89 {option}`services.mchprs.declarativeSettings` is `true`.
97 Address for the server.
98 Please use enclosing square brackets when using ipv6.
100 {option}`services.mchprs.declarativeSettings` is `true`.
106 default = "Minecraft High Performance Redstone Server";
110 {option}`services.mchprs.declarativeSettings` is `true`.
114 chat_format = mkOption {
116 default = "<{username}> {message}";
118 How to format chat message interpolating `username`
119 and `message` with curly braces.
121 {option}`services.mchprs.declarativeSettings` is `true`.
125 max_players = mkOption {
126 type = types.ints.positive;
129 Maximum number of simultaneous players.
131 {option}`services.mchprs.declarativeSettings` is `true`.
135 view_distance = mkOption {
136 type = types.ints.positive;
139 Maximal distance (in chunks) between players and loaded chunks.
141 {option}`services.mchprs.declarativeSettings` is `true`.
145 bungeecord = mkOption {
149 Enable compatibility with
150 [BungeeCord](https://github.com/SpigotMC/BungeeCord).
152 {option}`services.mchprs.declarativeSettings` is `true`.
156 schemati = mkOption {
160 Mimic the verification and directory layout used by the
161 Open Redstone Engineers
162 [Schemati plugin](https://github.com/OpenRedstoneEngineers/Schemati).
164 {option}`services.mchprs.declarativeSettings` is `true`.
168 block_in_hitbox = mkOption {
172 Allow placing blocks inside of players
173 (hitbox logic is simplified).
175 {option}`services.mchprs.declarativeSettings` is `true`.
179 auto_redpiler = mkOption {
183 Use redpiler automatically.
185 {option}`services.mchprs.declarativeSettings` is `true`.
193 Configuration for MCHPRS via `Config.toml`.
194 See https://github.com/MCHPR/MCHPRS/blob/master/README.md for documentation.
203 Whether or not the whitelist (in `whitelist.json`) shoud be enabled.
204 Only has effect when {option}`services.mchprs.declarativeSettings` is `true`.
211 minecraftUUID = types.strMatching
212 "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}" // {
213 description = "Minecraft UUID";
216 types.attrsOf minecraftUUID;
218 example = literalExpression ''
220 username1 = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
221 username2 = "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy";
225 Whitelisted players, only has an effect when
226 {option}`services.mchprs.declarativeWhitelist` is
227 `true` and the whitelist is enabled
228 via {option}`services.mchprs.whitelist.enable`.
229 This is a mapping from Minecraft usernames to UUIDs.
230 You can use <https://mcuuid.net/> to get a
231 Minecraft UUID for a username.
238 config = mkIf cfg.enable {
239 users.users.mchprs = {
240 description = "MCHPRS service user";
246 users.groups.mchprs = { };
248 systemd.services.mchprs = {
249 description = "MCHPRS Service";
250 wantedBy = [ "multi-user.target" ];
251 after = [ "network.target" ];
254 ExecStart = "${lib.getExe cfg.package}";
256 RuntimeMaxSec = cfg.maxRuntime;
258 WorkingDirectory = cfg.dataDir;
260 StandardOutput = "journal";
261 StandardError = "journal";
264 CapabilityBoundingSet = [ "" ];
265 DeviceAllow = [ "" ];
266 LockPersonality = true;
267 MemoryDenyWriteExecute = true;
268 PrivateDevices = true;
272 ProtectControlGroups = true;
274 ProtectHostname = true;
275 ProtectKernelLogs = true;
276 ProtectKernelModules = true;
277 ProtectKernelTunables = true;
278 ProtectProc = "invisible";
279 RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];
280 RestrictNamespaces = true;
281 RestrictRealtime = true;
282 RestrictSUIDSGID = true;
283 SystemCallArchitectures = "native";
288 (if cfg.declarativeSettings then ''
289 if [ -e .declarativeSettings ]; then
291 # Settings were declarative before, no need to back up anything
292 cp -f ${configTomlFile} Config.toml
296 # Declarative settings for the first time, backup stateful files
297 cp -b --suffix=.stateful ${configTomlFile} Config.toml
299 echo "Autogenerated file that implies that this server configuration is managed declaratively by NixOS" \
300 > .declarativeSettings
304 if [ -e .declarativeSettings ]; then
305 rm .declarativeSettings
307 '') + (if cfg.declarativeWhitelist then ''
308 if [ -e .declarativeWhitelist ]; then
310 # Whitelist was declarative before, no need to back up anything
311 ln -sf ${whitelistFile} whitelist.json
315 # Declarative whitelist for the first time, backup stateful files
316 ln -sb --suffix=.stateful ${whitelistFile} whitelist.json
318 echo "Autogenerated file that implies that this server's whitelist is managed declaratively by NixOS" \
319 > .declarativeWhitelist
323 if [ -e .declarativeWhitelist ]; then
324 rm .declarativeWhitelist
329 networking.firewall = mkIf (cfg.declarativeSettings && cfg.openFirewall) {
330 allowedUDPPorts = [ cfg.settings.port ];
331 allowedTCPPorts = [ cfg.settings.port ];
335 meta.maintainers = with maintainers; [ gdd ];