python3Packages.pywikibot: init at 9.5.0 (#333068)
[NixPkgs.git] / nixos / modules / services / web-apps / zabbix.nix
blob3463148b30e0d799ac3813f6a94ae9c56e922bf9
2   config,
3   lib,
4   options,
5   pkgs,
6   ...
7 }:
9 let
11   inherit (lib)
12     mkDefault
13     mkEnableOption
14     mkPackageOption
15     mkRenamedOptionModule
16     mkForce
17     mkIf
18     mkMerge
19     mkOption
20     types
21     ;
22   inherit (lib)
23     literalExpression
24     mapAttrs
25     optionalString
26     optionals
27     versionAtLeast
28     ;
30   cfg = config.services.zabbixWeb;
31   opt = options.services.zabbixWeb;
32   fpm = config.services.phpfpm.pools.zabbix;
34   user = "zabbix";
35   group = "zabbix";
36   stateDir = "/var/lib/zabbix";
38   zabbixConfig = pkgs.writeText "zabbix.conf.php" ''
39     <?php
40     // Zabbix GUI configuration file.
41     global $DB;
42     $DB['TYPE'] = '${
43       {
44         mysql = "MYSQL";
45         pgsql = "POSTGRESQL";
46         oracle = "ORACLE";
47       }
48       .${cfg.database.type}
49     }';
50     $DB['SERVER'] = '${cfg.database.host}';
51     $DB['PORT'] = '${toString cfg.database.port}';
52     $DB['DATABASE'] = '${cfg.database.name}';
53     $DB['USER'] = '${cfg.database.user}';
54     # NOTE: file_get_contents adds newline at the end of returned string
55     $DB['PASSWORD'] = ${
56       if cfg.database.passwordFile != null then
57         "trim(file_get_contents('${cfg.database.passwordFile}'), \"\\r\\n\")"
58       else
59         "''"
60     };
61     // Schema name. Used for IBM DB2 and PostgreSQL.
62     $DB['SCHEMA'] = ''';
63     $ZBX_SERVER = '${cfg.server.address}';
64     $ZBX_SERVER_PORT = '${toString cfg.server.port}';
65     $ZBX_SERVER_NAME = ''';
66     $IMAGE_FORMAT_DEFAULT = IMAGE_FORMAT_PNG;
68     ${cfg.extraConfig}
69   '';
72   imports = [
73     (mkRenamedOptionModule
74       [
75         "services"
76         "zabbixWeb"
77         "virtualHost"
78       ]
79       [
80         "services"
81         "zabbixWeb"
82         "httpd"
83         "virtualHost"
84       ]
85     )
86   ];
87   # interface
89   options.services = {
90     zabbixWeb = {
91       enable = mkEnableOption "the Zabbix web interface";
93       package = mkPackageOption pkgs [
94         "zabbix"
95         "web"
96       ] { };
98       server = {
99         port = mkOption {
100           type = types.port;
101           description = "The port of the Zabbix server to connect to.";
102           default = 10051;
103         };
105         address = mkOption {
106           type = types.str;
107           description = "The IP address or hostname of the Zabbix server to connect to.";
108           default = "localhost";
109         };
110       };
112       database = {
113         type = mkOption {
114           type = types.enum [
115             "mysql"
116             "pgsql"
117             "oracle"
118           ];
119           example = "mysql";
120           default = "pgsql";
121           description = "Database engine to use.";
122         };
124         host = mkOption {
125           type = types.str;
126           default = "";
127           description = "Database host address.";
128         };
130         port = mkOption {
131           type = types.port;
132           default =
133             if cfg.database.type == "mysql" then
134               config.services.mysql.port
135             else if cfg.database.type == "pgsql" then
136               config.services.postgresql.settings.port
137             else
138               1521;
139           defaultText = literalExpression ''
140             if config.${opt.database.type} == "mysql" then config.${options.services.mysql.port}
141             else if config.${opt.database.type} == "pgsql" then config.services.postgresql.settings.port
142             else 1521
143           '';
144           description = "Database host port.";
145         };
147         name = mkOption {
148           type = types.str;
149           default = "zabbix";
150           description = "Database name.";
151         };
153         user = mkOption {
154           type = types.str;
155           default = "zabbix";
156           description = "Database user.";
157         };
159         passwordFile = mkOption {
160           type = types.nullOr types.path;
161           default = null;
162           example = "/run/keys/zabbix-dbpassword";
163           description = ''
164             A file containing the password corresponding to
165             {option}`database.user`.
166           '';
167         };
169         socket = mkOption {
170           type = types.nullOr types.path;
171           default = null;
172           example = "/run/postgresql";
173           description = "Path to the unix socket file to use for authentication.";
174         };
175       };
177       frontend = mkOption {
178         type = types.enum [
179           "nginx"
180           "httpd"
181         ];
182         example = "nginx";
183         default = "httpd";
184         description = "Frontend server to use.";
185       };
187       httpd.virtualHost = mkOption {
188         type = types.submodule (import ../web-servers/apache-httpd/vhost-options.nix);
189         example = literalExpression ''
190           {
191             hostName = "zabbix.example.org";
192             adminAddr = "webmaster@example.org";
193             forceSSL = true;
194             enableACME = true;
195           }
196         '';
197         default = { };
198         description = ''
199           Apache configuration can be done by adapting `services.httpd.virtualHosts.<name>`.
200           See [](#opt-services.httpd.virtualHosts) for further information.
201         '';
202       };
204       hostname = mkOption {
205         type = types.str;
206         default = "zabbix.local";
207         description = "Hostname for either nginx or httpd.";
208       };
210       nginx.virtualHost = mkOption {
211         type = types.submodule (import ../web-servers/nginx/vhost-options.nix);
212         example = literalExpression ''
213           {
214             forceSSL = true;
215             sslCertificateKey = "/etc/ssl/zabbix.key";
216             sslCertificate = "/etc/ssl/zabbix.crt";
217           }
218         '';
219         default = { };
220         description = ''
221           Nginx configuration can be done by adapting `services.nginx.virtualHosts.<name>`.
222           See [](#opt-services.nginx.virtualHosts) for further information.
223         '';
224       };
226       poolConfig = mkOption {
227         type =
228           with types;
229           attrsOf (oneOf [
230             str
231             int
232             bool
233           ]);
234         default = {
235           "pm" = "dynamic";
236           "pm.max_children" = 32;
237           "pm.start_servers" = 2;
238           "pm.min_spare_servers" = 2;
239           "pm.max_spare_servers" = 4;
240           "pm.max_requests" = 500;
241         };
242         description = ''
243           Options for the Zabbix PHP pool. See the documentation on `php-fpm.conf` for details on configuration directives.
244         '';
245       };
247       extraConfig = mkOption {
248         type = types.lines;
249         default = "";
250         description = ''
251           Additional configuration to be copied verbatim into {file}`zabbix.conf.php`.
252         '';
253       };
254     };
255   };
257   # implementation
259   config = mkIf cfg.enable {
261     services.zabbixWeb.extraConfig =
262       optionalString
263         (
264           (versionAtLeast config.system.stateVersion "20.09") && (versionAtLeast cfg.package.version "5.0.0")
265         )
266         ''
267           $DB['DOUBLE_IEEE754'] = 'true';
268         '';
270     systemd.tmpfiles.rules =
271       [ "d '${stateDir}' 0750 ${user} ${group} - -" ]
272       ++ optionals (cfg.frontend == "httpd") [
273         "d '${stateDir}/session' 0750 ${user} ${config.services.httpd.group} - -"
274       ]
275       ++ optionals (cfg.frontend == "nginx") [
276         "d '${stateDir}/session' 0750 ${user} ${config.services.nginx.group} - -"
277       ];
279     services.phpfpm.pools.zabbix = {
280       inherit user;
281       group = config.services.${cfg.frontend}.group;
282       phpOptions =
283         ''
284           # https://www.zabbix.com/documentation/current/manual/installation/install
285           memory_limit = 128M
286           post_max_size = 16M
287           upload_max_filesize = 2M
288           max_execution_time = 300
289           max_input_time = 300
290           session.auto_start = 0
291           mbstring.func_overload = 0
292           always_populate_raw_post_data = -1
293           # https://bbs.archlinux.org/viewtopic.php?pid=1745214#p1745214
294           session.save_path = ${stateDir}/session
295         ''
296         + optionalString (config.time.timeZone != null) ''
297           date.timezone = "${config.time.timeZone}"
298         ''
299         + optionalString (cfg.database.type == "oracle") ''
300           extension=${pkgs.phpPackages.oci8}/lib/php/extensions/oci8.so
301         '';
302       phpEnv.ZABBIX_CONFIG = "${zabbixConfig}";
303       settings = {
304         "listen.owner" =
305           if cfg.frontend == "httpd" then config.services.httpd.user else config.services.nginx.user;
306         "listen.group" =
307           if cfg.frontend == "httpd" then config.services.httpd.group else config.services.nginx.group;
308       } // cfg.poolConfig;
309     };
311     services.httpd = mkIf (cfg.frontend == "httpd") {
312       enable = true;
313       adminAddr = mkDefault cfg.httpd.virtualHost.adminAddr;
314       extraModules = [ "proxy_fcgi" ];
315       virtualHosts.${cfg.hostname} = mkMerge [
316         cfg.httpd.virtualHost
317         {
318           documentRoot = mkForce "${cfg.package}/share/zabbix";
319           extraConfig = ''
320             <Directory "${cfg.package}/share/zabbix">
321               <FilesMatch "\.php$">
322                 <If "-f %{REQUEST_FILENAME}">
323                   SetHandler "proxy:unix:${fpm.socket}|fcgi://localhost/"
324                 </If>
325               </FilesMatch>
326               AllowOverride all
327               Options -Indexes
328               DirectoryIndex index.php
329             </Directory>
330           '';
331         }
332       ];
333     };
335     services.nginx = mkIf (cfg.frontend == "nginx") {
336       enable = true;
337       virtualHosts.${cfg.hostname} = mkMerge [
338         cfg.nginx.virtualHost
339         {
340           root = mkForce "${cfg.package}/share/zabbix";
341           locations."/" = {
342             index = "index.html index.htm index.php";
343             tryFiles = "$uri $uri/ =404";
344           };
345           locations."~ \.php$".extraConfig = ''
346             fastcgi_pass  unix:${fpm.socket};
347             fastcgi_index index.php;
348           '';
349         }
350       ];
351     };
353     users.users.${user} = mapAttrs (name: mkDefault) {
354       description = "Zabbix daemon user";
355       uid = config.ids.uids.zabbix;
356       inherit group;
357     };
359     users.groups.${group} = mapAttrs (name: mkDefault) { gid = config.ids.gids.zabbix; };
360   };