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