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" ];