diff --git a/nixos/doc/manual/release-notes/rl-1903.xml b/nixos/doc/manual/release-notes/rl-1903.xml
index a1f715a3adf16..6c0cc8f3dab7e 100644
--- a/nixos/doc/manual/release-notes/rl-1903.xml
+++ b/nixos/doc/manual/release-notes/rl-1903.xml
@@ -220,6 +220,18 @@
reset to the default value (false).
+
+
+ The services.fcgiwrap module has been converted to use
+ socket activation with systemd. You can now
+ configure the owner, group and mode of a unix socket. The service
+ won't be started as root anymore by default and the option
+ services.fcgiwrap.socketType was removed because
+ services.fcgiwrap.socketAddress now takes
+ addresses as defined in
+ systemd.socket5.
+
+
diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix
index dc0a175d5bb8e..8a05d94b538d2 100644
--- a/nixos/modules/rename.nix
+++ b/nixos/modules/rename.nix
@@ -262,6 +262,7 @@ with lib;
(mkRemovedOptionModule [ "virtualisation" "xen" "qemu" ] "You don't need this option anymore, it will work without it.")
(mkRemovedOptionModule [ "services" "logstash" "enableWeb" ] "The web interface was removed from logstash")
(mkRemovedOptionModule [ "boot" "zfs" "enableLegacyCrypto" ] "The corresponding package was removed from nixpkgs.")
+ (mkRemovedOptionModule [ "services" "fcgiwrap" "socketType" ] "Use services.fcgiwrap.socketAddress to specify the socket type instead.")
# ZSH
(mkRenamedOptionModule [ "programs" "zsh" "enableSyntaxHighlighting" ] [ "programs" "zsh" "syntaxHighlighting" "enable" ])
diff --git a/nixos/modules/services/web-servers/fcgiwrap.nix b/nixos/modules/services/web-servers/fcgiwrap.nix
index a64a187255a48..1b451d86489ac 100644
--- a/nixos/modules/services/web-servers/fcgiwrap.nix
+++ b/nixos/modules/services/web-servers/fcgiwrap.nix
@@ -20,28 +20,44 @@ in {
description = "Number of processes to prefork.";
};
- socketType = mkOption {
- type = types.enum [ "unix" "tcp" "tcp6" ];
- default = "unix";
- description = "Socket type: 'unix', 'tcp' or 'tcp6'.";
- };
-
socketAddress = mkOption {
type = types.str;
default = "/run/fcgiwrap.sock";
example = "1.2.3.4:5678";
- description = "Socket address. In case of a UNIX socket, this should be its filesystem path.";
+ description = ''
+ Socket address as defined in
+ systemd.socket5
+ for ListemStream.
+ '';
+ };
+
+ socketUser = mkOption {
+ type = types.str;
+ default = "root";
+ description = "Owner of the socket if it is defined as a Unix socket.";
+ };
+
+ socketGroup = mkOption {
+ type = types.str;
+ default = "root";
+ description = "Group of the socket if it is defined as a Unix socket.";
+ };
+
+ socketMode = mkOption {
+ type = types.str;
+ default = "0660";
+ description = "File mode of the socket if it is defined as a Unix socket.";
};
user = mkOption {
- type = types.nullOr types.str;
- default = null;
+ type = types.str;
+ default = "nobody";
description = "User permissions for the socket.";
};
group = mkOption {
- type = types.nullOr types.str;
- default = null;
+ type = types.str;
+ default = "nogroup";
description = "Group permissions for the socket.";
};
};
@@ -50,23 +66,21 @@ in {
config = mkIf cfg.enable {
systemd.services.fcgiwrap = {
after = [ "nss-user-lookup.target" ];
- wantedBy = optional (cfg.socketType != "unix") "multi-user.target";
-
serviceConfig = {
- ExecStart = "${pkgs.fcgiwrap}/sbin/fcgiwrap -c ${builtins.toString cfg.preforkProcesses} ${
- if (cfg.socketType != "unix") then "-s ${cfg.socketType}:${cfg.socketAddress}" else ""
- }";
- } // (if cfg.user != null && cfg.group != null then {
+ ExecStart = "${pkgs.fcgiwrap}/sbin/fcgiwrap -c ${toString cfg.preforkProcesses}";
User = cfg.user;
Group = cfg.group;
- } else { } );
+ };
};
- systemd.sockets = if (cfg.socketType == "unix") then {
- fcgiwrap = {
- wantedBy = [ "sockets.target" ];
- socketConfig.ListenStream = cfg.socketAddress;
+ systemd.sockets.fcgiwrap = {
+ wantedBy = [ "sockets.target" ];
+ socketConfig = {
+ ListenStream = cfg.socketAddress;
+ SocketUser = cfg.socketUser;
+ SocketGroup = cfg.socketGroup;
+ SocketMode = cfg.socketMode;
};
- } else { };
+ };
};
}
diff --git a/nixos/modules/system/activation/switch-to-configuration.pl b/nixos/modules/system/activation/switch-to-configuration.pl
index 397b308b73118..0b4a05ebd9901 100644
--- a/nixos/modules/system/activation/switch-to-configuration.pl
+++ b/nixos/modules/system/activation/switch-to-configuration.pl
@@ -229,7 +229,17 @@ sub fingerprintUnit {
# Reload the changed mount unit to force a remount.
$unitsToReload{$unit} = 1;
recordUnit($reloadListFile, $unit);
- } elsif ($unit =~ /\.socket$/ || $unit =~ /\.path$/ || $unit =~ /\.slice$/) {
+ } elsif ($unit =~ /\.socket$/) {
+ my $unitInfo = parseUnit($newUnitFile);
+ # If a socket unit has been changed, the corresponding
+ # service unit has to be stopped before the socket can
+ # be restarted.
+ my $serviceUnit = $unitInfo->{'Unit'} // "$baseName.service";
+ $unitsToStop{$serviceUnit} = 1;
+ $unitsToStop{$unit} = 1;
+ $unitsToStart{$unit} = 1;
+ recordUnit($startListFile, $unit);
+ } elsif ($unit =~ /\.path$/ || $unit =~ /\.slice$/) {
# FIXME: do something?
} else {
my $unitInfo = parseUnit($newUnitFile);
diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix
index 754a8ff20b262..4d16d2fd73481 100644
--- a/nixos/tests/all-tests.nix
+++ b/nixos/tests/all-tests.nix
@@ -69,6 +69,7 @@ in
elk = handleTestOn ["x86_64-linux"] ./elk.nix {};
env = handleTest ./env.nix {};
etcd = handleTestOn ["x86_64-linux"] ./etcd.nix {};
+ fcgiwrap = handleTest ./fcgiwrap.nix {};
ferm = handleTest ./ferm.nix {};
firefox = handleTest ./firefox.nix {};
firewall = handleTest ./firewall.nix {};
diff --git a/nixos/tests/fcgiwrap.nix b/nixos/tests/fcgiwrap.nix
new file mode 100644
index 0000000000000..936086bd731a4
--- /dev/null
+++ b/nixos/tests/fcgiwrap.nix
@@ -0,0 +1,54 @@
+import ./make-test.nix ({ pkgs, lib, ... }:
+
+let
+ helloScript = pkgs.writeShellScriptBin "hello" ''
+ echo "Status: 200 OK"
+ echo
+ echo "$out says: Hello World!"
+ '';
+
+ mkServer = extraConfig: { ... }:
+ lib.mkMerge [
+ { services.fcgiwrap.enable = true;
+ services.nginx.enable = true;
+ services.nginx.commonHttpConfig = ''
+ error_log syslog:server=unix:/dev/log;
+ access_log syslog:server=unix:/dev/log;
+ '';
+ services.nginx.virtualHosts."_".locations."/".extraConfig = ''
+ fastcgi_param SCRIPT_FILENAME ${helloScript}/bin/hello;
+ fastcgi_pass unix:/run/fcgiwrap.sock;
+ '';
+ }
+ extraConfig
+ ];
+
+in
+
+{ name = "fcgiwrap";
+ meta = with pkgs.stdenv.lib.maintainers;
+ { maintainers = [ fpletz ]; };
+
+ nodes = {
+ working = mkServer {
+ services.fcgiwrap.socketGroup = "nginx";
+ };
+
+ permissionfail = mkServer {
+ services.fcgiwrap.socketGroup = "root";
+ };
+ };
+
+ testScript = { nodes, ... }: let
+ permissionfail = nodes.permissionfail.config.system.build.toplevel;
+ in ''
+ $working->start;
+
+ $working->waitForUnit("nginx");
+ $working->waitForOpenPort("80");
+ $working->succeed("curl http://localhost/ | tee /dev/stderr | grep 'Hello World!'");
+
+ $working->succeed("${permissionfail}/bin/switch-to-configuration test");
+ $working->fail("curl -f http://localhost/");
+ '';
+})
diff --git a/pkgs/servers/fcgiwrap/default.nix b/pkgs/servers/fcgiwrap/default.nix
index a1ec3a7deb085..1470944c862fe 100644
--- a/pkgs/servers/fcgiwrap/default.nix
+++ b/pkgs/servers/fcgiwrap/default.nix
@@ -1,4 +1,4 @@
-{ stdenv, fetchurl, systemd, fcgi, autoreconfHook, pkgconfig }:
+{ stdenv, fetchurl, fetchpatch, systemd, fcgi, autoreconfHook, pkgconfig }:
stdenv.mkDerivation rec {
name = "fcgiwrap-${version}";
@@ -9,6 +9,15 @@ stdenv.mkDerivation rec {
sha256 = "07y6s4mm86cv7p1ljz94sxnqa89y9amn3vzwsnbq5hrl4vdy0zac";
};
+ patches = [
+ # Support for custom working dir with the FCGI_CHDIR environment variable.
+ # https://github.com/gnosek/fcgiwrap/pull/21
+ (fetchpatch {
+ url = "https://github.com/gnosek/fcgiwrap/commit/caf1f5c7b3e9cf5b777139c0419d47fa933ff510.patch";
+ sha256 = "0npdicjvkhpjvd39parrc3wjwd0871d3vz34nwr7p2mk6x9q5dwi";
+ })
+ ];
+
NIX_CFLAGS_COMPILE = "-Wno-error=implicit-fallthrough";
configureFlags = [ "--with-systemd" "--with-systemdsystemunitdir=$(out)/etc/systemd/system" ];