Merge pull request #63156 from Izorkin/phpfpm-rootless

phpfpm: do not run anything as root
This commit is contained in:
Elis Hirwing 2019-06-27 19:13:53 +02:00 committed by GitHub
commit b5478fd1a2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 231 additions and 242 deletions

View File

@ -241,6 +241,12 @@ with lib;
# binfmt # binfmt
(mkRenamedOptionModule [ "boot" "binfmtMiscRegistrations" ] [ "boot" "binfmt" "registrations" ]) (mkRenamedOptionModule [ "boot" "binfmtMiscRegistrations" ] [ "boot" "binfmt" "registrations" ])
# PHP-FPM
(mkRemovedOptionModule [ "services" "phpfpm" "poolConfigs" ] "Use services.phpfpm.pools instead.")
(mkRemovedOptionModule [ "services" "phpfpm" "phpPackage" ] "Use services.phpfpm.pools.<name>.phpPackage instead.")
(mkRemovedOptionModule [ "services" "phpfpm" "phpOptions" ] "Use services.phpfpm.pools.<name>.phpOptions instead.")
(mkRenamedOptionModule [ "services" "phpfpm" "extraConfig" ] [ "services" "phpfpm" "globalExtraConfig" ])
] ++ (flip map [ "blackboxExporter" "collectdExporter" "fritzboxExporter" ] ++ (flip map [ "blackboxExporter" "collectdExporter" "fritzboxExporter"
"jsonExporter" "minioExporter" "nginxExporter" "nodeExporter" "jsonExporter" "minioExporter" "nginxExporter" "nodeExporter"
"snmpExporter" "unifiExporter" "varnishExporter" ] "snmpExporter" "unifiExporter" "varnishExporter" ]

View File

@ -105,7 +105,7 @@ in
extraConfig = '' extraConfig = ''
location ~* \.php$ { location ~* \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/run/phpfpm/roundcube; fastcgi_pass unix:/run/phpfpm-roundcube/roundcube.sock;
include ${pkgs.nginx}/conf/fastcgi_params; include ${pkgs.nginx}/conf/fastcgi_params;
include ${pkgs.nginx}/conf/fastcgi.conf; include ${pkgs.nginx}/conf/fastcgi.conf;
} }
@ -119,24 +119,28 @@ in
enable = true; enable = true;
}; };
services.phpfpm.poolConfigs.roundcube = '' services.phpfpm.pools.roundcube = {
listen = /run/phpfpm/roundcube socketName = "roundcube";
listen.owner = nginx phpPackage = pkgs.php;
listen.group = nginx user = "${config.services.nginx.user}";
listen.mode = 0660 group = "${config.services.nginx.group}";
user = nginx extraConfig = ''
pm = dynamic listen.owner = ${config.services.nginx.user}
pm.max_children = 75 listen.group = ${config.services.nginx.group}
pm.start_servers = 2 listen.mode = 0600
pm.min_spare_servers = 1 pm = dynamic
pm.max_spare_servers = 20 pm.max_children = 75
pm.max_requests = 500 pm.start_servers = 2
php_admin_value[error_log] = 'stderr' pm.min_spare_servers = 1
php_admin_flag[log_errors] = on pm.max_spare_servers = 20
php_admin_value[post_max_size] = 25M pm.max_requests = 500
php_admin_value[upload_max_filesize] = 25M php_admin_value[error_log] = 'stderr'
catch_workers_output = yes php_admin_flag[log_errors] = on
''; php_admin_value[post_max_size] = 25M
php_admin_value[upload_max_filesize] = 25M
catch_workers_output = yes
'';
};
systemd.services.phpfpm-roundcube.after = [ "roundcube-setup.service" ]; systemd.services.phpfpm-roundcube.after = [ "roundcube-setup.service" ];
systemd.services.roundcube-setup = let systemd.services.roundcube-setup = let

View File

@ -19,7 +19,7 @@ let
useCustomDir = cfg.storageDir != null; useCustomDir = cfg.storageDir != null;
socket = "/run/phpfpm/${dirName}.sock"; socket = "/run/phpfpm-zoneminder/zoneminder.sock";
zms = "/cgi-bin/zms"; zms = "/cgi-bin/zms";
@ -284,7 +284,10 @@ in {
phpfpm = lib.mkIf useNginx { phpfpm = lib.mkIf useNginx {
pools.zoneminder = { pools.zoneminder = {
listen = socket; socketName = "zoneminder";
phpPackage = pkgs.php;
user = "${user}";
group = "${group}";
phpOptions = '' phpOptions = ''
date.timezone = "${config.time.timeZone}" date.timezone = "${config.time.timeZone}"
@ -292,9 +295,6 @@ in {
"extension=${e.pkg}/lib/php/extensions/${e.name}.so") phpExtensions)} "extension=${e.pkg}/lib/php/extensions/${e.name}.so") phpExtensions)}
''; '';
extraConfig = '' extraConfig = ''
user = ${user}
group = ${group}
listen.owner = ${user} listen.owner = ${user}
listen.group = ${group} listen.group = ${group}
listen.mode = 0660 listen.mode = 0660

View File

@ -1,7 +1,6 @@
{ config, lib, pkgs, ... }: with lib; let { config, lib, pkgs, ... }: with lib; let
cfg = config.services.icingaweb2; cfg = config.services.icingaweb2;
poolName = "icingaweb2"; poolName = "icingaweb2";
phpfpmSocketName = "/var/run/phpfpm/${poolName}.sock";
defaultConfig = { defaultConfig = {
global = { global = {
@ -162,19 +161,23 @@ in {
}; };
config = mkIf cfg.enable { config = mkIf cfg.enable {
services.phpfpm.poolConfigs = mkIf (cfg.pool == "${poolName}") { services.phpfpm.pools = mkIf (cfg.pool == "${poolName}") {
"${poolName}" = '' "${poolName}" = {
listen = "${phpfpmSocketName}" socketName = "${poolName}";
listen.owner = nginx phpPackage = pkgs.php;
listen.group = nginx user = "icingaweb2";
listen.mode = 0600 group = "icingaweb2";
user = icingaweb2 extraConfig = ''
pm = dynamic listen.owner = ${config.services.nginx.user}
pm.max_children = 75 listen.group = ${config.services.nginx.group}
pm.start_servers = 2 listen.mode = 0600
pm.min_spare_servers = 2 pm = dynamic
pm.max_spare_servers = 10 pm.max_children = 75
''; pm.start_servers = 2
pm.min_spare_servers = 2
pm.max_spare_servers = 10
'';
};
}; };
services.phpfpm.phpOptions = mkIf (cfg.pool == "${poolName}") services.phpfpm.phpOptions = mkIf (cfg.pool == "${poolName}")
@ -206,7 +209,7 @@ in {
include ${config.services.nginx.package}/conf/fastcgi.conf; include ${config.services.nginx.package}/conf/fastcgi.conf;
try_files $uri =404; try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:${phpfpmSocketName}; fastcgi_pass unix:/run/phpfpm-${poolName}/${poolName}.sock;
fastcgi_param SCRIPT_FILENAME ${pkgs.icingaweb2}/public/index.php; fastcgi_param SCRIPT_FILENAME ${pkgs.icingaweb2}/public/index.php;
''; '';
}; };
@ -239,5 +242,8 @@ in {
group = "icingaweb2"; group = "icingaweb2";
isSystemUser = true; isSystemUser = true;
}; };
users.users.nginx = {
extraGroups = [ "icingaweb2" ];
};
}; };
} }

View File

@ -202,13 +202,13 @@ in
}; };
services.phpfpm.pools.limesurvey = { services.phpfpm.pools.limesurvey = {
socketName = "limesurvey";
phpPackage = php; phpPackage = php;
listen = "/run/phpfpm/limesurvey.sock"; user = "${user}";
group = "${group}";
extraConfig = '' extraConfig = ''
listen.owner = ${config.services.httpd.user}; listen.owner = ${config.services.httpd.user};
listen.group = ${config.services.httpd.group}; listen.group = ${config.services.httpd.group};
user = ${user};
group = ${group};
env[LIMESURVEY_CONFIG] = ${limesurveyConfig} env[LIMESURVEY_CONFIG] = ${limesurveyConfig}
@ -241,7 +241,7 @@ in
<Directory "${pkg}/share/limesurvey"> <Directory "${pkg}/share/limesurvey">
<FilesMatch "\.php$"> <FilesMatch "\.php$">
<If "-f %{REQUEST_FILENAME}"> <If "-f %{REQUEST_FILENAME}">
SetHandler "proxy:unix:/run/phpfpm/limesurvey.sock|fcgi://localhost/" SetHandler "proxy:unix:/run/phpfpm-limesurvey/limesurvey.sock|fcgi://localhost/"
</If> </If>
</FilesMatch> </FilesMatch>

View File

@ -4,13 +4,14 @@ let
cfg = config.services.matomo; cfg = config.services.matomo;
user = "matomo"; user = "matomo";
group = "matomo";
dataDir = "/var/lib/${user}"; dataDir = "/var/lib/${user}";
deprecatedDataDir = "/var/lib/piwik"; deprecatedDataDir = "/var/lib/piwik";
pool = user; pool = user;
# it's not possible to use /run/phpfpm/${pool}.sock because /run/phpfpm/ is root:root 0770, # it's not possible to use /run/phpfpm-${pool}/${pool}.sock because /run/phpfpm/ is root:root 0770,
# and therefore is not accessible by the web server. # and therefore is not accessible by the web server.
phpSocket = "/run/phpfpm-${pool}.sock"; phpSocket = "/run/phpfpm-${pool}/${pool}.sock";
phpExecutionUnit = "phpfpm-${pool}"; phpExecutionUnit = "phpfpm-${pool}";
databaseService = "mysql.service"; databaseService = "mysql.service";
@ -137,9 +138,12 @@ in {
isSystemUser = true; isSystemUser = true;
createHome = true; createHome = true;
home = dataDir; home = dataDir;
group = user; group = "${group}";
}; };
users.groups.${user} = {}; users.users.${config.services.nginx.user} = {
extraGroups = [ "${group}" ];
};
users.groups.${group} = {};
systemd.services.matomo-setup-update = { systemd.services.matomo-setup-update = {
# everything needs to set up and up to date before Matomo php files are executed # everything needs to set up and up to date before Matomo php files are executed
@ -169,7 +173,7 @@ in {
echo "Migrating from ${deprecatedDataDir} to ${dataDir}" echo "Migrating from ${deprecatedDataDir} to ${dataDir}"
mv -T ${deprecatedDataDir} ${dataDir} mv -T ${deprecatedDataDir} ${dataDir}
fi fi
chown -R ${user}:${user} ${dataDir} chown -R ${user}:${group} ${dataDir}
chmod -R ug+rwX,o-rwx ${dataDir} chmod -R ug+rwX,o-rwx ${dataDir}
''; '';
script = '' script = ''
@ -225,22 +229,26 @@ in {
serviceConfig.UMask = "0007"; serviceConfig.UMask = "0007";
}; };
services.phpfpm.poolConfigs = let services.phpfpm.pools = let
# workaround for when both are null and need to generate a string, # workaround for when both are null and need to generate a string,
# which is illegal, but as assertions apparently are being triggered *after* config generation, # which is illegal, but as assertions apparently are being triggered *after* config generation,
# we have to avoid already throwing errors at this previous stage. # we have to avoid already throwing errors at this previous stage.
socketOwner = if (cfg.nginx != null) then config.services.nginx.user socketOwner = if (cfg.nginx != null) then config.services.nginx.user
else if (cfg.webServerUser != null) then cfg.webServerUser else ""; else if (cfg.webServerUser != null) then cfg.webServerUser else "";
in { in {
${pool} = '' ${pool} = {
listen = "${phpSocket}" socketName = "${pool}";
listen.owner = ${socketOwner} phpPackage = pkgs.php;
listen.group = root user = "${user}";
listen.mode = 0600 group = "${group}";
user = ${user} extraConfig = ''
env[PIWIK_USER_PATH] = ${dataDir} listen.owner = ${socketOwner}
${cfg.phpfpmProcessManagerConfig} listen.group = ${group}
''; listen.mode = 0600
env[PIWIK_USER_PATH] = ${dataDir}
${cfg.phpfpmProcessManagerConfig}
'';
};
}; };

View File

@ -394,13 +394,14 @@ in {
phpOptions))); phpOptions)));
in { in {
phpOptions = phpOptionsExtensions; phpOptions = phpOptionsExtensions;
socketName = "nextcloud";
phpPackage = phpPackage; phpPackage = phpPackage;
listen = "/run/phpfpm/nextcloud"; user = "nextcloud";
group = "${config.services.nginx.group}";
extraConfig = '' extraConfig = ''
listen.owner = nginx listen.owner = ${config.services.nginx.user}
listen.group = nginx listen.group = ${config.services.nginx.group}
user = nextcloud listen.mode = 0600
group = nginx
${cfg.poolConfig} ${cfg.poolConfig}
env[NEXTCLOUD_CONFIG_DIR] = ${cfg.home}/config env[NEXTCLOUD_CONFIG_DIR] = ${cfg.home}/config
env[PATH] = /run/wrappers/bin:/nix/var/nix/profiles/default/bin:/run/current-system/sw/bin:/usr/bin:/bin env[PATH] = /run/wrappers/bin:/nix/var/nix/profiles/default/bin:/run/current-system/sw/bin:/usr/bin:/bin
@ -466,7 +467,7 @@ in {
fastcgi_param HTTPS ${if cfg.https then "on" else "off"}; fastcgi_param HTTPS ${if cfg.https then "on" else "off"};
fastcgi_param modHeadersAvailable true; fastcgi_param modHeadersAvailable true;
fastcgi_param front_controller_active true; fastcgi_param front_controller_active true;
fastcgi_pass unix:/run/phpfpm/nextcloud; fastcgi_pass unix:/run/phpfpm-nextcloud/nextcloud.sock;
fastcgi_intercept_errors on; fastcgi_intercept_errors on;
fastcgi_request_buffering off; fastcgi_request_buffering off;
fastcgi_read_timeout 120s; fastcgi_read_timeout 120s;

View File

@ -13,7 +13,7 @@ let
runDir = "/run/restya-board"; runDir = "/run/restya-board";
poolName = "restya-board"; poolName = "restya-board";
phpfpmSocketName = "/run/phpfpm/${poolName}.sock"; phpfpmSocketName = "/run/phpfpm-${poolName}/${poolName}.sock";
in in
@ -178,9 +178,12 @@ in
config = mkIf cfg.enable { config = mkIf cfg.enable {
services.phpfpm.poolConfigs = { services.phpfpm.pools = {
"${poolName}" = { "${poolName}" = {
listen = phpfpmSocketName; socketName = "${poolName}";
phpPackage = pkgs.php;
user = "${cfg.user}";
group = "${cfg.group}";
phpOptions = '' phpOptions = ''
date.timezone = "CET" date.timezone = "CET"
@ -192,11 +195,9 @@ in
''} ''}
''; '';
extraConfig = '' extraConfig = ''
listen.owner = nginx listen.owner = ${config.services.nginx.user}
listen.group = nginx listen.group = ${config.services.nginx.group}
listen.mode = 0600 listen.mode = 0600
user = ${cfg.user}
group = ${cfg.group}
pm = dynamic pm = dynamic
pm.max_children = 75 pm.max_children = 75
pm.start_servers = 10 pm.start_servers = 10
@ -365,6 +366,9 @@ in
home = runDir; home = runDir;
group = "restya-board"; group = "restya-board";
}; };
users.users.nginx = {
extraGroups = [ "restya-board" ];
};
users.groups.restya-board = {}; users.groups.restya-board = {};
services.postgresql.enable = mkIf (cfg.database.host == null) true; services.postgresql.enable = mkIf (cfg.database.host == null) true;

View File

@ -3,9 +3,9 @@ with lib;
let let
cfg = config.services.selfoss; cfg = config.services.selfoss;
poolName = "selfoss_pool"; poolName = "selfoss";
phpfpmSocketName = "/run/phpfpm/${poolName}.sock"; phpfpmSocketName = "/run/phpfpm-${poolName}/${poolName}.sock";
group = "${cfg.user}";
dataDir = "/var/lib/selfoss"; dataDir = "/var/lib/selfoss";
selfoss-config = selfoss-config =
@ -116,21 +116,25 @@ in
config = mkIf cfg.enable { config = mkIf cfg.enable {
services.phpfpm.poolConfigs = mkIf (cfg.pool == "${poolName}") { services.phpfpm.pools = mkIf (cfg.pool == "${poolName}") {
"${poolName}" = '' "${poolName}" = {
listen = "${phpfpmSocketName}"; socketName = "${poolName}";
listen.owner = nginx phpPackage = pkgs.php;
listen.group = nginx user = "${cfg.user}";
listen.mode = 0600 group = "${group}";
user = nginx extraConfig = ''
pm = dynamic listen.owner = ${config.services.nginx.user}
pm.max_children = 75 listen.group = ${config.services.nginx.group}
pm.start_servers = 10 listen.mode = 0600
pm.min_spare_servers = 5 pm = dynamic
pm.max_spare_servers = 20 pm.max_children = 75
pm.max_requests = 500 pm.start_servers = 10
catch_workers_output = 1 pm.min_spare_servers = 5
''; pm.max_spare_servers = 20
pm.max_requests = 500
catch_workers_output = 1
'';
};
}; };
systemd.services.selfoss-config = { systemd.services.selfoss-config = {
@ -145,7 +149,7 @@ in
# Create the files # Create the files
cp -r "${pkgs.selfoss}/"* "${dataDir}" cp -r "${pkgs.selfoss}/"* "${dataDir}"
ln -sf "${selfoss-config}" "${dataDir}/config.ini" ln -sf "${selfoss-config}" "${dataDir}/config.ini"
chown -R "${cfg.user}" "${dataDir}" chown -R "${cfg.user}":"${group}" "${dataDir}"
chmod -R 755 "${dataDir}" chmod -R 755 "${dataDir}"
''; '';
wantedBy = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ];
@ -162,5 +166,8 @@ in
}; };
users.users.nginx = {
extraGroups = [ "${group}" ];
};
}; };
} }

View File

@ -512,12 +512,14 @@ let
services.phpfpm.pools = mkIf (cfg.pool == "${poolName}") { services.phpfpm.pools = mkIf (cfg.pool == "${poolName}") {
"${poolName}" = { "${poolName}" = {
listen = "/var/run/phpfpm/${poolName}.sock"; socketName = "${poolName}";
phpPackage = pkgs.php;
user = "${config.services.nginx.user}";
group = "${config.services.nginx.group}";
extraConfig = '' extraConfig = ''
listen.owner = nginx listen.owner = ${config.services.nginx.user}
listen.group = nginx listen.group = ${config.services.nginx.group}
listen.mode = 0600 listen.mode = 0600
user = ${cfg.user}
pm = dynamic pm = dynamic
pm.max_children = 75 pm.max_children = 75
pm.start_servers = 10 pm.start_servers = 10
@ -543,7 +545,7 @@ let
locations."~ \.php$" = { locations."~ \.php$" = {
extraConfig = '' extraConfig = ''
fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:${config.services.phpfpm.pools.${cfg.pool}.listen}; fastcgi_pass unix:/run/phpfpm-${poolName}/${poolName}.sock;
fastcgi_index index.php; fastcgi_index index.php;
''; '';
}; };

View File

@ -4,37 +4,26 @@ with lib;
let let
cfg = config.services.phpfpm; cfg = config.services.phpfpm;
enabled = cfg.poolConfigs != {} || cfg.pools != {}; enabled = cfg.pools != {};
stateDir = "/run/phpfpm"; poolConfigs = (mapAttrs mapPool cfg.pools);
poolConfigs =
(mapAttrs mapPoolConfig cfg.poolConfigs) //
(mapAttrs mapPool cfg.pools);
mapPoolConfig = n: p: {
phpPackage = cfg.phpPackage;
phpOptions = cfg.phpOptions;
config = p;
};
mapPool = n: p: { mapPool = n: p: {
phpPackage = p.phpPackage; phpPackage = p.phpPackage;
phpOptions = p.phpOptions; phpOptions = p.phpOptions;
config = '' userPool = p.user;
listen = ${p.listen} groupPool = p.group;
${p.extraConfig}
'';
}; };
fpmCfgFile = pool: conf: pkgs.writeText "phpfpm-${pool}.conf" '' fpmCfgFile = pool: conf: pkgs.writeText "phpfpm-${pool}.conf" ''
[global] [global]
error_log = syslog error_log = syslog
daemonize = no daemonize = no
${cfg.extraConfig} ${cfg.globalExtraConfig}
[${pool}] [${pool}]
${conf} listen = /run/phpfpm-${pool}/${cfg.pools.${pool}.socketName}.sock
${cfg.pools.${pool}.extraConfig}
''; '';
phpIni = pool: pkgs.runCommand "php.ini" { phpIni = pool: pkgs.runCommand "php.ini" {
@ -49,86 +38,99 @@ let
''; '';
in { in {
options = { options = {
services.phpfpm = { services.phpfpm = {
extraConfig = mkOption { globalExtraConfig = mkOption {
type = types.lines; type = types.lines;
default = ""; default = "";
description = '' description = ''
Extra configuration that should be put in the global section of Global extra configuration that should be put in the global section of
the PHP-FPM configuration file. Do not specify the options the PHP-FPM configuration file. Do not specify the options
<literal>error_log</literal> or <literal>error_log</literal> or
<literal>daemonize</literal> here, since they are generated by <literal>daemonize</literal> here, since they are generated by NixOS.
NixOS.
'';
};
phpPackage = mkOption {
type = types.package;
default = pkgs.php;
defaultText = "pkgs.php";
description = ''
The PHP package to use for running the PHP-FPM service.
'';
};
phpOptions = mkOption {
type = types.lines;
default = "";
example =
''
date.timezone = "CET"
'';
description =
"Options appended to the PHP configuration file <filename>php.ini</filename>.";
};
poolConfigs = mkOption {
default = {};
type = types.attrsOf types.lines;
example = literalExample ''
{ mypool = '''
listen = /run/phpfpm/mypool
user = nobody
pm = dynamic
pm.max_children = 75
pm.start_servers = 10
pm.min_spare_servers = 5
pm.max_spare_servers = 20
pm.max_requests = 500
''';
}
'';
description = ''
A mapping between PHP-FPM pool names and their configurations.
See the documentation on <literal>php-fpm.conf</literal> for
details on configuration directives. If no pools are defined,
the phpfpm service is disabled.
''; '';
}; };
pools = mkOption { pools = mkOption {
type = types.attrsOf (types.submodule (import ./pool-options.nix {
inherit lib config;
}));
default = {}; default = {};
type = types.attrsOf (types.submodule {
options = {
socketName = mkOption {
type = types.str;
example = "php-fpm";
description = ''
The address on which to accept FastCGI requests.
'';
};
phpPackage = mkOption {
type = types.package;
default = fpmCfg.phpPackage;
defaultText = "config.services.phpfpm.phpPackage";
description = ''
The PHP package to use for running this PHP-FPM pool.
'';
};
phpOptions = mkOption {
type = types.lines;
default = fpmCfg.phpOptions;
defaultText = "config.services.phpfpm.phpOptions";
description = ''
"Options appended to the PHP configuration file <filename>php.ini</filename> used for this PHP-FPM pool."
'';
};
user = mkOption {
type = types.string;
default = "phpfpm";
description = "User account under which phpfpm runs.";
};
group = mkOption {
type = types.string;
default = "phpfpm";
description = "Group account under which phpfpm runs.";
};
extraConfig = mkOption {
type = types.lines;
example = ''
pm = dynamic
pm.max_children = 75
pm.start_servers = 10
pm.min_spare_servers = 5
pm.max_spare_servers = 20
pm.max_requests = 500
'';
description = ''
Extra lines that go into the pool configuration.
See the documentation on <literal>php-fpm.conf</literal> for
details on configuration directives.
'';
};
};
});
example = literalExample '' example = literalExample ''
{ {
mypool = { mypool = {
listen = "/path/to/unix/socket"; socketName = "example";
phpPackage = pkgs.php; phpPackage = pkgs.php;
extraConfig = ''' user = "phpfpm";
user = nobody group = "phpfpm";
pm = dynamic extraConfig = '''
pm.max_children = 75 pm = dynamic
pm.start_servers = 10 pm.max_children = 75
pm.min_spare_servers = 5 pm.start_servers = 10
pm.max_spare_servers = 20 pm.min_spare_servers = 5
pm.max_requests = 500 pm.max_spare_servers = 20
'''; pm.max_requests = 500
} ''';
}''; }
}
'';
description = '' description = ''
PHP-FPM pools. If no pools or poolConfigs are defined, the PHP-FPM PHP-FPM pools. If no pools or poolConfigs are defined, the PHP-FPM
service is disabled. service is disabled.
@ -154,9 +156,6 @@ in {
after = [ "network.target" ]; after = [ "network.target" ];
wantedBy = [ "phpfpm.target" ]; wantedBy = [ "phpfpm.target" ];
partOf = [ "phpfpm.target" ]; partOf = [ "phpfpm.target" ];
preStart = ''
mkdir -p ${stateDir}
'';
serviceConfig = let serviceConfig = let
cfgFile = fpmCfgFile pool poolConfig.config; cfgFile = fpmCfgFile pool poolConfig.config;
iniFile = phpIni poolConfig; iniFile = phpIni poolConfig;
@ -166,10 +165,19 @@ in {
ProtectSystem = "full"; ProtectSystem = "full";
ProtectHome = true; ProtectHome = true;
# XXX: We need AF_NETLINK to make the sendmail SUID binary from postfix work # XXX: We need AF_NETLINK to make the sendmail SUID binary from postfix work
RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6 AF_NETLINK"; RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" "AF_NETLINK" ];
Type = "notify"; Type = "notify";
ExecStart = "${poolConfig.phpPackage}/bin/php-fpm -y ${cfgFile} -c ${iniFile}"; ExecStart = "${poolConfig.phpPackage}/bin/php-fpm -y '${cfgFile}' -c '${iniFile}'";
ExecReload = "${pkgs.coreutils}/bin/kill -USR2 $MAINPID"; ExecReload = "${pkgs.coreutils}/bin/kill -USR2 $MAINPID";
# User and group
User = "${poolConfig.userPool}";
Group = "${poolConfig.groupPool}";
# Runtime directory and mode
RuntimeDirectory = "phpfpm-${pool}";
RuntimeDirectoryMode = "0750";
# Capabilities
AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" "CAP_SETGID" "CAP_SETUID" "CAP_CHOWN" "CAP_SYS_RESOURCE" ];
CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" "CAP_SETGID" "CAP_SETUID" "CAP_CHOWN" "CAP_SYS_RESOURCE" ];
}; };
} }
); );

View File

@ -1,57 +0,0 @@
{ lib, config }:
let
fpmCfg = config.services.phpfpm;
in
with lib; {
options = {
listen = mkOption {
type = types.str;
example = "/path/to/unix/socket";
description = ''
The address on which to accept FastCGI requests.
'';
};
phpPackage = mkOption {
type = types.package;
default = fpmCfg.phpPackage;
defaultText = "config.services.phpfpm.phpPackage";
description = ''
The PHP package to use for running this PHP-FPM pool.
'';
};
phpOptions = mkOption {
type = types.lines;
default = fpmCfg.phpOptions;
defaultText = "config.services.phpfpm.phpOptions";
description = ''
"Options appended to the PHP configuration file <filename>php.ini</filename> used for this PHP-FPM pool."
'';
};
extraConfig = mkOption {
type = types.lines;
example = ''
user = nobody
pm = dynamic
pm.max_children = 75
pm.start_servers = 10
pm.min_spare_servers = 5
pm.max_spare_servers = 20
pm.max_requests = 500
'';
description = ''
Extra lines that go into the pool configuration.
See the documentation on <literal>php-fpm.conf</literal> for
details on configuration directives.
'';
};
};
}