+++ /dev/null
-{ lib, config, pkgs, ... }:
-with lib;
-let
- cfg = config.services.phpApplication;
- cfgByEnv = lists.groupBy (x: x.websiteEnv) (builtins.attrValues cfg.apps);
-in
-{
- options = with types; {
- services.phpApplication.apps = mkOption {
- default = {};
- description = ''
- php applications to define
- '';
- type = attrsOf (submodule {
- options = {
- varDir = mkOption {
- type = nullOr path;
- description = ''
- Path to application’s vardir.
- '';
- };
- varDirPaths = mkOption {
- type = attrsOf str;
- default = {};
- description = ''
- Map of additional folders => mode to create under varDir
- '';
- };
- mode = mkOption {
- type = str;
- default = "0700";
- description = ''
- Mode to apply to the vardir
- '';
- };
- phpSession = mkOption {
- type = bool;
- default = true;
- description = "Handle phpsession files separately in vardir";
- };
- phpListen = mkOption {
- type = nullOr str;
- default = null;
- description = "Name of the socket to listen to. Defaults to app name if null";
- };
- phpPool = mkOption {
- type = attrsOf str;
- default = {};
- description = "Pool configuration to append";
- };
- phpEnv = mkOption {
- type = attrsOf str;
- default = {};
- description = "Pool environment to append";
- };
- phpPackage = mkOption {
- type = attrsOf str;
- default = pkgs.php;
- description = "Php package to use";
- };
- phpOptions = mkOption {
- type = lines;
- default = "";
- description = "php configuration to append";
- };
- phpOpenbasedir = mkOption {
- type = listOf path;
- default = [];
- description = ''
- paths to add to php open_basedir configuration in addition to app and vardir
- '';
- };
- phpWatchFiles = mkOption {
- type = listOf path;
- default = [];
- description = ''
- Path to other files to watch to trigger preStart scripts
- '';
- };
- websiteEnv = mkOption {
- type = str;
- description = ''
- website instance name to use
- '';
- };
- httpdUser = mkOption {
- type = str;
- default = config.services.httpd.user;
- description = ''
- httpd user to run the prestart scripts as.
- '';
- };
- httpdGroup = mkOption {
- type = str;
- default = config.services.httpd.group;
- description = ''
- httpd group to run the prestart scripts as.
- '';
- };
- httpdWatchFiles = mkOption {
- type = listOf path;
- default = [];
- description = ''
- Path to other files to watch to trigger httpd reload
- '';
- };
- app = mkOption {
- type = path;
- description = ''
- Path to application root
- '';
- };
- webRoot = mkOption {
- type = nullOr path;
- description = ''
- Path to the web root path of the application. May differ from the application itself (usually a subdirectory)
- '';
- };
- preStartActions = mkOption {
- type = listOf str;
- default = [];
- description = ''
- List of actions to run as apache user at preStart when
- whatchFiles or app dir changed.
- '';
- };
- serviceDeps = mkOption {
- type = listOf str;
- default = [];
- description = ''
- List of systemd services this application depends on
- '';
- };
- };
- });
- };
- # Read-only variables
- services.phpApplication.phpListenPaths = mkOption {
- type = attrsOf path;
- default = attrsets.mapAttrs' (name: icfg: attrsets.nameValuePair
- name config.services.phpfpm.pools."${name}".socket
- ) cfg.apps;
- readOnly = true;
- description = ''
- Full paths to listen for php
- '';
- };
- };
-
- config = {
- services.websites.env = attrsets.mapAttrs' (name: cfgs: attrsets.nameValuePair
- name {
- modules = [ "proxy_fcgi" ];
- watchPaths = builtins.concatLists (map (c: c.httpdWatchFiles) cfgs);
- }
- ) cfgByEnv;
-
- services.phpfpm.pools = attrsets.mapAttrs' (name: icfg: attrsets.nameValuePair
- name {
- user = icfg.httpdUser;
- group = icfg.httpdUser;
- settings = {
- "listen.owner" = icfg.httpdUser;
- "listen.group" = icfg.httpdGroup;
- "php_admin_value[open_basedir]" = builtins.concatStringsSep ":" ([icfg.app icfg.varDir] ++ icfg.phpWatchFiles ++ icfg.phpOpenbasedir);
- }
- // optionalAttrs (icfg.phpSession) { "php_admin_value[session.save_path]" = "${icfg.varDir}/phpSessions"; }
- // icfg.phpPool;
- phpOptions = config.services.phpfpm.phpOptions + icfg.phpOptions;
- inherit (icfg) phpEnv phpPackage;
- }
- ) cfg.apps;
-
- services.filesWatcher = attrsets.mapAttrs' (name: icfg: attrsets.nameValuePair
- "phpfpm-${name}" {
- restart = true;
- paths = icfg.phpWatchFiles;
- }
- ) (attrsets.filterAttrs (n: v: builtins.length v.phpWatchFiles > 0) cfg.apps);
-
- systemd.services = attrsets.mapAttrs' (name: icfg: attrsets.nameValuePair
- "phpfpm-${name}" {
- after = lib.mkAfter icfg.serviceDeps;
- wants = icfg.serviceDeps;
- preStart = lib.mkAfter (optionalString (!isNull icfg.varDir) ''
- watchFilesChanged() {
- ${optionalString (builtins.length icfg.phpWatchFiles == 0) "return 1"}
- [ ! -f "${icfg.varDir}"/watchedFiles ] \
- || ! sha512sum -c --status ${icfg.varDir}/watchedFiles
- }
- appDirChanged() {
- [ ! -f "${icfg.varDir}/currentWebappDir" -o \
- "${icfg.app}" != "$(cat ${icfg.varDir}/currentWebappDir 2>/dev/null)" ]
- }
- updateWatchFiles() {
- ${optionalString (builtins.length icfg.phpWatchFiles == 0) "return 0"}
- sha512sum ${builtins.concatStringsSep " " icfg.phpWatchFiles} > ${icfg.varDir}/watchedFiles
- }
-
- if watchFilesChanged || appDirChanged; then
- pushd ${icfg.app} > /dev/null
- ${builtins.concatStringsSep "\n " (map (c: "/run/wrappers/bin/sudo -u ${icfg.httpdUser} ${c}") icfg.preStartActions) }
- popd > /dev/null
- echo -n "${icfg.app}" > ${icfg.varDir}/currentWebappDir
- updateWatchFiles
- fi
- '');
- }
- ) cfg.apps;
-
- system.activationScripts = attrsets.mapAttrs' (name: icfg: attrsets.nameValuePair
- name {
- deps = [];
- text = optionalString (!isNull icfg.varDir) ''
- install -m ${icfg.mode} -o ${icfg.httpdUser} -g ${icfg.httpdGroup} -d ${icfg.varDir}
- '' + optionalString (icfg.phpSession) ''
- install -m 0700 -o ${icfg.httpdUser} -g ${icfg.httpdGroup} -d ${icfg.varDir}/phpSessions
- '' + builtins.concatStringsSep "\n" (attrsets.mapAttrsToList (n: v: ''
- install -m ${v} -o ${icfg.httpdUser} -g ${icfg.httpdGroup} -d ${icfg.varDir}/${n}
- '') icfg.varDirPaths);
- }
- ) cfg.apps;
- };
-}