199 lines
6.6 KiB
Nix
199 lines
6.6 KiB
Nix
{ lib, config, pkgs, ... }:
|
|
|
|
with lib;
|
|
|
|
let
|
|
cfg = config.services.postfixadmin;
|
|
fpm = config.services.phpfpm.pools.postfixadmin;
|
|
localDB = cfg.database.host == "localhost";
|
|
user = if localDB then cfg.database.username else "nginx";
|
|
in
|
|
{
|
|
options.services.postfixadmin = {
|
|
enable = mkOption {
|
|
type = types.bool;
|
|
default = false;
|
|
description = ''
|
|
Whether to enable postfixadmin.
|
|
|
|
Also enables nginx virtual host management.
|
|
Further nginx configuration can be done by adapting <literal>services.nginx.virtualHosts.<name></literal>.
|
|
See <xref linkend="opt-services.nginx.virtualHosts"/> for further information.
|
|
'';
|
|
};
|
|
|
|
hostName = mkOption {
|
|
type = types.str;
|
|
example = "postfixadmin.example.com";
|
|
description = "Hostname to use for the nginx vhost";
|
|
};
|
|
|
|
adminEmail = mkOption {
|
|
type = types.str;
|
|
example = "postmaster@example.com";
|
|
description = ''
|
|
Defines the Site Admin's email address.
|
|
This will be used to send emails from to create mailboxes and
|
|
from Send Email / Broadcast message pages.
|
|
'';
|
|
};
|
|
|
|
setupPasswordFile = mkOption {
|
|
type = types.path;
|
|
description = ''
|
|
Password file for the admin.
|
|
Generate with <literal>php -r "echo password_hash('some password here', PASSWORD_DEFAULT);"</literal>
|
|
'';
|
|
};
|
|
|
|
database = {
|
|
username = mkOption {
|
|
type = types.str;
|
|
default = "postfixadmin";
|
|
description = ''
|
|
Username for the postgresql connection.
|
|
If <literal>database.host</literal> is set to <literal>localhost</literal>, a unix user and group of the same name will be created as well.
|
|
'';
|
|
};
|
|
host = mkOption {
|
|
type = types.str;
|
|
default = "localhost";
|
|
description = ''
|
|
Host of the postgresql server. If this is not set to
|
|
<literal>localhost</literal>, you have to create the
|
|
postgresql user and database yourself, with appropriate
|
|
permissions.
|
|
'';
|
|
};
|
|
passwordFile = mkOption {
|
|
type = types.path;
|
|
description = "Password file for the postgresql connection. Must be readable by user <literal>nginx</literal>.";
|
|
};
|
|
dbname = mkOption {
|
|
type = types.str;
|
|
default = "postfixadmin";
|
|
description = "Name of the postgresql database";
|
|
};
|
|
};
|
|
|
|
extraConfig = mkOption {
|
|
type = types.lines;
|
|
default = "";
|
|
description = "Extra configuration for the postfixadmin instance, see postfixadmin's config.inc.php for available options.";
|
|
};
|
|
};
|
|
|
|
config = mkIf cfg.enable {
|
|
environment.etc."postfixadmin/config.local.php".text = ''
|
|
<?php
|
|
|
|
$CONF['setup_password'] = file_get_contents('${cfg.setupPasswordFile}');
|
|
|
|
$CONF['database_type'] = 'pgsql';
|
|
$CONF['database_host'] = ${if localDB then "null" else "'${cfg.database.host}'"};
|
|
${optionalString localDB "$CONF['database_user'] = '${cfg.database.username}';"}
|
|
$CONF['database_password'] = ${if localDB then "'dummy'" else "file_get_contents('${cfg.database.passwordFile}')"};
|
|
$CONF['database_name'] = '${cfg.database.dbname}';
|
|
$CONF['configured'] = true;
|
|
|
|
${cfg.extraConfig}
|
|
'';
|
|
|
|
systemd.tmpfiles.rules = [ "d /var/cache/postfixadmin/templates_c 700 ${user} ${user}" ];
|
|
|
|
services.nginx = {
|
|
enable = true;
|
|
virtualHosts = {
|
|
${cfg.hostName} = {
|
|
forceSSL = mkDefault true;
|
|
enableACME = mkDefault true;
|
|
locations."/" = {
|
|
root = "${pkgs.postfixadmin}/public";
|
|
index = "index.php";
|
|
extraConfig = ''
|
|
location ~* \.php$ {
|
|
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
|
fastcgi_pass unix:${fpm.socket};
|
|
include ${config.services.nginx.package}/conf/fastcgi_params;
|
|
include ${pkgs.nginx}/conf/fastcgi.conf;
|
|
}
|
|
'';
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
services.postgresql = mkIf localDB {
|
|
enable = true;
|
|
ensureUsers = [ {
|
|
name = cfg.database.username;
|
|
} ];
|
|
};
|
|
# The postgresql module doesn't currently support concepts like
|
|
# objects owners and extensions; for now we tack on what's needed
|
|
# here.
|
|
systemd.services.postfixadmin-postgres = let pgsql = config.services.postgresql; in mkIf localDB {
|
|
after = [ "postgresql.service" ];
|
|
bindsTo = [ "postgresql.service" ];
|
|
wantedBy = [ "multi-user.target" ];
|
|
path = [
|
|
pgsql.package
|
|
pkgs.util-linux
|
|
];
|
|
script = ''
|
|
set -eu
|
|
|
|
PSQL() {
|
|
psql --port=${toString pgsql.port} "$@"
|
|
}
|
|
|
|
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}"'
|
|
current_owner=$(PSQL -tAc "SELECT pg_catalog.pg_get_userbyid(datdba) FROM pg_catalog.pg_database WHERE datname = '${cfg.database.dbname}'")
|
|
if [[ "$current_owner" != "${cfg.database.username}" ]]; then
|
|
PSQL -tAc 'ALTER DATABASE "${cfg.database.dbname}" OWNER TO "${cfg.database.username}"'
|
|
if [[ -e "${config.services.postgresql.dataDir}/.reassigning_${cfg.database.dbname}" ]]; then
|
|
echo "Reassigning ownership of database ${cfg.database.dbname} to user ${cfg.database.username} failed on last boot. Failing..."
|
|
exit 1
|
|
fi
|
|
touch "${config.services.postgresql.dataDir}/.reassigning_${cfg.database.dbname}"
|
|
PSQL "${cfg.database.dbname}" -tAc "REASSIGN OWNED BY \"$current_owner\" TO \"${cfg.database.username}\""
|
|
rm "${config.services.postgresql.dataDir}/.reassigning_${cfg.database.dbname}"
|
|
fi
|
|
'';
|
|
|
|
serviceConfig = {
|
|
User = pgsql.superUser;
|
|
Type = "oneshot";
|
|
RemainAfterExit = true;
|
|
};
|
|
};
|
|
|
|
users.users.${user} = mkIf localDB {
|
|
group = user;
|
|
isSystemUser = true;
|
|
createHome = false;
|
|
};
|
|
users.groups.${user} = mkIf localDB {};
|
|
|
|
services.phpfpm.pools.postfixadmin = {
|
|
user = user;
|
|
phpPackage = pkgs.php74;
|
|
phpOptions = ''
|
|
error_log = 'stderr'
|
|
log_errors = on
|
|
'';
|
|
settings = mapAttrs (name: mkDefault) {
|
|
"listen.owner" = "nginx";
|
|
"listen.group" = "nginx";
|
|
"listen.mode" = "0660";
|
|
"pm" = "dynamic";
|
|
"pm.max_children" = 75;
|
|
"pm.start_servers" = 2;
|
|
"pm.min_spare_servers" = 1;
|
|
"pm.max_spare_servers" = 20;
|
|
"pm.max_requests" = 500;
|
|
"catch_workers_output" = true;
|
|
};
|
|
};
|
|
};
|
|
}
|