at 25.11-pre 9.5 kB view raw
1{ 2 config, 3 lib, 4 pkgs, 5 ... 6}: 7 8with lib; 9 10let 11 cfg = config.services.phpfpm; 12 13 runtimeDir = "/run/phpfpm"; 14 15 toStr = 16 value: 17 if true == value then 18 "yes" 19 else if false == value then 20 "no" 21 else 22 toString value; 23 24 fpmCfgFile = 25 pool: poolOpts: 26 pkgs.writeText "phpfpm-${pool}.conf" '' 27 [global] 28 ${concatStringsSep "\n" (mapAttrsToList (n: v: "${n} = ${toStr v}") cfg.settings)} 29 ${optionalString (cfg.extraConfig != null) cfg.extraConfig} 30 31 [${pool}] 32 ${concatStringsSep "\n" (mapAttrsToList (n: v: "${n} = ${toStr v}") poolOpts.settings)} 33 ${concatStringsSep "\n" (mapAttrsToList (n: v: "env[${n}] = ${toStr v}") poolOpts.phpEnv)} 34 ${optionalString (poolOpts.extraConfig != null) poolOpts.extraConfig} 35 ''; 36 37 phpIni = 38 poolOpts: 39 pkgs.runCommand "php.ini" 40 { 41 inherit (poolOpts) phpPackage phpOptions; 42 preferLocalBuild = true; 43 passAsFile = [ "phpOptions" ]; 44 } 45 '' 46 cat ${poolOpts.phpPackage}/etc/php.ini $phpOptionsPath > $out 47 ''; 48 49 poolOpts = 50 { name, ... }: 51 let 52 poolOpts = cfg.pools.${name}; 53 in 54 { 55 options = { 56 socket = mkOption { 57 type = types.str; 58 readOnly = true; 59 description = '' 60 Path to the unix socket file on which to accept FastCGI requests. 61 62 ::: {.note} 63 This option is read-only and managed by NixOS. 64 ::: 65 ''; 66 example = "${runtimeDir}/<name>.sock"; 67 }; 68 69 listen = mkOption { 70 type = types.str; 71 default = ""; 72 example = "/path/to/unix/socket"; 73 description = '' 74 The address on which to accept FastCGI requests. 75 ''; 76 }; 77 78 phpPackage = mkOption { 79 type = types.package; 80 default = cfg.phpPackage; 81 defaultText = literalExpression "config.services.phpfpm.phpPackage"; 82 description = '' 83 The PHP package to use for running this PHP-FPM pool. 84 ''; 85 }; 86 87 phpOptions = mkOption { 88 type = types.lines; 89 description = '' 90 "Options appended to the PHP configuration file {file}`php.ini` used for this PHP-FPM pool." 91 ''; 92 }; 93 94 phpEnv = lib.mkOption { 95 type = with types; attrsOf str; 96 default = { }; 97 description = '' 98 Environment variables used for this PHP-FPM pool. 99 ''; 100 example = literalExpression '' 101 { 102 HOSTNAME = "$HOSTNAME"; 103 TMP = "/tmp"; 104 TMPDIR = "/tmp"; 105 TEMP = "/tmp"; 106 } 107 ''; 108 }; 109 110 user = mkOption { 111 type = types.str; 112 description = "User account under which this pool runs."; 113 }; 114 115 group = mkOption { 116 type = types.str; 117 description = "Group account under which this pool runs."; 118 }; 119 120 settings = mkOption { 121 type = 122 with types; 123 attrsOf (oneOf [ 124 str 125 int 126 bool 127 ]); 128 default = { }; 129 description = '' 130 PHP-FPM pool directives. Refer to the "List of pool directives" section of 131 <https://www.php.net/manual/en/install.fpm.configuration.php> 132 for details. Note that settings names must be enclosed in quotes (e.g. 133 `"pm.max_children"` instead of `pm.max_children`). 134 ''; 135 example = literalExpression '' 136 { 137 "pm" = "dynamic"; 138 "pm.max_children" = 75; 139 "pm.start_servers" = 10; 140 "pm.min_spare_servers" = 5; 141 "pm.max_spare_servers" = 20; 142 "pm.max_requests" = 500; 143 } 144 ''; 145 }; 146 147 extraConfig = mkOption { 148 type = with types; nullOr lines; 149 default = null; 150 description = '' 151 Extra lines that go into the pool configuration. 152 See the documentation on `php-fpm.conf` for 153 details on configuration directives. 154 ''; 155 }; 156 }; 157 158 config = { 159 socket = if poolOpts.listen == "" then "${runtimeDir}/${name}.sock" else poolOpts.listen; 160 group = mkDefault poolOpts.user; 161 phpOptions = mkBefore cfg.phpOptions; 162 163 settings = mapAttrs (name: mkDefault) { 164 listen = poolOpts.socket; 165 user = poolOpts.user; 166 group = poolOpts.group; 167 }; 168 }; 169 }; 170 171in 172{ 173 imports = [ 174 (mkRemovedOptionModule [ "services" "phpfpm" "poolConfigs" ] "Use services.phpfpm.pools instead.") 175 (mkRemovedOptionModule [ "services" "phpfpm" "phpIni" ] "") 176 ]; 177 178 options = { 179 services.phpfpm = { 180 settings = mkOption { 181 type = 182 with types; 183 attrsOf (oneOf [ 184 str 185 int 186 bool 187 ]); 188 default = { }; 189 description = '' 190 PHP-FPM global directives. Refer to the "List of global php-fpm.conf directives" section of 191 <https://www.php.net/manual/en/install.fpm.configuration.php> 192 for details. Note that settings names must be enclosed in quotes (e.g. 193 `"pm.max_children"` instead of `pm.max_children`). 194 You need not specify the options `error_log` or 195 `daemonize` here, since they are generated by NixOS. 196 ''; 197 }; 198 199 extraConfig = mkOption { 200 type = with types; nullOr lines; 201 default = null; 202 description = '' 203 Extra configuration that should be put in the global section of 204 the PHP-FPM configuration file. Do not specify the options 205 `error_log` or 206 `daemonize` here, since they are generated by 207 NixOS. 208 ''; 209 }; 210 211 phpPackage = mkPackageOption pkgs "php" { }; 212 213 phpOptions = mkOption { 214 type = types.lines; 215 default = ""; 216 example = '' 217 date.timezone = "CET" 218 ''; 219 description = '' 220 Options appended to the PHP configuration file {file}`php.ini`. 221 ''; 222 }; 223 224 pools = mkOption { 225 type = types.attrsOf (types.submodule poolOpts); 226 default = { }; 227 example = literalExpression '' 228 { 229 mypool = { 230 user = "php"; 231 group = "php"; 232 phpPackage = pkgs.php; 233 settings = { 234 "pm" = "dynamic"; 235 "pm.max_children" = 75; 236 "pm.start_servers" = 10; 237 "pm.min_spare_servers" = 5; 238 "pm.max_spare_servers" = 20; 239 "pm.max_requests" = 500; 240 }; 241 } 242 }''; 243 description = '' 244 PHP-FPM pools. If no pools are defined, the PHP-FPM 245 service is disabled. 246 ''; 247 }; 248 }; 249 }; 250 251 config = mkIf (cfg.pools != { }) { 252 253 warnings = 254 mapAttrsToList (pool: poolOpts: '' 255 Using config.services.phpfpm.pools.${pool}.listen is deprecated and will become unsupported in a future release. Please reference the read-only option config.services.phpfpm.pools.${pool}.socket to access the path of your socket. 256 '') (filterAttrs (pool: poolOpts: poolOpts.listen != "") cfg.pools) 257 ++ mapAttrsToList (pool: poolOpts: '' 258 Using config.services.phpfpm.pools.${pool}.extraConfig is deprecated and will become unsupported in a future release. Please migrate your configuration to config.services.phpfpm.pools.${pool}.settings. 259 '') (filterAttrs (pool: poolOpts: poolOpts.extraConfig != null) cfg.pools) 260 ++ optional (cfg.extraConfig != null) '' 261 Using config.services.phpfpm.extraConfig is deprecated and will become unsupported in a future release. Please migrate your configuration to config.services.phpfpm.settings. 262 ''; 263 264 services.phpfpm.settings = { 265 error_log = "syslog"; 266 daemonize = false; 267 }; 268 269 systemd.slices.system-phpfpm = { 270 description = "PHP FastCGI Process Manager Slice"; 271 }; 272 273 systemd.targets.phpfpm = { 274 description = "PHP FastCGI Process manager pools target"; 275 wantedBy = [ "multi-user.target" ]; 276 }; 277 278 systemd.services = mapAttrs' ( 279 pool: poolOpts: 280 nameValuePair "phpfpm-${pool}" { 281 description = "PHP FastCGI Process Manager service for pool ${pool}"; 282 after = [ "network.target" ]; 283 wantedBy = [ "phpfpm.target" ]; 284 partOf = [ "phpfpm.target" ]; 285 documentation = [ "man:php-fpm(8)" ]; 286 serviceConfig = 287 let 288 cfgFile = fpmCfgFile pool poolOpts; 289 iniFile = phpIni poolOpts; 290 in 291 { 292 Slice = "system-phpfpm.slice"; 293 PrivateDevices = true; 294 PrivateTmp = true; 295 ProtectSystem = "full"; 296 ProtectHome = true; 297 # XXX: We need AF_NETLINK to make the sendmail SUID binary from postfix work 298 RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6 AF_NETLINK"; 299 Type = "notify"; 300 ExecStart = "${poolOpts.phpPackage}/bin/php-fpm -y ${cfgFile} -c ${iniFile}"; 301 ExecReload = "${pkgs.coreutils}/bin/kill -USR2 $MAINPID"; 302 RuntimeDirectory = "phpfpm"; 303 RuntimeDirectoryPreserve = true; # Relevant when multiple processes are running 304 Restart = "always"; 305 }; 306 } 307 ) cfg.pools; 308 }; 309}