{ lib, config, ... }: with lib; let cfg = config.services.phpApplication; cfgByEnv = lists.groupBy (x: x.websiteEnv) (builtins.attrValues cfg); in { options = { services.phpApplication = with types; mkOption { default = {}; description = '' php applications to define ''; type = attrsOf (submodule { options = { varDir = mkOption { type = nullOr path; description = '' Path to application’s 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"; }; 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. ''; }; app = mkOption { type = path; description = '' Path to application root ''; }; webappName = mkOption { type = nullOr str; description = '' Alias name for the app, to be used in services.websites.webappDirs ''; }; 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 ''; }; watchFiles = mkOption { type = listOf path; default = []; description = '' Path to other files to watch to trigger preStart scripts ''; }; }; }); }; }; config = { services.websites.env = attrsets.mapAttrs' (name: cfgs: attrsets.nameValuePair name { modules = [ "proxy_fcgi" ]; watchPaths = builtins.concatLists (map (c: c.watchFiles) cfgs); } ) cfgByEnv; services.websites.webappDirs = attrsets.mapAttrs' (name: icfg: attrsets.nameValuePair icfg.webappName icfg.webRoot ) (attrsets.filterAttrs (n: v: !isNull v.webappName && !isNull v.webRoot) cfg); 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.watchFiles == 0) "return 0"} [ ! -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.watchFiles == 0) "return 0"} sha512sum ${builtins.concatStringsSep " " icfg.watchFiles} > ${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; 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 ''; } ) cfg; }; }