about summary refs log tree commit diff
path: root/nixpkgs/nixos/modules/services/misc/pufferpanel.nix
blob: 2022406c8325c3315312954604f58b38e5af663c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
{ 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 ];
}