1 { lib, config, pkgs, ... }:
6 cfg = config.services.postfixadmin;
7 fpm = config.services.phpfpm.pools.postfixadmin;
8 localDB = cfg.database.host == "localhost";
9 user = if localDB then cfg.database.username else "nginx";
12 options.services.postfixadmin = {
16 description = lib.mdDoc ''
17 Whether to enable postfixadmin.
19 Also enables nginx virtual host management.
20 Further nginx configuration can be done by adapting `services.nginx.virtualHosts.<name>`.
21 See [](#opt-services.nginx.virtualHosts) for further information.
27 example = "postfixadmin.example.com";
28 description = lib.mdDoc "Hostname to use for the nginx vhost";
31 adminEmail = mkOption {
33 example = "postmaster@example.com";
34 description = lib.mdDoc ''
35 Defines the Site Admin's email address.
36 This will be used to send emails from to create mailboxes and
37 from Send Email / Broadcast message pages.
41 setupPasswordFile = mkOption {
43 description = lib.mdDoc ''
44 Password file for the admin.
45 Generate with `php -r "echo password_hash('some password here', PASSWORD_DEFAULT);"`
52 default = "postfixadmin";
53 description = lib.mdDoc ''
54 Username for the postgresql connection.
55 If `database.host` is set to `localhost`, a unix user and group of the same name will be created as well.
60 default = "localhost";
61 description = lib.mdDoc ''
62 Host of the postgresql server. If this is not set to
63 `localhost`, you have to create the
64 postgresql user and database yourself, with appropriate
68 passwordFile = mkOption {
70 description = lib.mdDoc "Password file for the postgresql connection. Must be readable by user `nginx`.";
74 default = "postfixadmin";
75 description = lib.mdDoc "Name of the postgresql database";
79 extraConfig = mkOption {
82 description = lib.mdDoc "Extra configuration for the postfixadmin instance, see postfixadmin's config.inc.php for available options.";
86 config = mkIf cfg.enable {
87 environment.etc."postfixadmin/config.local.php".text = ''
90 $CONF['setup_password'] = file_get_contents('${cfg.setupPasswordFile}');
92 $CONF['database_type'] = 'pgsql';
93 $CONF['database_host'] = ${if localDB then "null" else "'${cfg.database.host}'"};
94 ${optionalString localDB "$CONF['database_user'] = '${cfg.database.username}';"}
95 $CONF['database_password'] = ${if localDB then "'dummy'" else "file_get_contents('${cfg.database.passwordFile}')"};
96 $CONF['database_name'] = '${cfg.database.dbname}';
97 $CONF['configured'] = true;
102 systemd.tmpfiles.rules = [ "d /var/cache/postfixadmin/templates_c 700 ${user} ${user}" ];
108 forceSSL = mkDefault true;
109 enableACME = mkDefault true;
111 root = "${pkgs.postfixadmin}/public";
115 fastcgi_split_path_info ^(.+\.php)(/.+)$;
116 fastcgi_pass unix:${fpm.socket};
117 include ${config.services.nginx.package}/conf/fastcgi_params;
118 include ${pkgs.nginx}/conf/fastcgi.conf;
126 services.postgresql = mkIf localDB {
129 name = cfg.database.username;
132 # The postgresql module doesn't currently support concepts like
133 # objects owners and extensions; for now we tack on what's needed
135 systemd.services.postfixadmin-postgres = let pgsql = config.services.postgresql; in mkIf localDB {
136 after = [ "postgresql.service" ];
137 bindsTo = [ "postgresql.service" ];
138 wantedBy = [ "multi-user.target" ];
147 psql --port=${toString pgsql.port} "$@"
150 PSQL -tAc "SELECT 1 FROM pg_database WHERE datname = '${cfg.database.dbname}'" | grep -q 1 || PSQL -tAc 'CREATE DATABASE "${cfg.database.dbname}" OWNER "${cfg.database.username}"'
151 current_owner=$(PSQL -tAc "SELECT pg_catalog.pg_get_userbyid(datdba) FROM pg_catalog.pg_database WHERE datname = '${cfg.database.dbname}'")
152 if [[ "$current_owner" != "${cfg.database.username}" ]]; then
153 PSQL -tAc 'ALTER DATABASE "${cfg.database.dbname}" OWNER TO "${cfg.database.username}"'
154 if [[ -e "${config.services.postgresql.dataDir}/.reassigning_${cfg.database.dbname}" ]]; then
155 echo "Reassigning ownership of database ${cfg.database.dbname} to user ${cfg.database.username} failed on last boot. Failing..."
158 touch "${config.services.postgresql.dataDir}/.reassigning_${cfg.database.dbname}"
159 PSQL "${cfg.database.dbname}" -tAc "REASSIGN OWNED BY \"$current_owner\" TO \"${cfg.database.username}\""
160 rm "${config.services.postgresql.dataDir}/.reassigning_${cfg.database.dbname}"
165 User = pgsql.superUser;
167 RemainAfterExit = true;
171 users.users.${user} = mkIf localDB {
176 users.groups.${user} = mkIf localDB {};
178 services.phpfpm.pools.postfixadmin = {
180 phpPackage = pkgs.php81;
185 settings = mapAttrs (name: mkDefault) {
186 "listen.owner" = "nginx";
187 "listen.group" = "nginx";
188 "listen.mode" = "0660";
190 "pm.max_children" = 75;
191 "pm.start_servers" = 2;
192 "pm.min_spare_servers" = 1;
193 "pm.max_spare_servers" = 20;
194 "pm.max_requests" = 500;
195 "catch_workers_output" = true;