{ config, pkgs, lib, ... }: let cfg = config.services.pufferpanel; in { options.services.pufferpanel = { enable = lib.mkOption { type = lib.types.bool; default = false; description = lib.mdDoc '' Whether to enable PufferPanel game management server. Note that [PufferPanel templates] and binaries downloaded by PufferPanel expect [FHS environment]. It is possible to set {option}`package` option to use PufferPanel wrapper with FHS environment. For example, to use `Download Game from Steam` and `Download Java` template operations: ```Nix { lib, pkgs, ... }: { services.pufferpanel = { enable = true; extraPackages = with pkgs; [ bash curl gawk gnutar gzip ]; package = pkgs.buildFHSEnv { name = "pufferpanel-fhs"; runScript = lib.getExe pkgs.pufferpanel; targetPkgs = pkgs': with pkgs'; [ icu openssl zlib ]; }; }; } ``` [PufferPanel templates]: https://github.com/PufferPanel/templates [FHS environment]: https://wikipedia.org/wiki/Filesystem_Hierarchy_Standard ''; }; package = lib.mkPackageOptionMD pkgs "pufferpanel" { }; extraGroups = lib.mkOption { type = lib.types.listOf lib.types.str; default = [ ]; example = [ "podman" ]; description = lib.mdDoc '' Additional groups for the systemd service. ''; }; extraPackages = lib.mkOption { type = lib.types.listOf lib.types.package; default = [ ]; example = lib.literalExpression "[ pkgs.jre ]"; description = lib.mdDoc '' Packages to add to the PATH environment variable. Both the {file}`bin` and {file}`sbin` subdirectories of each package are added. ''; }; environment = lib.mkOption { type = lib.types.attrsOf lib.types.str; default = { }; example = lib.literalExpression '' { PUFFER_WEB_HOST = ":8080"; PUFFER_DAEMON_SFTP_HOST = ":5657"; PUFFER_DAEMON_CONSOLE_BUFFER = "1000"; PUFFER_DAEMON_CONSOLE_FORWARD = "true"; PUFFER_PANEL_REGISTRATIONENABLED = "false"; } ''; description = lib.mdDoc '' Environment variables to set for the service. Secrets should be specified using {option}`environmentFile`. Refer to the [PufferPanel source code][] for the list of available configuration options. Variable name is an upper-cased configuration entry name with underscores instead of dots, prefixed with `PUFFER_`. For example, `panel.settings.companyName` entry can be set using {env}`PUFFER_PANEL_SETTINGS_COMPANYNAME`. When running with panel enabled (configured with `PUFFER_PANEL_ENABLE` environment variable), it is recommended disable registration using `PUFFER_PANEL_REGISTRATIONENABLED` environment variable (registration is enabled by default). To create the initial administrator user, run {command}`pufferpanel --workDir /var/lib/pufferpanel user add --admin`. Some options override corresponding settings set via web interface (e.g. `PUFFER_PANEL_REGISTRATIONENABLED`). Those options can be temporarily toggled or set in settings but do not persist between restarts. [PufferPanel source code]: https://github.com/PufferPanel/PufferPanel/blob/master/config/entries.go ''; }; environmentFile = lib.mkOption { type = lib.types.nullOr lib.types.path; default = null; description = lib.mdDoc '' File to load environment variables from. Loaded variables override values set in {option}`environment`. ''; }; }; config = lib.mkIf cfg.enable { systemd.services.pufferpanel = { description = "PufferPanel game management server"; wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; path = cfg.extraPackages; environment = cfg.environment; # Note that we export environment variables for service directories if the # value is not set. An empty environment variable is considered to be set. # E.g. # export PUFFER_LOGS=${PUFFER_LOGS-$LOGS_DIRECTORY} # would set PUFFER_LOGS to $LOGS_DIRECTORY if PUFFER_LOGS environment # variable is not defined. script = '' ${lib.concatLines (lib.mapAttrsToList (name: value: '' export ${name}="''${${name}-${value}}" '') { PUFFER_LOGS = "$LOGS_DIRECTORY"; PUFFER_DAEMON_DATA_CACHE = "$CACHE_DIRECTORY"; PUFFER_DAEMON_DATA_SERVERS = "$STATE_DIRECTORY/servers"; PUFFER_DAEMON_DATA_BINARIES = "$STATE_DIRECTORY/binaries"; })} exec ${lib.getExe cfg.package} run --workDir "$STATE_DIRECTORY" ''; serviceConfig = { Type = "simple"; Restart = "always"; UMask = "0077"; SupplementaryGroups = cfg.extraGroups; StateDirectory = "pufferpanel"; StateDirectoryMode = "0700"; CacheDirectory = "pufferpanel"; CacheDirectoryMode = "0700"; LogsDirectory = "pufferpanel"; LogsDirectoryMode = "0700"; EnvironmentFile = cfg.environmentFile; # Command "pufferpanel shutdown --pid $MAINPID" sends SIGTERM (code 15) # to the main process and waits for termination. This is essentially # KillMode=mixed we are using here. See # https://freedesktop.org/software/systemd/man/systemd.kill.html#KillMode= KillMode = "mixed"; DynamicUser = true; ProtectHome = true; ProtectProc = "invisible"; ProtectClock = true; ProtectHostname = true; ProtectControlGroups = true; ProtectKernelLogs = true; ProtectKernelModules = true; ProtectKernelTunables = true; PrivateUsers = true; PrivateDevices = true; RestrictRealtime = true; RestrictNamespaces = [ "user" "mnt" ]; # allow buildFHSEnv RestrictAddressFamilies = [ "AF_INET" "AF_INET6" "AF_UNIX" ]; LockPersonality = true; DeviceAllow = [ "" ]; DevicePolicy = "closed"; CapabilityBoundingSet = [ "" ]; }; }; }; meta.maintainers = [ lib.maintainers.tie ]; }