{ 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); }; }; }; }