1# Tests in: nixos/tests/php/fpm-modular.nix
2
3# Non-module dependencies (importApply)
4{ formats, coreutils }:
5
6# Service module
7{
8 options,
9 config,
10 lib,
11 ...
12}:
13let
14 cfg = config.php-fpm;
15 format = formats.iniWithGlobalSection { };
16 configFile = format.generate "php-fpm.conf" {
17 globalSection = lib.filterAttrs (_: v: !lib.isAttrs v) cfg.settings;
18 sections = lib.filterAttrs (_: lib.isAttrs) cfg.settings;
19 };
20
21 poolOpts =
22 { name, ... }:
23 {
24 freeformType =
25 with lib.types;
26 attrsOf (oneOf [
27 str
28 int
29 bool
30 ]);
31 options = {
32 listen = lib.mkOption {
33 type =
34 with lib.types;
35 oneOf [
36 path
37 port
38 str
39 ];
40 default = "/run/php-fpm/${name}.sock";
41 description = ''
42 The address on which to accept FastCGI requests. Valid syntaxes are: `ip.add.re.ss:port`, `port`, `/path/to/unix/socket`.
43 '';
44 };
45
46 pm = lib.mkOption {
47 type = lib.types.enum [
48 "static"
49 "ondemand"
50 "dynamic"
51 ];
52 description = ''
53 Choose how the process manager will control the number of child processes.
54
55 `static` - the number of child processes is fixed (`pm.max_children`).
56 `ondemand` - the processes spawn on demand (when requested, as opposed to `dynamic`, where `pm.start_servers` are started when the service is started).
57 `dynamic` - the number of child processes is set dynamically based on the following directives: `pm.max_children`, `pm.start_servers`, pm.min_spare_servers, `pm.max_spare_servers`.
58 '';
59 };
60
61 "pm.max_children" = lib.mkOption {
62 type = lib.types.int;
63 description = ''
64 The number of child processes to be created when `pm` is set to `static` and the maximum
65 number of child processes to be created when `pm` is set to `dynamic`.
66
67 This option sets the limit on the number of simultaneous requests that will be served.
68 '';
69 };
70
71 user = lib.mkOption {
72 type = lib.types.str;
73 description = ''
74 Unix user of FPM processes.
75 '';
76 };
77 };
78 };
79in
80{
81 _class = "service";
82
83 options.php-fpm = {
84 package = lib.mkOption {
85 type = lib.types.package;
86 description = "PHP package to use for php-fpm";
87 defaultText = lib.literalMD ''The PHP package that provided this module.'';
88 example = lib.literalExpression ''
89 php.buildEnv {
90 extensions =
91 { all, ... }:
92 with all;
93 [
94 imagick
95 opcache
96 ];
97 extraConfig = "memory_limit=256M";
98 }
99 '';
100 };
101
102 settings = lib.mkOption {
103 type = lib.types.submodule {
104 freeformType =
105 with lib.types;
106 attrsOf (oneOf [
107 str
108 int
109 bool
110 (submodule poolOpts)
111 ]);
112 options = {
113 log_level = lib.mkOption {
114 type = lib.types.enum [
115 "alert"
116 "error"
117 "warning"
118 "notice"
119 "debug"
120 ];
121 default = "notice";
122 description = ''
123 Error log level.
124 '';
125 };
126 };
127 };
128 default = { };
129 example = lib.literalExpression ''
130 {
131 log_level = "debug";
132 log_limit = 2048;
133
134 mypool = {
135 "user" = "php";
136 "group" = "php";
137 "listen.owner" = "caddy";
138 "listen.group" = "caddy";
139 "pm" = "dynamic";
140 "pm.max_children" = 75;
141 "pm.start_servers" = 10;
142 "pm.min_spare_servers" = 5;
143 "pm.max_spare_servers" = 20;
144 "pm.max_requests" = 500;
145 }
146 }
147 '';
148 description = ''
149 PHP FPM configuration. Refer to [upstream documentation](https://www.php.net/manual/en/install.fpm.configuration.php) for details on supported values.
150 '';
151 };
152 };
153
154 config = {
155 php-fpm.settings = {
156 error_log = "syslog";
157 daemonize = false;
158 };
159
160 process.argv = [
161 "${cfg.package}/bin/php-fpm"
162 "-y"
163 configFile
164 ];
165 }
166 // lib.optionalAttrs (options ? systemd) {
167
168 systemd.service = {
169 after = [ "network.target" ];
170 documentation = [ "man:php-fpm(8)" ];
171
172 serviceConfig = {
173 Type = "notify";
174 ExecReload = "${coreutils}/bin/kill -USR2 $MAINPID";
175 RuntimeDirectory = "php-fpm";
176 RuntimeDirectoryPreserve = true;
177 Restart = "always";
178 };
179 };
180
181 }
182 // lib.optionalAttrs (options ? finit) {
183
184 finit.service = {
185 conditions = [ "service/syslogd/ready" ];
186 reload = "${coreutils}/bin/kill -USR2 $MAINPID";
187 notify = "systemd";
188 };
189 };
190
191 meta.maintainers = with lib.maintainers; [
192 aanderse
193 ];
194}