171 lines
5.0 KiB
Nix
171 lines
5.0 KiB
Nix
{ config, lib, pkgs, ... }:
|
|
|
|
with lib;
|
|
let
|
|
cfg = config.fudo.services.mail-server;
|
|
|
|
hostname = config.instance.hostname;
|
|
domain-name = config.instance.local-domain;
|
|
domain = config.fudo.domains.${domain-name};
|
|
|
|
mailserver-host = domain.primary-mailserver;
|
|
mailserver-domain-name = config.fudo.hosts.${mailserver-host}.domain;
|
|
mailserver-domain = config.fudo.domains.${mailserver-domain-name};
|
|
|
|
mailserver-fqdn = "${mailserver-host}.${mailserver-domain-name}";
|
|
|
|
hasMailServer = mailserver-host != null;
|
|
|
|
isMailServer = hostname == mailserver-host;
|
|
|
|
isLocalMailserver = domain-name == mailserver-domain-name;
|
|
|
|
metricsEnabled = !isNull mailserver-domain.metrics;
|
|
|
|
host-certs = config.fudo.acme.host-domains.${hostname};
|
|
|
|
in {
|
|
options.fudo.services.mail-server = with types; {
|
|
debug = mkEnableOption "Enable debug options for mailserver.";
|
|
|
|
enable = mkOption {
|
|
type = bool;
|
|
default = true;
|
|
description =
|
|
"Temporary -- allow disabling mail server (in favor of mail container).";
|
|
};
|
|
|
|
state-directory = mkOption {
|
|
type = str;
|
|
description = "Directory at which to store mailserver state.";
|
|
};
|
|
};
|
|
|
|
config = mkIf (hasMailServer && cfg.enable) {
|
|
services.nginx = mkIf (isMailServer && metricsEnabled) {
|
|
enable = true;
|
|
recommendedOptimisation = true;
|
|
recommendedProxySettings = true;
|
|
|
|
virtualHosts."mail-stats.${mailserver-domain-name}" = let
|
|
trusted-networks = config.instance.local-networks;
|
|
trustedNetworkString = optionalString (length trusted-networks > 0)
|
|
(concatStringsSep "\n"
|
|
(map (network: "allow ${network};") trusted-networks)) + ''
|
|
|
|
|
|
deny all;'';
|
|
in {
|
|
enableACME = true;
|
|
forceSSL = true;
|
|
|
|
locations = let monitor-cfg = config.fudo.mail-server.monitoring;
|
|
in {
|
|
"/metrics/dovecot" = {
|
|
proxyPass = "http://127.0.0.1:${
|
|
toString monitor-cfg.dovecot-listen-port
|
|
}/metrics";
|
|
extraConfig = trustedNetworkString;
|
|
};
|
|
"/metrics/postfix" = {
|
|
proxyPass = "http://127.0.0.1:${
|
|
toString monitor-cfg.postfix-listen-port
|
|
}/metrics";
|
|
extraConfig = trustedNetworkString;
|
|
};
|
|
"/metrics/rspamd" = {
|
|
proxyPass = "http://127.0.0.1:${
|
|
toString monitor-cfg.rspamd-listen-port
|
|
}/metrics";
|
|
extraConfig = trustedNetworkString;
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
fudo = {
|
|
acme.host-domains = mkIf isMailServer {
|
|
${hostname} = {
|
|
"imap.${mailserver-domain-name}" = {
|
|
admin-email = "admin@${mailserver-domain-name}";
|
|
local-copies.dovecot = {
|
|
user = config.services.dovecot2.user;
|
|
dependent-services = [ "dovecot2.service" ];
|
|
};
|
|
};
|
|
"smtp.${mailserver-domain-name}" = {
|
|
admin-email = "admin@${mailserver-domain-name}";
|
|
local-copies.postfix = {
|
|
user = config.services.postfix.user;
|
|
dependent-services = [ "postfix.service" ];
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
metrics.prometheus.service-discovery-dns = mkIf metricsEnabled
|
|
(genAttrs [ "dovecot" "postfix" "rspamd" ]
|
|
(mtype: [ "${mtype}._metrics._tcp.${mailserver-domain-name}" ]));
|
|
|
|
mail-server = mkIf isLocalMailserver {
|
|
enable = isMailServer;
|
|
|
|
domain = mailserver-domain-name;
|
|
mail-hostname = "smtp.${mailserver-domain-name}";
|
|
monitoring.enable = metricsEnabled;
|
|
|
|
debug = cfg.debug;
|
|
|
|
clamav.enable = true;
|
|
|
|
dkim.signing = true;
|
|
|
|
dovecot = let
|
|
cert-copy =
|
|
host-certs."imap.${mailserver-domain-name}".local-copies.dovecot;
|
|
in {
|
|
ssl-certificate = cert-copy.full-certificate;
|
|
ssl-private-key = cert-copy.private-key;
|
|
};
|
|
|
|
postfix = let
|
|
cert-copy =
|
|
host-certs."smtp.${mailserver-domain-name}".local-copies.postfix;
|
|
in {
|
|
ssl-certificate = cert-copy.full-certificate;
|
|
ssl-private-key = cert-copy.private-key;
|
|
};
|
|
|
|
local-domains = [ mailserver-fqdn "smtp.${mailserver-domain-name}" ];
|
|
|
|
mail-directory = "${cfg.state-directory}/mail";
|
|
state-directory = "${cfg.state-directory}/state";
|
|
|
|
trusted-networks = let
|
|
wrapIpv6 = net:
|
|
let elems = builtins.split "/" net;
|
|
in "[${elemAt elems 0}]/${elemAt elems 2}";
|
|
|
|
in map (network:
|
|
if (builtins.match ".*::.*" network) != null then
|
|
wrapIpv6 network
|
|
else
|
|
network) config.instance.local-networks;
|
|
|
|
user-aliases = genAttrs (attrNames config.fudo.users)
|
|
(username: config.fudo.users."${username}".email-aliases);
|
|
|
|
alias-users = genAttrs [
|
|
"root"
|
|
"postmaster"
|
|
"hostmaster"
|
|
"webmaster"
|
|
"system"
|
|
"admin"
|
|
"dmarc-report"
|
|
] (alias: config.instance.local-admins);
|
|
};
|
|
};
|
|
};
|
|
}
|