1{ config, lib, pkgs, ... }:
2let
3 cfg = config.services.centrifugo;
4
5 settingsFormat = pkgs.formats.json { };
6
7 configFile = settingsFormat.generate "centrifugo.json" cfg.settings;
8in
9{
10 options.services.centrifugo = {
11 enable = lib.mkEnableOption "Centrifugo messaging server";
12
13 package = lib.mkPackageOption pkgs "centrifugo" { };
14
15 settings = lib.mkOption {
16 type = settingsFormat.type;
17 default = { };
18 description = ''
19 Declarative Centrifugo configuration. See the [Centrifugo
20 documentation] for a list of options.
21
22 [Centrifugo documentation]: https://centrifugal.dev/docs/server/configuration
23 '';
24 };
25
26 credentials = lib.mkOption {
27 type = lib.types.attrsOf lib.types.path;
28 default = { };
29 example = {
30 CENTRIFUGO_UNI_GRPC_TLS_KEY = "/run/keys/centrifugo-uni-grpc-tls.key";
31 };
32 description = ''
33 Environment variables with absolute paths to credentials files to load
34 on service startup.
35 '';
36 };
37
38 environmentFiles = lib.mkOption {
39 type = lib.types.listOf lib.types.path;
40 default = [ ];
41 description = ''
42 Files to load environment variables from. Options set via environment
43 variables take precedence over {option}`settings`.
44
45 See the [Centrifugo documentation] for the environment variable name
46 format.
47
48 [Centrifugo documentation]: https://centrifugal.dev/docs/server/configuration#os-environment-variables
49 '';
50 };
51
52 extraGroups = lib.mkOption {
53 type = lib.types.listOf lib.types.str;
54 default = [ ];
55 example = [ "redis-centrifugo" ];
56 description = ''
57 Additional groups for the systemd service.
58 '';
59 };
60 };
61
62 config = lib.mkIf cfg.enable {
63 systemd.services.centrifugo = {
64 description = "Centrifugo messaging server";
65 wantedBy = [ "multi-user.target" ];
66 after = [ "network.target" ];
67
68 serviceConfig = {
69 Type = "exec";
70
71 ExecStartPre = "${lib.getExe cfg.package} checkconfig --config ${configFile}";
72 ExecStart = "${lib.getExe cfg.package} --config ${configFile}";
73 ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
74
75 Restart = "always";
76 RestartSec = "1s";
77
78 # Copy files to the credentials directory with file name being the
79 # environment variable name. Note that "%d" specifier expands to the
80 # path of the credentials directory.
81 LoadCredential = lib.mapAttrsToList (name: value: "${name}:${value}") cfg.credentials;
82 Environment = lib.mapAttrsToList (name: _: "${name}=%d/${name}") cfg.credentials;
83
84 EnvironmentFile = cfg.environmentFiles;
85
86 SupplementaryGroups = cfg.extraGroups;
87
88 DynamicUser = true;
89 UMask = "0077";
90
91 ProtectHome = true;
92 ProtectProc = "invisible";
93 ProcSubset = "pid";
94 ProtectClock = true;
95 ProtectHostname = true;
96 ProtectControlGroups = true;
97 ProtectKernelLogs = true;
98 ProtectKernelModules = true;
99 ProtectKernelTunables = true;
100 PrivateUsers = true;
101 PrivateDevices = true;
102 RestrictRealtime = true;
103 RestrictNamespaces = true;
104 RestrictAddressFamilies = [
105 "AF_INET"
106 "AF_INET6"
107 "AF_UNIX"
108 ];
109 DeviceAllow = [ "" ];
110 DevicePolicy = "closed";
111 CapabilityBoundingSet = [ "" ];
112 MemoryDenyWriteExecute = true;
113 LockPersonality = true;
114 SystemCallArchitectures = "native";
115 SystemCallErrorNumber = "EPERM";
116 SystemCallFilter = [
117 "@system-service"
118 "~@privileged"
119 ];
120 };
121 };
122 };
123}