1 { config, lib, options, pkgs, ... }:
5 cfg = config.services.galene;
6 opt = options.services.galene;
7 defaultstateDir = "/var/lib/galene";
8 defaultrecordingsDir = "${cfg.stateDir}/recordings";
9 defaultgroupsDir = "${cfg.stateDir}/groups";
10 defaultdataDir = "${cfg.stateDir}/data";
15 enable = mkEnableOption "Galene Service";
18 default = defaultstateDir;
21 The directory where Galene stores its internal state. If left as the default
22 value this directory will automatically be created before the Galene server
23 starts, otherwise the sysadmin is responsible for ensuring the directory
24 exists with appropriate ownership and permissions.
31 description = "User account under which galene runs.";
37 description = "Group under which galene runs.";
44 Whether Galene should listen in http or in https. If left as the default
45 value (false), Galene needs to be fed a private key and a certificate.
50 type = types.nullOr types.str;
52 example = "/path/to/your/cert.pem";
54 Path to the server's certificate. The file is copied at runtime to
55 Galene's data directory where it needs to reside.
60 type = types.nullOr types.str;
62 example = "/path/to/your/key.pem";
64 Path to the server's private key. The file is copied at runtime to
65 Galene's data directory where it needs to reside.
69 httpAddress = mkOption {
72 description = "HTTP listen address for galene.";
78 description = "HTTP listen port.";
81 staticDir = mkOption {
83 default = "${cfg.package.static}/static";
84 defaultText = literalExpression ''"''${package.static}/static"'';
85 example = "/var/lib/galene/static";
86 description = "Web server directory.";
89 recordingsDir = mkOption {
91 default = defaultrecordingsDir;
92 defaultText = literalExpression ''"''${config.${opt.stateDir}}/recordings"'';
93 example = "/var/lib/galene/recordings";
94 description = "Recordings directory.";
99 default = defaultdataDir;
100 defaultText = literalExpression ''"''${config.${opt.stateDir}}/data"'';
101 example = "/var/lib/galene/data";
102 description = "Data directory.";
105 groupsDir = mkOption {
107 default = defaultgroupsDir;
108 defaultText = literalExpression ''"''${config.${opt.stateDir}}/groups"'';
109 example = "/var/lib/galene/groups";
110 description = "Web server directory.";
113 package = mkPackageOption pkgs "galene" { };
117 config = mkIf cfg.enable {
120 assertion = cfg.insecure || (cfg.certFile != null && cfg.keyFile != null);
122 Galene needs both certFile and keyFile defined for encryption, or
128 systemd.services.galene = {
129 description = "galene";
130 after = [ "network.target" ];
131 wantedBy = [ "multi-user.target" ];
134 ${optionalString (cfg.insecure != true) ''
135 install -m 700 -o '${cfg.user}' -g '${cfg.group}' ${cfg.certFile} ${cfg.dataDir}/cert.pem
136 install -m 700 -o '${cfg.user}' -g '${cfg.group}' ${cfg.keyFile} ${cfg.dataDir}/key.pem
140 serviceConfig = mkMerge [
145 WorkingDirectory = cfg.stateDir;
146 ExecStart = ''${cfg.package}/bin/galene \
147 ${optionalString (cfg.insecure) "-insecure"} \
148 -data ${cfg.dataDir} \
149 -groups ${cfg.groupsDir} \
150 -recordings ${cfg.recordingsDir} \
151 -static ${cfg.staticDir}'';
153 # Upstream Requirements
155 StateDirectory = [ ] ++
156 optional (cfg.stateDir == defaultstateDir) "galene" ++
157 optional (cfg.dataDir == defaultdataDir) "galene/data" ++
158 optional (cfg.groupsDir == defaultgroupsDir) "galene/groups" ++
159 optional (cfg.recordingsDir == defaultrecordingsDir) "galene/recordings";
162 CapabilityBoundingSet = [ "" ];
163 DeviceAllow = [ "" ];
164 LockPersonality = true;
165 MemoryDenyWriteExecute = true;
166 NoNewPrivileges = true;
167 PrivateDevices = true;
172 ProtectControlGroups = true;
174 ProtectHostname = true;
175 ProtectKernelLogs = true;
176 ProtectKernelModules = true;
177 ProtectKernelTunables = true;
178 ProtectProc = "invisible";
179 ProtectSystem = "strict";
180 ReadWritePaths = cfg.recordingsDir;
182 RestrictAddressFamilies = [ "AF_INET" "AF_INET6" "AF_NETLINK" ];
183 RestrictNamespaces = true;
184 RestrictRealtime = true;
185 RestrictSUIDSGID = true;
186 SystemCallArchitectures = "native";
187 SystemCallFilter = [ "@system-service" "~@privileged" ];
193 users.users = mkIf (cfg.user == "galene")
196 description = "galene Service";
202 users.groups = mkIf (cfg.group == "galene") {
206 meta.maintainers = with lib.maintainers; [ rgrunbla ];