From e0ea85dcde327b3c98a8023fe62d4b384b11c350 Mon Sep 17 00:00:00 2001 From: Jakob Lechner Date: Mon, 8 Dec 2025 15:21:51 +0100 Subject: [PATCH] Migrate mailserver config to 25.11 --- hosts/iron/services/mail.nix | 24 +++--- modules/mailserver/default.nix | 5 -- modules/mailserver/dovecot.nix | 57 +++++++------- modules/mailserver/postfix.nix | 133 ++++++++++++++++----------------- 4 files changed, 102 insertions(+), 117 deletions(-) diff --git a/hosts/iron/services/mail.nix b/hosts/iron/services/mail.nix index c5d855e..9040449 100644 --- a/hosts/iron/services/mail.nix +++ b/hosts/iron/services/mail.nix @@ -1,15 +1,9 @@ -{ config, ... }: - -let - inherit (config.networking) ports; -in { #sops.secrets."domain_key_jalr.de".owner = "rspamd"; jalr = { mailserver = { enable = true; fqdn = "hha.jalr.de"; - relayPort = ports.postfix-relay.tcp; domains = [ { domain = "jalr.de"; @@ -25,14 +19,18 @@ in }; }; services.postfix = { - config = { - smtp_bind_address = "159.69.103.126"; - smtp_bind_address_enforce = true; + settings = { + main = { + smtp_bind_address = "159.69.103.126"; + smtp_bind_address_enforce = true; + }; + master = { + smtp.args = [ + "-o" + "inet_protocols=ipv4" + ]; + }; }; - masterConfig.smtp.args = [ - "-o" - "inet_protocols=ipv4" - ]; }; services.nginx.virtualHosts."hha.jalr.de" = { enableACME = true; diff --git a/modules/mailserver/default.nix b/modules/mailserver/default.nix index 59a8e2c..a18dc19 100644 --- a/modules/mailserver/default.nix +++ b/modules/mailserver/default.nix @@ -5,11 +5,6 @@ in { options.jalr.mailserver = with lib; with lib.types; { enable = mkEnableOption "simple mail server"; - relayPort = mkOption { - description = "SMTP port for relay mail relay."; - type = port; - default = 25; - }; fqdn = mkOption { type = str; description = '' diff --git a/modules/mailserver/dovecot.nix b/modules/mailserver/dovecot.nix index a2485a5..dbd6e71 100644 --- a/modules/mailserver/dovecot.nix +++ b/modules/mailserver/dovecot.nix @@ -8,6 +8,26 @@ let "\n" ({ address, passwordHash, ... }: "${address}:${passwordHash}") cfg.users); + + sieveScripts = { + learn-spam = pkgs.writeText "learn-spam.sieve" '' + require ["vnd.dovecot.pipe", "copy", "imapsieve"]; + pipe :copy "rspamc" ["learn_spam"]; + ''; + learn-ham = pkgs.writeText "learn-ham.sieve" '' + require ["vnd.dovecot.pipe", "copy", "imapsieve", "environment", "variables"]; + + if environment :matches "imap.mailbox" "*" { + set "mailbox" "''${1}"; + } + + if string "''${mailbox}" "Trash" { + stop; + } + + pipe :copy "rspamc" ["learn_ham"]; + ''; + }; in lib.mkIf cfg.enable { services.dovecot2 = { @@ -111,12 +131,12 @@ lib.mkIf cfg.enable { ${lib.optionalString cfg.spam.enable '' imapsieve_mailbox1_name = Spam imapsieve_mailbox1_causes = COPY - imapsieve_mailbox1_before = file:/var/lib/dovecot/sieve/learn-spam.sieve + imapsieve_mailbox1_before = file:${sieveScripts.learn-spam} imapsieve_mailbox2_name = * imapsieve_mailbox2_from = Spam imapsieve_mailbox2_causes = COPY - imapsieve_mailbox2_before = file:/var/lib/dovecot/sieve/learn-ham.sieve + imapsieve_mailbox2_before = file:${sieveScripts.learn-ham} sieve_pipe_bin_dir = ${pkgs.symlinkJoin { name = "sieve-pipe-bin-dir"; paths = with pkgs; [ rspamd ]; } }/bin ''} } @@ -125,37 +145,12 @@ lib.mkIf cfg.enable { environment.systemPackages = [ pkgs.dovecot_pigeonhole ]; - systemd.services.dovecot2 = { + /* + systemd.services.dovecot2 = { wants = [ "acme-finished-${cfg.fqdn}.target" ]; after = [ "acme-finished-${cfg.fqdn}.target" ]; - - preStart = lib.mkIf cfg.spam.enable - (lib.mkAfter - (lib.concatStrings - (lib.mapAttrsToList - (name: content: '' - cp ${pkgs.writeText name content} /var/lib/dovecot/sieve/${name} - '') - { - "learn-spam.sieve" = '' - require ["vnd.dovecot.pipe", "copy", "imapsieve"]; - pipe :copy "rspamc" ["learn_spam"]; - ''; - "learn-ham.sieve" = '' - require ["vnd.dovecot.pipe", "copy", "imapsieve", "environment", "variables"]; - - if environment :matches "imap.mailbox" "*" { - set "mailbox" "''${1}"; - } - - if string "''${mailbox}" "Trash" { - stop; - } - - pipe :copy "rspamc" ["learn_ham"]; - ''; - }))); - }; + }; + */ networking.firewall.allowedTCPPorts = [ 143 # IMAP diff --git a/modules/mailserver/postfix.nix b/modules/mailserver/postfix.nix index 1bd0079..1209fb0 100644 --- a/modules/mailserver/postfix.nix +++ b/modules/mailserver/postfix.nix @@ -38,75 +38,81 @@ lib.mkIf cfg.enable { services.postfix = { enable = true; - inherit (cfg) relayPort; - enableSubmission = false; # plain/STARTTLS (latter is forced in submissionOptions) enableSubmissions = true; # submission with implicit TLS (TCP/465) - hostname = cfg.fqdn; - networksStyle = "host"; + settings = { + main = { + smtpd_tls_chain_files = [ + "${cfg.certDir}/key.pem" + "${cfg.certDir}/fullchain.pem" + ]; + recipient_delimiter = "+"; + myhostname = cfg.fqdn; + mynetworks_style = "host"; - settings.main.smtpd_tls_chain_files = [ - "${cfg.certDir}/key.pem" - "${cfg.certDir}/fullchain.pem" - ]; + # General + smtpd_banner = "${cfg.fqdn} ESMTP"; + disable_vrfy_command = true; # disable check if mailbox exists + enable_long_queue_ids = true; # better for debugging + strict_rfc821_envelopes = true; # only accept properly formatted envelope + message_size_limit = cfg.messageSizeLimit; - recipientDelimiter = "+"; + virtual_mailbox_domains = listToString (map (x: x.domain) cfg.domains); + virtual_mailbox_maps = "hash:/var/lib/postfix/conf/valiases"; + virtual_alias_maps = "hash:/var/lib/postfix/conf/valiases"; + virtual_transport = "lmtp:unix:/run/dovecot2/dovecot-lmtp"; + + smtpd_recipient_restrictions = listToString [ + "reject_non_fqdn_recipient" + "reject_unknown_recipient_domain" + "reject_unverified_recipient" + ]; + + smtpd_client_restrictions = listToString [ + "reject_unknown_client_hostname" + ]; + + smtpd_sender_restrictions = listToString [ + "reject_non_fqdn_sender" + "reject_unknown_sender_domain" + ]; + + # generated 2021-02-04, Mozilla Guideline v5.6, Postfix 3.5.6, OpenSSL 1.1.1i, intermediate configuration + # https://ssl-config.mozilla.org/#server=postfix&version=3.5.6&config=intermediate&openssl=1.1.1i&guideline=5.6 + smtpd_tls_security_level = "may"; + smtpd_tls_auth_only = "yes"; + smtpd_tls_mandatory_protocols = "!SSLv2, !SSLv3, !TLSv1, !TLSv1.1"; + smtpd_tls_protocols = "!SSLv2, !SSLv3, !TLSv1, !TLSv1.1"; + smtpd_tls_mandatory_ciphers = "medium"; + smtpd_tls_loglevel = "1"; + + tls_medium_cipherlist = listToString [ + "ECDHE-ECDSA-AES128-GCM-SHA256" + "ECDHE-RSA-AES128-GCM-SHA256" + "ECDHE-ECDSA-AES256-GCM-SHA384" + "ECDHE-RSA-AES256-GCM-SHA384" + "ECDHE-ECDSA-CHACHA20-POLY1305" + "ECDHE-RSA-CHACHA20-POLY1305" + "DHE-RSA-AES128-GCM-SHA256" + "DHE-RSA-AES256-GCM-SHA384" + ]; + tls_preempt_cipherlist = "no"; + }; + master = { + submission-header-cleanup = { + private = false; + maxproc = 0; + command = "cleanup"; + args = [ "-o" "header_checks=pcre:${submissionHeaderCleanupRules}" ]; + }; + }; + }; mapFiles = { inherit valiases; }; - config = { - # General - smtpd_banner = "${cfg.fqdn} ESMTP"; - disable_vrfy_command = true; # disable check if mailbox exists - enable_long_queue_ids = true; # better for debugging - strict_rfc821_envelopes = true; # only accept properly formatted envelope - message_size_limit = toString cfg.messageSizeLimit; - - virtual_mailbox_domains = listToString (map (x: x.domain) cfg.domains); - virtual_mailbox_maps = "hash:/var/lib/postfix/conf/valiases"; - virtual_alias_maps = "hash:/var/lib/postfix/conf/valiases"; - virtual_transport = "lmtp:unix:/run/dovecot2/dovecot-lmtp"; - - smtpd_recipient_restrictions = listToString [ - "reject_non_fqdn_recipient" - "reject_unknown_recipient_domain" - "reject_unverified_recipient" - ]; - - smtpd_client_restrictions = listToString [ - "reject_unknown_client_hostname" - ]; - - smtpd_sender_restrictions = listToString [ - "reject_non_fqdn_sender" - "reject_unknown_sender_domain" - ]; - - # generated 2021-02-04, Mozilla Guideline v5.6, Postfix 3.5.6, OpenSSL 1.1.1i, intermediate configuration - # https://ssl-config.mozilla.org/#server=postfix&version=3.5.6&config=intermediate&openssl=1.1.1i&guideline=5.6 - smtpd_tls_security_level = "may"; - smtpd_tls_auth_only = "yes"; - smtpd_tls_mandatory_protocols = "!SSLv2, !SSLv3, !TLSv1, !TLSv1.1"; - smtpd_tls_protocols = "!SSLv2, !SSLv3, !TLSv1, !TLSv1.1"; - smtpd_tls_mandatory_ciphers = "medium"; - smtpd_tls_loglevel = "1"; - - tls_medium_cipherlist = listToString [ - "ECDHE-ECDSA-AES128-GCM-SHA256" - "ECDHE-RSA-AES128-GCM-SHA256" - "ECDHE-ECDSA-AES256-GCM-SHA384" - "ECDHE-RSA-AES256-GCM-SHA384" - "ECDHE-ECDSA-CHACHA20-POLY1305" - "ECDHE-RSA-CHACHA20-POLY1305" - "DHE-RSA-AES128-GCM-SHA256" - "DHE-RSA-AES256-GCM-SHA384" - ]; - tls_preempt_cipherlist = "no"; - }; - # plain/STARTTLS (forced with smtpd_tls_security_level) submissionOptions = { smtpd_tls_security_level = "encrypt"; @@ -132,15 +138,6 @@ lib.mkIf cfg.enable { }; # implicit TLS submissionsOptions = config.services.postfix.submissionOptions; - - masterConfig = { - submission-header-cleanup = { - private = false; - maxproc = 0; - command = "cleanup"; - args = [ "-o" "header_checks=pcre:${submissionHeaderCleanupRules}" ]; - }; - }; }; networking.firewall.allowedTCPPorts = [