From a1aff6b61ce1b4333c780298da275d937aeabb0a Mon Sep 17 00:00:00 2001 From: Robin Raymond Date: Fri, 22 Dec 2017 11:17:39 +0100 Subject: [PATCH] playing around with opensmtp --- default.nix | 8 +-- mail-server/dovecot.nix | 14 +--- mail-server/opensmtpd.nix | 146 ++++++++++++++++++++++++++++++++++++++ mail-server/systemd.nix | 12 +++- tests/intern.nix | 1 + 5 files changed, 164 insertions(+), 17 deletions(-) create mode 100644 mail-server/opensmtpd.nix diff --git a/default.nix b/default.nix index 5854226..7958d74 100644 --- a/default.nix +++ b/default.nix @@ -167,7 +167,7 @@ in vmailUserName = mkOption { type = types.str; - default = "virtualMail"; + default = "vmail"; description = '' The user name and group name of the user that owns the directory where all the mail is stored. @@ -176,7 +176,7 @@ in vmailGroupName = mkOption { type = types.str; - default = "virtualMail"; + default = "vmail"; description = '' The user name and group name of the user that owns the directory where all the mail is stored. @@ -331,8 +331,8 @@ in ./mail-server/networking.nix ./mail-server/systemd.nix ./mail-server/dovecot.nix - ./mail-server/postfix.nix - ./mail-server/rmilter.nix + ./mail-server/opensmtpd.nix + # ./mail-server/rmilter.nix ./mail-server/nginx.nix ]; diff --git a/mail-server/dovecot.nix b/mail-server/dovecot.nix index 89249b5..0b51600 100644 --- a/mail-server/dovecot.nix +++ b/mail-server/dovecot.nix @@ -63,10 +63,10 @@ in ssl = required service lmtp { - unix_listener /var/lib/postfix/queue/private/dovecot-lmtp { - group = postfix + unix_listener /run/dovecot/lmtp { + group = ${vmailGroupName} mode = 0600 - user = postfix # TODO: < make variable + user = ${vmailUserName} } } @@ -74,14 +74,6 @@ in mail_plugins = $mail_plugins sieve } - service auth { - unix_listener /var/lib/postfix/queue/private/auth { - mode = 0660 - user = postfix # TODO: < make variable - group = postfix # TODO: < make variable - } - } - auth_mechanisms = plain login namespace inbox { diff --git a/mail-server/opensmtpd.nix b/mail-server/opensmtpd.nix new file mode 100644 index 0000000..497eb0b --- /dev/null +++ b/mail-server/opensmtpd.nix @@ -0,0 +1,146 @@ +# nixos-mailserver: a simple mail server +# Copyright (C) 2016-2017 Robin Raymond +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see + +{ config, pkgs, lib, ... }: + +with (import ./common.nix { inherit config; }); + +let + inherit (lib.strings) concatStringsSep; + cfg = config.mailserver; + + # valiases_postfix :: [ String ] + valiases_postfix = lib.flatten (lib.mapAttrsToList + (name: value: + let to = name; + in map (from: "${from} ${to}") value.aliases) + cfg.loginAccounts); + + vmailMaps = lib.flatten (lib.mapAttrsToList + (name: value: "${name} ${cfg.vmailUserName}") cfg.loginAccounts); + + # catchAllPostfix :: [ String ] + catchAllPostfix = lib.flatten (lib.mapAttrsToList + (name: value: + let to = name; + in map (from: "@${from} ${to}") value.catchAll) + cfg.loginAccounts); + + # extra_valiases_postfix :: [ String ] + # TODO: Remove virtualAliases when deprecated -> removed + extra_valiases_postfix = (map + (from: + let to = cfg.virtualAliases.${from}; + in "${from} ${to}") + (builtins.attrNames cfg.virtualAliases)) + ++ + (map + (from: + let to = cfg.extraVirtualAliases.${from}; + in "${from} ${to}") + (builtins.attrNames cfg.extraVirtualAliases)); + + # all_valiases_postfix :: [ String ] + all_valiases_postfix = valiases_postfix ++ extra_valiases_postfix ++ catchAllPostfix ++ vmailMaps; + + # accountToIdentity :: User -> String + accountToIdentity = account: "${account.name} ${account.name}"; + + # vaccounts_identity :: [ String ] + vaccounts_identity = map accountToIdentity (lib.attrValues cfg.loginAccounts); + + # valiases_file :: Path + valiases_file = builtins.toFile "valias" + (lib.concatStringsSep "\n" all_valiases_postfix); + + # vhosts_file :: Path + vhosts_file = builtins.toFile "vhosts" (concatStringsSep "\n" cfg.domains); + + passwdList = lib.flatten (lib.mapAttrsToList (name : value: + "${name}:${value.hashedPassword}:5000:5000::/var/vmail/:/run/current-system/sw/bin/nologin") + cfg.loginAccounts); + passwd = lib.concatStringsSep "\n" passwdList; + + + example = + '' + user1@example.com:$6$IsXn9Xe2kUTPETVl$Z.gkkqpwi95/ZsL/FXZaAjMjdv03m5jae6v8Pv7aaNnzdzNd01nbgt3HtKnaS10hZTbXgumqdQyTU0m1wkr76.:5000:5000::/var/vmail:/run/current-system/sw/bin/nologin + ''; + + passwd_file = builtins.toFile "passwd" passwd; + + # vaccounts_file :: Path + # see + # https://blog.grimneko.de/2011/12/24/a-bunch-of-tips-for-improving-your-postfix-setup/ + # for details on how this file looks. By using the same file as valiases, + # every alias is owned (uniquely) by its user. We have to add the users own + # address though + vaccounts_file = builtins.toFile "vaccounts" (lib.concatStringsSep "\n" + (vaccounts_identity ++ all_valiases_postfix)); + + submissionHeaderCleanupRules = pkgs.writeText "submission_header_cleanup_rules" '' + # Removes sensitive headers from mails handed in via the submission port. + # See https://thomas-leister.de/mailserver-debian-stretch/ + # Uses "pcre" style regex. + + /^Received:/ IGNORE + /^X-Originating-IP:/ IGNORE + /^X-Mailer:/ IGNORE + /^User-Agent:/ IGNORE + /^X-Enigmail:/ IGNORE + ''; +in +{ + config = with cfg; lib.mkIf enable { + + services.opensmtpd = { + enable = true; + procPackages = [ pkgs.opensmtpd-extras ]; + extraServerArgs = [ "-v" ]; + serverConfiguration = + '' + # pki setup + pki ${fqdn} certificate "${certificatePath}" + pki ${fqdn} key "${keyPath}" + + # tables setup + # table aliases file:/etc/mail/aliases + table domains file:${vhosts_file} + table passwd passwd:${passwd_file} + table virtuals file:${valiases_file} + + # # listen ports setup + listen on 0.0.0.0 port 25 tls pki ${fqdn} + listen on 0.0.0.0 port 587 tls-require pki ${fqdn} auth received-auth + + # allow local messages + accept from any for domain virtual deliver to lmtp "/run/dovecot/lmtp" rcpt-to + + # DKIM + listen on lo hostname ${fqdn} + listen on lo port 10028 tag DKIM hostname ${fqdn} + + accept tagged DKIM \ + for any \ + relay \ + hostname ${fqdn} + accept from local \ + for any \ + relay via smtp://127.0.0.1:10027 + ''; + }; + }; +} diff --git a/mail-server/systemd.nix b/mail-server/systemd.nix index 0f98b7d..e13029a 100644 --- a/mail-server/systemd.nix +++ b/mail-server/systemd.nix @@ -68,13 +68,21 @@ in { config = with cfg; lib.mkIf enable { # Make sure postfix gets started first, so that the certificates are in place - systemd.services.dovecot2.after = [ "postfix.service" ]; + systemd.services.dovecot2 = { + after = [ "postfix.service" ]; + preStart = + '' + mkdir -p '/run/dovecot/' + chown 'dovecot2:dovecot2' '/run/dovecot' + ''; + }; # Create certificates and maildir folder - systemd.services.postfix = { + systemd.services.opensmtpd = { after = (if (certificateScheme == 3) then [ "nginx.service" ] else []); preStart = '' + mkdir -p /var/empty # Create mail directory and set permissions. See # . mkdir -p "${mailDirectory}" diff --git a/tests/intern.nix b/tests/intern.nix index 3d49c15..3bdacb8 100644 --- a/tests/intern.nix +++ b/tests/intern.nix @@ -54,6 +54,7 @@ import { subtest "vmail gid is set correctly", sub { $machine->succeed("getent group vmail | grep 5000"); + $machine->succeed("systemctl status opensmtpd.service -l >&2"); }; '';