From 5dcbb4e2dcf2b771fcc172f161fbddf7996bdd9c Mon Sep 17 00:00:00 2001 From: Daniel Frank Date: Thu, 12 Aug 2021 18:32:28 +0200 Subject: [PATCH] Migrate the mail config to the nixos module --- configuration.nix | 1 - dovecot.nix | 164 ---------------------------------------------- mailserver.nix | 24 +++++-- postfix.nix | 89 ------------------------- postfixadmin.nix | 101 ---------------------------- roundcube.nix | 136 -------------------------------------- rspamd.nix | 68 ------------------- 7 files changed, 19 insertions(+), 564 deletions(-) delete mode 100644 dovecot.nix delete mode 100644 postfix.nix delete mode 100644 postfixadmin.nix delete mode 100644 roundcube.nix delete mode 100644 rspamd.nix diff --git a/configuration.nix b/configuration.nix index 935a42b..4700fe6 100644 --- a/configuration.nix +++ b/configuration.nix @@ -10,7 +10,6 @@ ./hardware-configuration.nix ./acme.nix ./sshusers.nix - ./variables.nix ./mailserver.nix ./borgbackup.nix ./nginx.nix diff --git a/dovecot.nix b/dovecot.nix deleted file mode 100644 index 44cacf5..0000000 --- a/dovecot.nix +++ /dev/null @@ -1,164 +0,0 @@ -{ config, lib, pkgs, ... }: - -let - dovecotSQL = pkgs.writeText "dovecot-sql.conf" '' - driver = sqlite - connect = ${config.variables.pfadminDataDir}/postfixadmin.db - password_query = SELECT username AS user, password FROM mailbox WHERE username = '%Lu' AND active='1' - user_query = SELECT username AS user FROM mailbox WHERE username = '%Lu' AND active='1' - ''; - dovecotConfSSL = pkgs.writeText "dovecot.conf" '' - ${lib.optionalString (config.variables.useSSL) '' - ssl = yes - ssl_cert = /var/lib/dovecot/ssl-keys.conf - chown root:root /var/lib/dovecot/ssl-keys.conf - chmod 400 /var/lib/dovecot/ssl-keys.conf - ''; - }; -} diff --git a/mailserver.nix b/mailserver.nix index e3fcf10..062e146 100644 --- a/mailserver.nix +++ b/mailserver.nix @@ -1,14 +1,28 @@ { config, pkgs, ... }: +let mymailserver = (import {}).pkgs.fetchgit { + url = "https://codeberg.org/tokudan/nixos-mailserver.git"; + rev = "15c419d488d1f4148f268d62fce0975f5a88a464"; + sha256 = "111xjmcvr7gq4406yxdj87wvi8psq3dhb7shkdsj5d4bdr9kr13q"; + }; +in + { # Import some configuration as they are too long to be easily readable here imports = [ - ./dovecot.nix - ./postfix.nix - ./postfixadmin.nix - ./roundcube.nix - ./rspamd.nix + #./dovecot.nix + #./postfix.nix + #./postfixadmin.nix + #./roundcube.nix + #./rspamd.nix + "${mymailserver}/default.nix" ]; + networking.domain = "hamburg.freifunk.net"; + services.mymailserver = { + enable = true; + adminAddress = "kontakt@hamburg.freifunk.net"; + mailFQDN = "mail2.hamburg.freifunk.net"; + }; users.groups."${config.variables.vmailGroup}" = { gid = config.variables.vmailGID; }; users.users."${config.variables.vmailUser}" = { uid = config.variables.vmailUID; diff --git a/postfix.nix b/postfix.nix deleted file mode 100644 index c9fe644..0000000 --- a/postfix.nix +++ /dev/null @@ -1,89 +0,0 @@ -{ config, lib, pkgs, ... }: - -let - submission_header_cleanup_regex = pkgs.writeText "submission_header_cleanup_regex" '' - /^Received:.*by ${config.variables.myFQDN} \(Postfix/ IGNORE - ''; - pfvirtual_mailbox_domains = pkgs.writeText "virtual_mailbox_domains.cf" '' - dbpath = ${config.variables.pfadminDataDir}/postfixadmin.db - query = SELECT domain FROM domain WHERE domain='%s' AND active = '1' - ''; - pfvirtual_alias_maps = pkgs.writeText "virtual_alias_maps.cf" '' - dbpath = ${config.variables.pfadminDataDir}/postfixadmin.db - query = SELECT goto FROM alias WHERE address='%s' AND active = '1' - ''; - pfvirtual_alias_domain_maps = pkgs.writeText "virtual_alias_domain_maps.cf" '' - dbpath = ${config.variables.pfadminDataDir}/postfixadmin.db - query = SELECT goto FROM alias,alias_domain WHERE alias_domain.alias_domain = '%d' and alias.address = ('%u' || '@' || alias_domain.target_domain) AND alias.active = 1 AND alias_domain.active='1' - ''; - pfvirtual_alias_domain_catchall_maps = pkgs.writeText "virtual_alias_domain_catchall_maps.cf" '' - dbpath = ${config.variables.pfadminDataDir}/postfixadmin.db - query = SELECT goto FROM alias,alias_domain WHERE alias_domain.alias_domain = '%d' and alias.address = ('@' || alias_domain.target_domain) AND alias.active = 1 AND alias_domain.active='1' - ''; - pfvirtual_mailbox_maps = pkgs.writeText "virtual_mailbox_maps.cf" '' - dbpath = ${config.variables.pfadminDataDir}/postfixadmin.db - query = SELECT maildir FROM mailbox WHERE username='%s' AND active = '1' - ''; - pfvirtual_alias_domain_mailbox_maps = pkgs.writeText "virtual_alias_domain_mailbox_maps.cf" '' - dbpath = ${config.variables.pfadminDataDir}/postfixadmin.db - query = SELECT maildir FROM mailbox,alias_domain WHERE alias_domain.alias_domain = '%d' and mailbox.username = ('%u' || '@' || alias_domain.target_domain) AND mailbox.active = 1 AND alias_domain.active='1' - ''; -in -{ - # Configure Postfix to support SQLite - nixpkgs.config.packageOverrides = pkgs: { postfix = pkgs.postfix.override { withSQLite = true; }; }; - # SSL/TLS specific configuration - security = lib.mkIf config.variables.useSSL { - # Configure the certificates... - acme.certs."postfix.${config.variables.myFQDN}" = { - domain = "${config.variables.myFQDN}"; - group = "certs"; - postRun = "systemctl restart postfix.service"; - # cheat by getting some settings from another certificate configured through nginx. - webroot = config.security.acme.certs."${config.variables.myFQDN}".webroot; - }; - }; - systemd = lib.mkIf config.variables.useSSL { - # Make sure at least the self-signed certs are available before trying to start postfix - services.postfix.after = [ "acme-selfsigned-certificates.target" ]; - }; - - # Setup Postfix - networking.firewall.allowedTCPPorts = [ 25 587 ]; - services.postfix = { - enable = true; - enableSmtp = true; - enableSubmission = true; - config = { - mydestination = ""; - myhostname = config.variables.myFQDN; - mynetworks_style = "host"; - recipient_delimiter = "+"; - relay_domains = ""; - smtpd_milters = "unix:${config.variables.rspamdMilterSocket}"; - non_smtpd_milters = "unix:${config.variables.rspamdMilterSocket}"; - smtpd_sasl_path = config.variables.dovecotAuthSocket; - smtpd_sasl_type = "dovecot"; - smtpd_tls_auth_only = "yes"; - smtpd_tls_chain_files = lib.mkIf config.variables.useSSL "/var/lib/acme/postfix.${config.variables.myFQDN}/full.pem"; - smtpd_tls_loglevel = "1"; - smtpd_tls_received_header = "yes"; - smtpd_tls_security_level = "may"; - smtp_tls_loglevel = "1"; - smtp_tls_security_level = "may"; - virtual_alias_maps = "proxy:sqlite:${pfvirtual_alias_maps}, proxy:sqlite:${pfvirtual_alias_domain_maps}, proxy:sqlite:${pfvirtual_alias_domain_catchall_maps}"; - virtual_mailbox_domains = "proxy:sqlite:${pfvirtual_mailbox_domains}"; - virtual_mailbox_maps = "proxy:sqlite:${pfvirtual_mailbox_maps}, proxy:sqlite:${pfvirtual_alias_domain_mailbox_maps}"; - virtual_transport = "lmtp:unix:${config.variables.dovecotLmtpSocket}"; - }; - masterConfig.submission.args = [ "-o" "cleanup_service_name=submission_cleanup" ]; - masterConfig."submission_cleanup" = { - command = "cleanup"; - args = [ "-o" "header_checks=regexp:${submission_header_cleanup_regex}" ]; - private = false; - maxproc = 0; - }; - rootAlias = config.variables.mailAdmin; - postmasterAlias = config.variables.mailAdmin; - }; -} diff --git a/postfixadmin.nix b/postfixadmin.nix deleted file mode 100644 index b4dd9d3..0000000 --- a/postfixadmin.nix +++ /dev/null @@ -1,101 +0,0 @@ -{ config, lib, pkgs, ... }: - -let - phppoolName = "postfixadmin_pool"; - pfaGroup = config.variables.pfaGroup; - pfaUser = config.variables.pfaUser; - postfixadminpkg = config.variables.postfixadminpkg; - pfadminDataDir = config.variables.pfadminDataDir; - cacheDir = config.variables.postfixadminpkgCacheDir; - phpfpmHostPort = config.variables.pfaPhpfpmHostPort; -in -{ - # Setup the user and group - users.groups."${pfaGroup}" = { }; - users.users."${pfaUser}" = { - isSystemUser = true; - group = "${pfaGroup}"; - extraGroups = [ "dovecot2" ]; - description = "PHP User for postfixadmin"; - }; - - # Setup nginx - networking.firewall.allowedTCPPorts = [ 80 443 ]; - services.nginx.enable = true; - services.nginx.virtualHosts."${config.variables.pfaDomain}" = { - forceSSL = config.variables.useSSL; - enableACME = config.variables.useSSL; - root = "${postfixadminpkg}/public"; - extraConfig = '' - charset utf-8; - - etag off; - add_header etag "\"${builtins.substring 11 32 postfixadminpkg}\""; - add_header Permissions-Policy "interest-cohort=()" always; - - index index.php; - - location ~* \.php$ { - add_header Permissions-Policy "interest-cohort=()" always; - # Zero-day exploit defense. - # http://forum.nginx.org/read.php?2,88845,page=3 - # Won't work properly (404 error) if the file is not stored on this - # server, which is entirely possible with php-fpm/php-fcgi. - # Comment the 'try_files' line out if you set up php-fpm/php-fcgi on - # another machine. And then cross your fingers that you won't get hacked. - try_files $uri =404; - # NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini - fastcgi_split_path_info ^(.+\.php)(/.+)$; - # With php5-cgi alone: - fastcgi_pass unix:${config.services.phpfpm.pools."${phppoolName}".socket}; - fastcgi_index index.php; - fastcgi_param GATEWAY_INTERFACE CGI/1.1; - fastcgi_param SERVER_SOFTWARE nginx; - fastcgi_param QUERY_STRING $query_string; - fastcgi_param REQUEST_METHOD $request_method; - fastcgi_param CONTENT_TYPE $content_type; - fastcgi_param CONTENT_LENGTH $content_length; - fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; - fastcgi_param SCRIPT_NAME $fastcgi_script_name; - fastcgi_param REQUEST_URI $request_uri; - fastcgi_param DOCUMENT_URI $document_uri; - fastcgi_param DOCUMENT_ROOT $document_root; - fastcgi_param SERVER_PROTOCOL $server_protocol; - fastcgi_param REMOTE_ADDR $remote_addr; - fastcgi_param REMOTE_PORT $remote_port; - fastcgi_param SERVER_ADDR $server_addr; - fastcgi_param SERVER_PORT $server_port; - fastcgi_param SERVER_NAME $server_name; - fastcgi_param HTTP_PROXY ""; - } - ''; - }; - systemd.services."postfixadmin-setup" = { - serviceConfig.Type = "oneshot"; - wantedBy = [ "multi-user.target" ]; - script = '' - # Setup the data directory with the database and the cache directory - mkdir -p ${pfadminDataDir} - chmod -c 751 ${pfadminDataDir} - chown -c ${pfaUser}:${pfaGroup} ${pfadminDataDir} - - mkdir -p ${cacheDir}/templates_c - chown -Rc ${pfaUser}:${pfaGroup} ${cacheDir}/templates_c - chmod -Rc 751 ${cacheDir}/templates_c - ''; - }; - services.phpfpm.pools."${phppoolName}" = { - user = "${pfaUser}"; - group = "${pfaGroup}"; - settings = { - "pm" = "dynamic"; - "pm.max_children" = 75; - "pm.min_spare_servers" = 5; - "pm.max_spare_servers" = 20; - "pm.max_requests" = 10; - "catch_workers_output" = 1; - "listen.owner" = "nginx"; - "listen.group" = "nginx"; - }; - }; -} diff --git a/roundcube.nix b/roundcube.nix deleted file mode 100644 index c466ef8..0000000 --- a/roundcube.nix +++ /dev/null @@ -1,136 +0,0 @@ -{ config, lib, pkgs, ... }: - -let - poolName = "roundcube_pool"; - - roundcube = (pkgs.callPackage ./pkg-roundcube.nix { - conf = pkgs.writeText "roundcube-config.inc.php" '' - /dev/null | ${pkgs.coreutils}/bin/base64 > "${config.variables.roundcubeDataDir}/des_key" - chown -c "${config.variables.roundcubeUser}":${config.variables.roundcubeGroup} "${config.variables.roundcubeDataDir}/des_key" - chmod -c 400 "${config.variables.roundcubeDataDir}/des_key" - if [ -s "${config.variables.roundcubeDataDir}/roundcube.sqlite" ]; then - # Just go ahead and remove the sessions, the key to decrypt them has just been destroyed anyway. - ${pkgs.sqlite}/bin/sqlite3 "${config.variables.roundcubeDataDir}/roundcube.sqlite" "DELETE FROM session;" - fi - ''; - }; - services.phpfpm.pools."${poolName}" = { - user = "${config.variables.roundcubeUser}"; - group = "${config.variables.roundcubeUser}"; - settings = { - "pm" = "dynamic"; - "pm.max_children" = 75; - "pm.min_spare_servers" = 5; - "pm.max_spare_servers" = 20; - "pm.max_requests" = 10; - "catch_workers_output" = 1; - "listen.owner" = "nginx"; - "listen.group" = "nginx"; - }; - }; - users.extraUsers."${config.variables.roundcubeUser}" = { }; - users.extraGroups."${config.variables.roundcubeUser}" = { }; - users.groups."${config.variables.roundcubeGroup}" = { }; - users.users."${config.variables.roundcubeUser}" = { - isSystemUser = true; - group = "${config.variables.roundcubeGroup}"; - description = "PHP User for roundcube"; - }; -} diff --git a/rspamd.nix b/rspamd.nix deleted file mode 100644 index 53dce38..0000000 --- a/rspamd.nix +++ /dev/null @@ -1,68 +0,0 @@ -{ config, lib, pkgs, ... }: - -let - rspamdExtraConfig = pkgs.writeText "rspamd-extra.conf" '' - secure_ip = [::1] - options { - filters: "chartable,dkim,dkim_signing,spf,surbl,regexp,fuzzy_check" - } - milter_headers { - extended_spam_headers = true; - } - classifier { - bayes { - autolearn = true; - } - } - dkim_signing { - path = "/var/lib/rspamd/dkim/$domain.$selector.key"; - check_pubkey = true; - } - ''; -in -{ - #networking.firewall.allowedTCPPorts = [ 110 143 993 995 ]; - environment.systemPackages = [ - (pkgs.writeShellScriptBin "dkim-generate" '' - if [ $# -ne 1 ]; then - echo Usage: dkim-generate DOMAIN >&2 - exit 1 - fi - rspamd=${pkgs.rspamd}/bin/rspamadm - mkdir -p /var/lib/rspamd/dkim - $rspamd dkim_keygen -b 2048 -d "$1" -s dkim | ${pkgs.gawk}/bin/awk '/^-/ {KEY= ! KEY; print; next} KEY {print} !KEY {print > "/dev/stderr"}' >/var/lib/rspamd/dkim/"$1".dkim.key 2>/var/lib/rspamd/dkim/"$1".dkim.dns - ls -l /var/lib/rspamd/dkim/"$1".dkim.key /var/lib/rspamd/dkim/"$1".dkim.dns - '') ]; - services.rspamd = { - enable = true; - # Just shove our own configuration up rspamd's rear end with high prio as the default configuration structure is a mess - extraConfig = '' - .include(try=true,priority=10,duplicate=merge) "${rspamdExtraConfig}" - ''; - workers = { - controller = { - enable = true; - extraConfig = '' - secure_ip = [::1] - ''; - bindSockets = [ - "[::1]:11334" - { mode = "0666"; owner = config.variables.vmailUser; socket = "/run/rspamd/worker-controller.socket"; } - ]; - }; - rspamd_proxy = { - enable = true; - type = "rspamd_proxy"; - count = 5; # TODO: match with postfix limits - extraConfig = '' - upstream "local" { - self_scan = yes; # Enable self-scan - } - ''; - bindSockets = [ - { socket = config.variables.rspamdMilterSocket; mode = "0600"; owner = config.services.postfix.user; group = config.services.rspamd.group; } - ]; - }; - }; - }; -}