1 { lib, config, pkgs, ... }:
4 cfg = config.services.phpApplication;
5 cfgByEnv = lists.groupBy (x: x.websiteEnv) (builtins.attrValues cfg.apps);
8 options = with types; {
9 services.phpApplication.apps = mkOption {
12 php applications to define
14 type = attrsOf (submodule {
19 Path to application’s vardir.
22 varDirPaths = mkOption {
26 Map of additional folders => mode to create under varDir
33 Mode to apply to the vardir
36 phpSession = mkOption {
39 description = "Handle phpsession files separately in vardir";
41 phpListen = mkOption {
44 description = "Name of the socket to listen to. Defaults to app name if null";
49 description = "Pool configuration to append";
54 description = "Pool environment to append";
56 phpPackage = mkOption {
59 description = "Php package to use";
61 phpOptions = mkOption {
64 description = "php configuration to append";
66 phpOpenbasedir = mkOption {
70 paths to add to php open_basedir configuration in addition to app and vardir
73 phpWatchFiles = mkOption {
77 Path to other files to watch to trigger preStart scripts
80 websiteEnv = mkOption {
83 website instance name to use
86 httpdUser = mkOption {
88 default = config.services.httpd.user;
90 httpd user to run the prestart scripts as.
93 httpdGroup = mkOption {
95 default = config.services.httpd.group;
97 httpd group to run the prestart scripts as.
100 httpdWatchFiles = mkOption {
104 Path to other files to watch to trigger httpd reload
110 Path to application root
113 webappName = mkOption {
117 Alias name for the app, to be used in services.websites.webappDirs
123 Path to the web root path of the application. May differ from the application itself (usually a subdirectory)
126 preStartActions = mkOption {
130 List of actions to run as apache user at preStart when
131 whatchFiles or app dir changed.
134 serviceDeps = mkOption {
138 List of systemd services this application depends on
144 # Read-only variables
145 services.phpApplication.phpListenPaths = mkOption {
147 default = attrsets.mapAttrs' (name: icfg: attrsets.nameValuePair
148 name config.services.phpfpm.pools."${name}".socket
152 Full paths to listen for php
155 services.phpApplication.webappDirs = mkOption {
157 default = attrsets.filterAttrs (n: v: builtins.hasAttr n cfg.apps) config.services.websites.webappDirsPaths;
160 Stable name webapp dirs for httpd
166 services.websites.env = attrsets.mapAttrs' (name: cfgs: attrsets.nameValuePair
168 modules = [ "proxy_fcgi" ];
169 watchPaths = builtins.concatLists (map (c: c.httpdWatchFiles) cfgs);
173 services.phpfpm.pools = attrsets.mapAttrs' (name: icfg: attrsets.nameValuePair
175 user = icfg.httpdUser;
176 group = icfg.httpdUser;
178 "listen.owner" = icfg.httpdUser;
179 "listen.group" = icfg.httpdGroup;
180 "php_admin_value[open_basedir]" = builtins.concatStringsSep ":" ([icfg.app icfg.varDir] ++ icfg.phpWatchFiles ++ icfg.phpOpenbasedir);
182 // optionalAttrs (icfg.phpSession) { "php_admin_value[session.save_path]" = "${icfg.varDir}/phpSessions"; }
184 phpOptions = config.services.phpfpm.phpOptions + icfg.phpOptions;
185 inherit (icfg) phpEnv phpPackage;
189 services.websites.webappDirs = attrsets.mapAttrs' (name: icfg: attrsets.nameValuePair
190 (if icfg.webappName == null then name else icfg.webappName) icfg.webRoot
191 ) (attrsets.filterAttrs (n: v: !isNull v.webRoot) cfg.apps);
193 services.filesWatcher = attrsets.mapAttrs' (name: icfg: attrsets.nameValuePair
196 paths = icfg.phpWatchFiles;
198 ) (attrsets.filterAttrs (n: v: builtins.length v.phpWatchFiles > 0) cfg.apps);
200 systemd.services = attrsets.mapAttrs' (name: icfg: attrsets.nameValuePair
202 after = lib.mkAfter icfg.serviceDeps;
203 wants = icfg.serviceDeps;
204 preStart = lib.mkAfter (optionalString (!isNull icfg.varDir) ''
205 watchFilesChanged() {
206 ${optionalString (builtins.length icfg.phpWatchFiles == 0) "return 1"}
207 [ ! -f "${icfg.varDir}"/watchedFiles ] \
208 || ! sha512sum -c --status ${icfg.varDir}/watchedFiles
211 [ ! -f "${icfg.varDir}/currentWebappDir" -o \
212 "${icfg.app}" != "$(cat ${icfg.varDir}/currentWebappDir 2>/dev/null)" ]
215 ${optionalString (builtins.length icfg.phpWatchFiles == 0) "return 0"}
216 sha512sum ${builtins.concatStringsSep " " icfg.phpWatchFiles} > ${icfg.varDir}/watchedFiles
219 if watchFilesChanged || appDirChanged; then
220 pushd ${icfg.app} > /dev/null
221 ${builtins.concatStringsSep "\n " (map (c: "/run/wrappers/bin/sudo -u ${icfg.httpdUser} ${c}") icfg.preStartActions) }
223 echo -n "${icfg.app}" > ${icfg.varDir}/currentWebappDir
230 system.activationScripts = attrsets.mapAttrs' (name: icfg: attrsets.nameValuePair
233 text = optionalString (!isNull icfg.varDir) ''
234 install -m ${icfg.mode} -o ${icfg.httpdUser} -g ${icfg.httpdGroup} -d ${icfg.varDir}
235 '' + optionalString (icfg.phpSession) ''
236 install -m 0700 -o ${icfg.httpdUser} -g ${icfg.httpdGroup} -d ${icfg.varDir}/phpSessions
237 '' + builtins.concatStringsSep "\n" (attrsets.mapAttrsToList (n: v: ''
238 install -m ${v} -o ${icfg.httpdUser} -g ${icfg.httpdGroup} -d ${icfg.varDir}/${n}
239 '') icfg.varDirPaths);