]> git.immae.eu Git - perso/Immae/Config/Nix.git/commitdiff
Refactor a bit the php-fpm module
authorIsmaël Bouya <ismael.bouya@normalesup.org>
Sat, 12 Jan 2019 00:15:55 +0000 (01:15 +0100)
committerIsmaël Bouya <ismael.bouya@normalesup.org>
Sat, 12 Jan 2019 00:15:55 +0000 (01:15 +0100)
This commit adds a new phpfpm service with a new option that permits to
specify pool-specific php configuration (caveat: now each pool has
distinct php ini file, even if they have the same content)

Make sure that the same php package is used everywhere

Build pdo_mysql using mysql c-connector. Would be good to have the same
with mysqli but it seems not to work

virtual/eldiron.nix
virtual/modules/websites/aten/default.nix
virtual/modules/websites/chloe/default.nix
virtual/modules/websites/connexionswing/default.nix
virtual/modules/websites/default.nix
virtual/modules/websites/ludivine/default.nix
virtual/modules/websites/phpfpm/default.nix [new file with mode: 0644]
virtual/modules/websites/phpfpm/pool-options.nix [new file with mode: 0644]
virtual/modules/websites/piedsjaloux/default.nix
virtual/packages/nextcloud.nix

index 2e4ae1272cfb46265b5b09d7d1ff1635e9f4cee5..c9075cfcd89bdbadf7e583937dcd82a3b7249161 100644 (file)
@@ -32,6 +32,7 @@
       ./modules/gitweb.nix
       ./modules/databases.nix
       ./modules/websites
+      ./modules/websites/phpfpm
     ];
     services.myGitolite.enable = true;
     services.myGitweb.enable = true;
@@ -73,8 +74,8 @@
         cd ${mypkgs.nextcloud.webRoot}
         NEXTCLOUD_CONFIG_DIR="${mypkgs.nextcloud.webRoot}/config" \
           exec \
-          ${config.services.phpfpm.phpPackage}/bin/php \
-          -c ${config.services.phpfpm.phpPackage}/etc/php.ini \
+          ${pkgs.php}/bin/php \
+          -c ${pkgs.php}/etc/php.ini \
           occ $*
         '';
     in [
 
     services.ympd = mypkgs.ympd.config // { enable = false; };
 
-    services.phpfpm = {
-      # FIXME: move session files to separate dirs
-      # /!\ phppackage is used in nextcloud configuation
+    services.myPhpfpm = {
+      phpPackage = pkgs.php;
       phpOptions = ''
         session.save_path = "/var/lib/php/sessions"
         session.gc_maxlifetime = 60*60*24*15
         session.cache_expire = 60*24*30
-        ; For nextcloud
-        extension=${pkgs.phpPackages.redis}/lib/php/extensions/redis.so
-        ; For nextcloud
-        extension=${pkgs.phpPackages.apcu}/lib/php/extensions/apcu.so
-        ; For nextcloud
-        zend_extension=${pkgs.php}/lib/php/extensions/opcache.so
         '';
       extraConfig = ''
         log_level = notice
         '';
+      poolPhpConfigs = {
+        nextcloud = mypkgs.nextcloud.phpFpm.phpConfig;
+      };
       poolConfigs = {
         adminer = mypkgs.adminer.phpFpm.pool;
         nextcloud = mypkgs.nextcloud.phpFpm.pool;
index d9db75cbdfe60668943015399945151c7500899f..2f319bb57a98431a0b6fcc7a0f5bebcbd1880353 100644 (file)
@@ -36,7 +36,7 @@ in {
         };
       };
 
-      services.phpfpm.poolConfigs.aten_prod = aten_prod.phpFpm.pool;
+      services.myPhpfpm.poolConfigs.aten_prod = aten_prod.phpFpm.pool;
       system.activationScripts.aten_prod = aten_prod.activationScript;
       services.myWebsites.apacheConfig.aten_prod.modules = aten_prod.apache.modules;
       services.myWebsites.production.modules = aten_prod.apache.modules;
@@ -49,7 +49,7 @@ in {
     })
     (lib.mkIf cfg.integration.enable {
       security.acme.certs."eldiron".extraDomains."dev.aten.pro" = null;
-      services.phpfpm.poolConfigs.aten_dev = aten_dev.phpFpm.pool;
+      services.myPhpfpm.poolConfigs.aten_dev = aten_dev.phpFpm.pool;
       system.activationScripts.aten_dev = aten_dev.activationScript;
       services.myWebsites.integration.modules = aten_dev.apache.modules;
       services.myWebsites.integration.vhostConfs.aten = {
index 72a9b6fdb01667a395f30352096726e10b2e9240..e5c3db7f86f86fc7b4b62317f777e1c51e7ed673 100644 (file)
@@ -36,7 +36,7 @@ in {
         };
       };
 
-      services.phpfpm.poolConfigs.chloe_prod = chloe_prod.phpFpm.pool;
+      services.myPhpfpm.poolConfigs.chloe_prod = chloe_prod.phpFpm.pool;
       system.activationScripts.chloe_prod = chloe_prod.activationScript;
       services.myWebsites.production.modules = chloe_prod.apache.modules;
       services.myWebsites.production.vhostConfs.chloe = {
@@ -48,7 +48,7 @@ in {
     })
     (lib.mkIf cfg.integration.enable {
       security.acme.certs."eldiron".extraDomains."chloe.immae.eu" = null;
-      services.phpfpm.poolConfigs.chloe_dev = chloe_dev.phpFpm.pool;
+      services.myPhpfpm.poolConfigs.chloe_dev = chloe_dev.phpFpm.pool;
       system.activationScripts.chloe_dev = chloe_dev.activationScript;
       services.myWebsites.integration.modules = chloe_dev.apache.modules;
       services.myWebsites.integration.vhostConfs.chloe = {
index 636b16eefba479049bd990b3b3a309e8ca7ba80e..5667c917e3e84de0ee46eb22d858caeba56fbe6b 100644 (file)
@@ -38,7 +38,7 @@ in {
         };
       };
 
-      services.phpfpm.poolConfigs.connexionswing_prod = connexionswing_prod.phpFpm.pool;
+      services.myPhpfpm.poolConfigs.connexionswing_prod = connexionswing_prod.phpFpm.pool;
       system.activationScripts.connexionswing_prod = connexionswing_prod.activationScript;
       services.myWebsites.production.modules = connexionswing_prod.apache.modules;
       services.myWebsites.production.vhostConfs.connexionswing = {
@@ -51,7 +51,7 @@ in {
     (lib.mkIf cfg.integration.enable {
       security.acme.certs."eldiron".extraDomains."sandetludo.immae.eu" = null;
       security.acme.certs."eldiron".extraDomains."connexionswing.immae.eu" = null;
-      services.phpfpm.poolConfigs.connexionswing_dev = connexionswing_dev.phpFpm.pool;
+      services.myPhpfpm.poolConfigs.connexionswing_dev = connexionswing_dev.phpFpm.pool;
       system.activationScripts.connexionswing_dev = connexionswing_dev.activationScript;
       services.myWebsites.integration.modules = connexionswing_dev.apache.modules;
       services.myWebsites.integration.vhostConfs.connexionswing = {
index 14b99983a0300b6ed0576b7d4cff64682ab5aa8f..54284e81a977a2e3d924e4f46db2e9e6d876999e 100644 (file)
@@ -107,6 +107,26 @@ in
       ];
     };
 
+    nixpkgs.config.packageOverrides = oldpkgs: rec {
+      php = php72;
+      php72 = (oldpkgs.php72.override {
+        mysql.connector-c = pkgs.mariadb;
+        config.php.mysqlnd = false;
+        config.php.mysqli = false;
+      }).overrideAttrs(old: rec {
+        # Didn't manage to build with mysqli + mysql_config connector
+        configureFlags = old.configureFlags ++ [
+          "--with-mysqli=mysqlnd"
+          ];
+        # preConfigure = (old.preConfigure or "") + ''
+        #   export CPPFLAGS="$CPPFLAGS -I${pkgs.mariadb}/include/mysql/server";
+        #   sed -i -e 's/#include "mysqli_priv.h"/#include "mysqli_priv.h"\n#include <mysql_version.h>/' \
+        #     ext/mysqli/mysqli.c ext/mysqli/mysqli_prop.c
+        #   '';
+      });
+      phpPackages = oldpkgs.php72Packages.override { inherit php; };
+    };
+
     services.myWebsites.Chloe.production.enable = cfg.production.enable;
     services.myWebsites.Ludivine.production.enable = cfg.production.enable;
     services.myWebsites.Aten.production.enable = cfg.production.enable;
index ed719ba42a5520f88cdc82458b7d2ecc3a0a592d..6aa1862a13af3339acc9e606eb4694205964c0ce 100644 (file)
@@ -32,7 +32,7 @@ in {
         };
       };
 
-      services.phpfpm.poolConfigs.ludivinecassal_prod = ludivinecassal_prod.phpFpm.pool;
+      services.myPhpfpm.poolConfigs.ludivinecassal_prod = ludivinecassal_prod.phpFpm.pool;
       system.activationScripts.ludivinecassal_prod = ludivinecassal_prod.activationScript;
       services.myWebsites.production.modules = ludivinecassal_prod.apache.modules;
       services.myWebsites.production.vhostConfs.ludivine = {
@@ -45,7 +45,7 @@ in {
     (lib.mkIf cfg.integration.enable {
       security.acme.certs."eldiron".extraDomains."ludivine.immae.eu" = null;
 
-      services.phpfpm.poolConfigs.ludivinecassal_dev = ludivinecassal_dev.phpFpm.pool;
+      services.myPhpfpm.poolConfigs.ludivinecassal_dev = ludivinecassal_dev.phpFpm.pool;
       system.activationScripts.ludivinecassal_dev = ludivinecassal_dev.activationScript;
       services.myWebsites.apacheConfig.ludivinecassal_dev.modules = ludivinecassal_dev.apache.modules;
       services.myWebsites.integration.modules = ludivinecassal_dev.apache.modules;
diff --git a/virtual/modules/websites/phpfpm/default.nix b/virtual/modules/websites/phpfpm/default.nix
new file mode 100644 (file)
index 0000000..3c6f027
--- /dev/null
@@ -0,0 +1,178 @@
+{ 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";
+        };
+      }
+   );
+  };
+}
diff --git a/virtual/modules/websites/phpfpm/pool-options.nix b/virtual/modules/websites/phpfpm/pool-options.nix
new file mode 100644 (file)
index 0000000..cc688c2
--- /dev/null
@@ -0,0 +1,35 @@
+{ lib }:
+
+with lib; {
+
+  options = {
+
+    listen = mkOption {
+      type = types.str;
+      example = "/path/to/unix/socket";
+      description = ''
+        The address on which to accept FastCGI requests.
+      '';
+    };
+
+    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.
+      '';
+    };
+  };
+}
+
index bf7417387ca0fb98bac378a93353c602a1880b5b..80261a39d7cb49f550681c2a351ac8f3aaa9ccaf 100644 (file)
@@ -36,7 +36,7 @@ in {
         };
       };
 
-      services.phpfpm.poolConfigs.piedsjaloux_prod = piedsjaloux_prod.phpFpm.pool;
+      services.myPhpfpm.poolConfigs.piedsjaloux_prod = piedsjaloux_prod.phpFpm.pool;
       system.activationScripts.piedsjaloux_prod = piedsjaloux_prod.activationScript;
       services.myWebsites.production.modules = piedsjaloux_prod.apache.modules;
       services.myWebsites.production.vhostConfs.piedsjaloux = {
@@ -48,7 +48,7 @@ in {
     })
     (lib.mkIf cfg.integration.enable {
       security.acme.certs."eldiron".extraDomains."piedsjaloux.immae.eu" = null;
-      services.phpfpm.poolConfigs.piedsjaloux_dev = piedsjaloux_dev.phpFpm.pool;
+      services.myPhpfpm.poolConfigs.piedsjaloux_dev = piedsjaloux_dev.phpFpm.pool;
       system.activationScripts.piedsjaloux_dev = piedsjaloux_dev.activationScript;
       services.myWebsites.integration.modules = piedsjaloux_dev.apache.modules;
       services.myWebsites.integration.vhostConfs.piedsjaloux = {
index 3ac71e09e5e880ada39e4f1f34c6fd2dd4b38571..b8d8e5941a14f9949185fe3fc88a48cb44651305 100644 (file)
@@ -1,4 +1,4 @@
-{ stdenv, fetchurl, checkEnv, writeText, lib }:
+{ stdenv, fetchurl, checkEnv, writeText, lib, phpPackages, php }:
 let
   nextcloud = let
     # FIXME: initial sync
@@ -231,6 +231,11 @@ let
         [ webRoot varDir config ]
         ++ lib.attrsets.mapAttrsToList (name: value: value) apps);
       socket = "/var/run/phpfpm/nextcloud.sock";
+      phpConfig = ''
+        extension=${phpPackages.redis}/lib/php/extensions/redis.so
+        extension=${phpPackages.apcu}/lib/php/extensions/apcu.so
+        zend_extension=${php}/lib/php/extensions/opcache.so
+        '';
       pool = ''
         listen = ${socket}
         user = ${apache.user}