···
cfg = config.services.uwsgi;
8
+
isEmperor = cfg.instance.type == "emperor";
12
+
# spawn other user processes
13
+
"CAP_SETUID" "CAP_SETGID"
15
+
# transfer capabilities
17
+
# create other user sockets
if any (n: !any (m: m == n) cfg.plugins) (c.plugins or [])
12
-
then throw "`plugins` attribute in UWSGI configuration contains plugins not in config.services.uwsgi.plugins"
25
+
then throw "`plugins` attribute in uWSGI configuration contains plugins not in config.services.uwsgi.plugins"
else c.plugins or cfg.plugins;
hasPython = v: filter (n: n == "python${v}") plugins != [];
···
if hasPython2 && hasPython3 then
21
-
throw "`plugins` attribute in UWSGI configuration shouldn't contain both python2 and python3"
34
+
throw "`plugins` attribute in uWSGI configuration shouldn't contain both python2 and python3"
else if hasPython2 then cfg.package.python2
else if hasPython3 then cfg.package.python3
···
oldPaths = filter (x: x != null) (map getPath env');
in env' ++ [ "PATH=${optionalString (oldPaths != []) "${last oldPaths}:"}${pythonEnv}/bin" ];
46
-
else if c.type == "emperor"
emperor = if builtins.typeOf c.vassals != "set" then c.vassals
···
paths = mapAttrsToList buildCfg c.vassals;
} // removeAttrs c [ "type" "vassals" ]
54
-
else throw "`type` attribute in UWSGI configuration should be either 'normal' or 'emperor'";
67
+
else throw "`type` attribute in uWSGI configuration should be either 'normal' or 'emperor'";
in pkgs.writeTextDir "${name}.json" (builtins.toJSON uwsgiCfg);
···
82
-
type = with lib.types; let
95
+
type = with types; let
valueType = nullOr (oneOf [
···
140
-
description = "User account under which uwsgi runs.";
153
+
description = "User account under which uWSGI runs.";
146
-
description = "Group account under which uwsgi runs.";
159
+
description = "Group account under which uWSGI runs.";
162
+
capabilities = mkOption {
163
+
type = types.listOf types.str;
164
+
apply = caps: caps ++ optionals isEmperor imperialPowers;
166
+
example = literalExample ''
168
+
"CAP_NET_BIND_SERVICE" # bind on ports <1024
169
+
"CAP_NET_RAW" # open raw sockets
173
+
Grant capabilities to the uWSGI instance. See the
174
+
<literal>capabilities(7)</literal> for available values.
177
+
uWSGI runs as an unprivileged user (even as Emperor) with the minimal
178
+
capabilities required. This option can be used to add fine-grained
179
+
permissions without running the service as root.
182
+
When in Emperor mode, any capability to be inherited by a vassal must
183
+
be specified again in the vassal configuration using <literal>cap</literal>.
184
+
See the uWSGI <link
185
+
xlink:href="https://uwsgi-docs.readthedocs.io/en/latest/Capabilities.html">docs</link>
186
+
for more information.
config = mkIf cfg.enable {
195
+
systemd.tmpfiles.rules = optional (cfg.runDir != "/run/uwsgi") ''
196
+
d ${cfg.runDir} 775 ${cfg.user} ${cfg.group}
systemd.services.uwsgi = {
wantedBy = [ "multi-user.target" ];
155
-
mkdir -p ${cfg.runDir}
156
-
chown ${cfg.user}:${cfg.group} ${cfg.runDir}
160
-
ExecStart = "${cfg.package}/bin/uwsgi --uid ${cfg.user} --gid ${cfg.group} --json ${buildCfg "server" cfg.instance}/server.json";
205
+
ExecStart = "${cfg.package}/bin/uwsgi --json ${buildCfg "server" cfg.instance}/server.json";
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
ExecStop = "${pkgs.coreutils}/bin/kill -INT $MAINPID";
210
+
AmbientCapabilities = cfg.capabilities;
211
+
CapabilityBoundingSet = cfg.capabilities;