+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+ cfg = config.services.myPhpfpm;
+ enabled = cfg.poolConfigs != {} || cfg.pools != {};
+
+ stateDir = "/run/phpfpm";
+
+ poolConfigs = cfg.poolConfigs // mapAttrs mkPool cfg.pools;
+
+ mkPool = n: p: ''
+ listen = ${p.listen}
+ ${p.extraConfig}
+ '';
+
+ fpmCfgFile = pool: poolConfig: pkgs.writeText "phpfpm-${pool}.conf" ''
+ [global]
+ error_log = syslog
+ daemonize = no
+ ${cfg.extraConfig}
+
+ [${pool}]
+ ${poolConfig}
+ '';
+
+ phpIni = poolPhpOptions: (pkgs.runCommand "php.ini" {
+ inherit (cfg) phpPackage phpOptions;
+ inherit poolPhpOptions;
+ nixDefaults = ''
+ sendmail_path = "/run/wrappers/bin/sendmail -t -i"
+ '';
+ passAsFile = [ "nixDefaults" "phpOptions" "poolPhpOptions" ];
+ } ''
+ cat $phpPackage/etc/php.ini $nixDefaultsPath $phpOptionsPath $poolPhpOptionsPath > $out
+ '');
+
+in {
+
+ options = {
+ services.myPhpfpm = {
+ extraConfig = mkOption {
+ type = types.lines;
+ default = "";
+ description = ''
+ Extra configuration that should be put in the global section of
+ the PHP-FPM configuration file. Do not specify the options
+ <literal>error_log</literal> or
+ <literal>daemonize</literal> here, since they are generated by
+ 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>.";
+ };
+
+ poolPhpConfigs = mkOption {
+ default = {};
+ type = types.attrsOf types.lines;
+ example = literalExample ''
+ { mypool = '''
+ extension = some_extension.so
+ ''';
+ }
+ '';
+ description = ''
+ Extra lines that go into the php configuration specific to pool.
+ '';
+ };
+
+ 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 {
+ type = types.attrsOf (types.submodule (import ./pool-options.nix {
+ inherit lib;
+ }));
+ default = {};
+ example = literalExample ''
+ {
+ mypool = {
+ listen = "/path/to/unix/socket";
+ extraConfig = '''
+ 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 = ''
+ PHP-FPM pools. If no pools or poolConfigs are defined, the PHP-FPM
+ service is disabled.
+ '';
+ };
+ };
+ };
+
+ config = mkIf enabled {
+
+ systemd.slices.phpfpm = {
+ description = "PHP FastCGI Process manager pools slice";
+ };
+
+ systemd.targets.phpfpm = {
+ description = "PHP FastCGI Process manager pools target";
+ wantedBy = [ "multi-user.target" ];
+ };
+
+ systemd.services = flip mapAttrs' poolConfigs (pool: poolConfig:
+ nameValuePair "phpfpm-${pool}" {
+ description = "PHP FastCGI Process Manager service for pool ${pool}";
+ after = [ "network.target" ];
+ wantedBy = [ "phpfpm.target" ];
+ partOf = [ "phpfpm.target" ];
+ preStart = ''
+ mkdir -p ${stateDir}
+ '';
+ serviceConfig = let
+ cfgFile = fpmCfgFile pool poolConfig;
+ poolPhpIni = cfg.poolPhpConfigs.${pool} or "";
+ in {
+ Slice = "phpfpm.slice";
+ PrivateDevices = true;
+ ProtectSystem = "full";
+ ProtectHome = true;
+ # XXX: We need AF_NETLINK to make the sendmail SUID binary from postfix work
+ RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6 AF_NETLINK";
+ Type = "notify";
+ ExecStart = "${cfg.phpPackage}/bin/php-fpm -y ${cfgFile} -c ${phpIni poolPhpIni}";
+ ExecReload = "${pkgs.coreutils}/bin/kill -USR2 $MAINPID";
+ };
+ }
+ );
+ };
+}