Merge branch 'certmgmt-next' into 'master'

Switch to NixOS ACME module for certificate management

Closes #256 and #267

See merge request simple-nixos-mailserver/nixos-mailserver!457
This commit is contained in:
Martin Weinelt
2025-12-19 01:58:52 +00:00
23 changed files with 224 additions and 292 deletions
+48 -100
View File
@@ -32,7 +32,6 @@ let
mkRemovedOptionModule
mkRenamedOptionModule
types
warn
;
cfg = config.mailserver;
@@ -131,20 +130,6 @@ in
description = "The domains that this mail server serves.";
};
certificateDomains = mkOption {
type = types.listOf types.str;
example = [
"imap.example.com"
"pop3.example.com"
];
default = [ ];
description = ''
({option}`mailserver.certificateScheme` == `acme-nginx`)
Secondary domains and subdomains for which it is necessary to generate a certificate.
'';
};
messageSizeLimit = mkOption {
type = types.int;
example = 52428800;
@@ -167,12 +152,12 @@ in
hashedPassword = mkOption {
type = with types; nullOr str;
default = null;
example = "$6$evQJs5CFQyPAW09S$Cn99Y8.QjZ2IBnSu4qf1vBxDRWkaIZWOtmu1Ddsm3.H3CFpeVc0JU4llIq8HQXgeatvYhh5O33eWG3TSpjzu6/";
example = "$y$j9T$vfGrwkAaXCjCEWtVNMQck1$383uIXQmn2z0hnmVAA8kwFQmjNj78.nYbvWeyNLIaP1";
description = ''
The user's hashed password. Use `mkpasswd` as follows
```
nix-shell -p mkpasswd --run 'mkpasswd -sm bcrypt'
nix-shell -p mkpasswd --run 'mkpasswd -s'
```
Warning: this is stored in plaintext in the Nix store!
@@ -188,7 +173,7 @@ in
A file containing the user's hashed password. Use `mkpasswd` as follows
```
nix-shell -p mkpasswd --run 'mkpasswd -sm bcrypt'
nix-shell -p mkpasswd --run 'mkpasswd -s'
```
'';
};
@@ -212,7 +197,8 @@ in
example = [ ''/^tom\..*@domain\.com$/'' ];
default = [ ];
description = ''
Same as {option}`mailserver.aliases` but using PCRE (Perl compatible regex).
Same as {option}`mailserver.loginAccounts.<name>.aliases` but
using PCRE (Perl compatible regex).
'';
};
@@ -290,10 +276,10 @@ in
);
example = {
user1 = {
hashedPassword = "$6$evQJs5CFQyPAW09S$Cn99Y8.QjZ2IBnSu4qf1vBxDRWkaIZWOtmu1Ddsm3.H3CFpeVc0JU4llIq8HQXgeatvYhh5O33eWG3TSpjzu6/";
hashedPassword = "$y$j9T$y6eZ1o.IvVNfdGMAsUEvh1$6K/llP52uw2iDh4iSwtAn54/JYy7FzCcoCHmjmx00H5";
};
user2 = {
hashedPassword = "$6$oE0ZNv2n7Vk9gOf$9xcZWCCLGdMflIfuA0vR1Q1Xblw6RZqPrP94mEit2/81/7AKj2bqUai5yPyWE.QYPyv6wLMHZvjw3Rlg7yTCD/";
hashedPassword = "$y$j9T$hZ.ubq0M897Hw.znxnGG9.$14EJBoOwbwKeWt.W4vpnBPEBZC9mYz4fWI9kOCLoZf4";
};
};
description = ''
@@ -302,7 +288,7 @@ in
follows
```
nix-shell -p mkpasswd --run 'mkpasswd -sm bcrypt'
nix-shell -p mkpasswd --run 'mkpasswd -s'
```
'';
default = { };
@@ -788,91 +774,43 @@ in
};
};
certificateScheme =
let
schemes = [
"manual"
"selfsigned"
"acme-nginx"
"acme"
];
translate =
i:
warn
"Setting mailserver.certificateScheme by number is deprecated, please use names instead: 'mailserver.certificateScheme = ${builtins.toString i}' can be replaced by 'mailserver.certificateScheme = \"${
(builtins.elemAt schemes (i - 1))
}\"'."
(builtins.elemAt schemes (i - 1));
in
mkOption {
type =
with types;
coercedTo (enum [
1
2
3
]) translate (enum schemes);
default = "selfsigned";
x509 = {
useACMEHost = mkOption {
type = with types; nullOr str;
default = null;
example = literalExpression "config.mailserver.fqdn";
description = ''
The scheme to use for managing TLS certificates:
Common name used in the relevant `security.acme.certs` configuration.
1. `manual`: you specify locations via {option}`mailserver.certificateFile` and
{option}`mailserver.keyFile` and manually copy certificates there.
2. `selfsigned`: you let the server create new (self-signed) certificates on the fly.
3. `acme-nginx`: you let the server request certificates from [Let's Encrypt](https://letsencrypt.org)
via NixOS' ACME module. By default, this will set up a stripped-down Nginx server for
{option}`mailserver.fqdn` and open port 80. For this to work, the FQDN must be properly
configured to point to your server (see the [setup guide](setup-guide.rst) for more information).
4. `acme`: you already have an ACME certificate set up (for example, you're already running a TLS-enabled
Nginx server on the FQDN). This is better than `manual` because the appropriate services will be reloaded
when the certificate is renewed.
Mutually exclusive with {option}`mailserver.x509.certificateFile` and {option}`mailserver.x509.privateKeyFile`.
'';
};
certificateFile = mkOption {
type = types.path;
example = "/root/mail-server.crt";
description = ''
({option}`mailserver.certificateScheme` == `manual`)
certificateFile = mkOption {
type = with types; nullOr path;
default = null;
example = "/var/keys/certs/fullchain.pem";
description = ''
Path to the signed X509 certificate including intermediate certificates.
Location of the certificate.
'';
};
This is commonly referred to as {file}`fullchain.pem`.
keyFile = mkOption {
type = types.path;
example = "/root/mail-server.key";
description = ''
({option}`mailserver.certificateScheme` == `manual`)
Mutually exclusive with {option}`mailserver.x509.useACMEHost`.
'';
};
Location of the key file.
'';
};
privateKeyFile = mkOption {
type = with types; nullOr str;
default = null;
example = "/var/keys/certs/privkey.pem";
description = ''
Path to the X509 private key.
certificateDirectory = mkOption {
type = types.path;
default = "/var/certs";
description = ''
({option}`mailserver.certificateScheme` == `selfsigned`)
This is commonly referred to as {file}`privkey.pem`.
This is the folder where the self-signed certificate will be created. The name is
hardcoded to "cert-DOMAIN.pem" and "key-DOMAIN.pem" and the
certificate is valid for 10 years.
'';
};
acmeCertificateName = mkOption {
type = types.str;
default = cfg.fqdn;
defaultText = literalExpression "config.mailserver.fqdn";
example = "example.com";
description = ''
({option}`mailserver.certificateScheme` == `acme`)
When the `acme` `certificateScheme` is selected, you can use this option
to override the default certificate name. This is useful if you've
generated a wildcard certificate, for example.
'';
Mutually exclusive with {option}`mailserver.x509.useACMEHost`.
'';
};
};
enableImap = mkOption {
@@ -1247,8 +1185,8 @@ in
if failed port 25 protocol smtp for 5 cycles then restart
check process dovecot with pidfile /var/run/dovecot2/master.pid
start program = "${pkgs.systemd}/bin/systemctl start dovecot2"
stop program = "${pkgs.systemd}/bin/systemctl stop dovecot2"
start program = "${pkgs.systemd}/bin/systemctl start dovecot"
stop program = "${pkgs.systemd}/bin/systemctl stop dovecot"
if failed host ${cfg.fqdn} port 993 type tcpssl sslauto protocol imap for 5 cycles then restart
check process rspamd with matching "rspamd: main process"
@@ -1502,7 +1440,6 @@ in
./mail-server/dovecot.nix
./mail-server/postfix.nix
./mail-server/rspamd.nix
./mail-server/nginx.nix
./mail-server/kresd.nix
(mkRemovedOptionModule [ "mailserver" "policydSPFExtraConfig" ] ''
SPF checking has been migrated to Rspamd, which makes this config redundant. Please look into the rspamd config to migrate your settings.
@@ -1531,5 +1468,16 @@ in
(mkRemovedOptionModule [ "mailserver" "dmarcReporting" "fromName" ] ''
The name in the `FROM` field for DMARC report now uses the `mailserver.systemName`.
'')
(mkRemovedOptionModule [ "mailserver" "certificateDomains" ] ''
Configure `security.acme.certs.''${config.mailserver.fqdn}.extraDomains` instead.
'')
(mkRemovedOptionModule [ "mailserver" "certificateScheme" ] "")
(mkRemovedOptionModule [ "mailserver" "certificateDirectory" ] ''
Automatic creation of self-signed certificates is no longer supported.
'')
(mkRenamedOptionModule [ "mailserver" "acmeCertificateName" ] [ "mailserver" "x509" "useACMEHost" ])
(mkRenamedOptionModule [ "mailserver" "certificateFile" ] [ "mailserver" "x509" "certificateFile" ])
(mkRenamedOptionModule [ "mailserver" "keyFile" ] [ "mailserver" "x509" "privateKeyFile" ])
];
}
+3 -3
View File
@@ -45,11 +45,11 @@ For remediating this issue the following steps are required:
wcurl https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/-/raw/master/migrations/nixos-mailserver-migration-03.py
chmod +x nixos-mailserver-migration-03.py
2. Stop the ``dovecot2.service``.
2. Stop the ``dovecot.service``.
.. code-block:: bash
systemctl stop dovecot2.service
systemctl stop dovecot.service
3. Create a backup or snapshot of your ``mailserver.mailDirectory``, so you can restore
should anything go wrong.
@@ -101,7 +101,7 @@ This migration is required if you both:
For remediating this issue the following steps are required:
1. Stop ``dovecot2.service``.
1. Stop ``dovecot.service``.
2. Move ``/var/vmail/ldap`` below your ``mailserver.mailDirectory``.
3. Update the ``mailserver.stateVersion`` to ``2``.
+10
View File
@@ -1,6 +1,16 @@
Release Notes
=============
NixOS 26.05
-----------
- Certificate handling was simplified. We recommend setting
:option:`mailserver.x509.useACMEHost` to a ``security.acme.certs``
configuration. If that does not fit your requirements, configure certificate
and private key using :option:`mailserver.x509.certificateFile` and
:option:`mailserver.x509.privateKeyFile` instead. Support for automatic
creation of self-signed certificates has been removed.
NixOS 25.11
-----------
+46
View File
@@ -0,0 +1,46 @@
{
config,
...
}:
{
imports = [
(builtins.fetchTarball {
# Pick a release version you are interested in and set its hash, e.g.
url = "https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/-/archive/nixos-25.11/nixos-mailserver-nixos-25.11.tar.gz";
# To get the sha256 of the nixos-mailserver tarball, we can use the nix-prefetch-url command:
# release="nixos-25.11"; nix-prefetch-url "https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/-/archive/${release}/nixos-mailserver-${release}.tar.gz" --unpack
sha256 = "0000000000000000000000000000000000000000000000000000";
})
];
security.acme = {
acceptTerms = true;
defaults.email = "security@example.com";
certs.${config.mailserver.fqdn} = {
# Further setup required, check the manual:
# https://nixos.org/manual/nixos/stable/#module-security-acme
};
};
mailserver = {
enable = true;
stateVersion = 3;
fqdn = "mail.example.com";
domains = [ "example.com" ];
# reference an existing ACME configuration
x509.useACMEHost = config.mailserver.fqdn;
# A list of all login accounts. To create the password hashes, use
# nix-shell -p mkpasswd --run 'mkpasswd -s'
loginAccounts = {
"user1@example.com" = {
hashedPasswordFile = "/a/file/containing/a/hashed/password";
aliases = [ "postmaster@example.com" ];
};
"user2@example.com" = {
# ...
};
};
};
}
+2 -36
View File
@@ -57,42 +57,8 @@ though there are more possible options (see the `NixOS Mailserver
options documentation <options.html>`_), these should be the most
common ones.
.. code:: nix
{ config, pkgs, ... }: {
imports = [
(builtins.fetchTarball {
# Pick a release version you are interested in and set its hash, e.g.
url = "https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/-/archive/nixos-25.11/nixos-mailserver-nixos-25.11.tar.gz";
# To get the sha256 of the nixos-mailserver tarball, we can use the nix-prefetch-url command:
# release="nixos-25.11"; nix-prefetch-url "https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/-/archive/${release}/nixos-mailserver-${release}.tar.gz" --unpack
sha256 = "0000000000000000000000000000000000000000000000000000";
})
];
mailserver = {
enable = true;
stateVersion = 3;
fqdn = "mail.example.com";
domains = [ "example.com" ];
# A list of all login accounts. To create the password hashes, use
# nix-shell -p mkpasswd --run 'mkpasswd -sm bcrypt'
loginAccounts = {
"user1@example.com" = {
hashedPasswordFile = "/a/file/containing/a/hashed/password";
aliases = ["postmaster@example.com"];
};
"user2@example.com" = { ... };
};
# Use Let's Encrypt certificates. Note that this needs to set up a stripped
# down nginx and opens port 80.
certificateScheme = "acme-nginx";
};
security.acme.acceptTerms = true;
security.acme.defaults.email = "security@example.com";
}
.. literalinclude:: ./setup-example.nix
:language: nix
After a ``nixos-rebuild switch`` your server should be running all
mail components.
+1
View File
@@ -112,6 +112,7 @@
"logo\\.png"
"conf\\.py"
"Makefile"
".*\\.nix"
".*\\.rst"
];
buildInputs = [
+15 -7
View File
@@ -38,6 +38,20 @@ in
assertion = config.mailserver.stateVersion != null;
message = "The `mailserver.stateVersion` option is not set. Check https://nixos-mailserver.readthedocs.io/en/latest/migrations.html to determine the proper value to initialize it at.";
}
{
assertion =
config.mailserver.x509.useACMEHost != null
-> config.mailserver.x509.certificateFile == null && config.mailserver.x509.privateKeyFile == null;
message = "Configuring an ACME certificate (`mailserver.x509.useACMEHost`) is not possible while also passing an existing certificate (`mailserver.x509.certificateFile`, `mailserver.x509.privateKeyFile`).";
}
{
assertion =
config.mailserver.x509.useACMEHost != null
|| (
config.mailserver.x509.certificateFile != null && config.mailserver.x509.privateKeyFile != null
);
message = "Configure either an ACME certificate (`mailserver.x509.useACMEHost`) or pass an existing certificate (`mailserver.x509.certificateFile`, `mailserver.x509.privateKeyFile`).";
}
]
++ lib.optionals config.mailserver.ldap.enable [
{
@@ -57,7 +71,7 @@ in
message = ''
Issue: The dovecot homedir for LDAP users was previously not respecting `mailserver.mailDirectory`.
Remediation:
- Stop the `dovecot2.service`
- Stop the `dovecot.service`
- Move `/var/vmail/ldap` below your `mailserver.mailDirectory`
- Increase the `stateVersion` to 2.
@@ -75,11 +89,5 @@ in
'';
}
]
++ lib.optionals (config.mailserver.certificateScheme != "acme") [
{
assertion = config.mailserver.acmeCertificateName == config.mailserver.fqdn;
message = "When the certificate scheme is not 'acme' (mailserver.certificateScheme != \"acme\"), it is not possible to define mailserver.acmeCertificateName";
}
]
);
}
+12 -20
View File
@@ -24,28 +24,20 @@
let
cfg = config.mailserver;
in
{
# cert :: PATH
certificatePath =
if cfg.certificateScheme == "manual" then
cfg.certificateFile
else if cfg.certificateScheme == "selfsigned" then
"${cfg.certificateDirectory}/cert-${cfg.fqdn}.pem"
else if cfg.certificateScheme == "acme" || cfg.certificateScheme == "acme-nginx" then
"${config.security.acme.certs.${cfg.acmeCertificateName}.directory}/fullchain.pem"
else
throw "unknown certificate scheme";
rec {
withACME = cfg.x509.useACMEHost != null;
# key :: PATH
keyPath =
if cfg.certificateScheme == "manual" then
cfg.keyFile
else if cfg.certificateScheme == "selfsigned" then
"${cfg.certificateDirectory}/key-${cfg.fqdn}.pem"
else if cfg.certificateScheme == "acme" || cfg.certificateScheme == "acme-nginx" then
"${config.security.acme.certs.${cfg.acmeCertificateName}.directory}/key.pem"
x509CertificateFile =
if withACME then
"${config.security.acme.certs.${cfg.x509.useACMEHost}.directory}/fullchain.pem"
else
throw "unknown certificate scheme";
cfg.x509.certificateFile;
x509PrivateKeyFile =
if withACME then
"${config.security.acme.certs.${cfg.x509.useACMEHost}.directory}/key.pem"
else
cfg.x509.privateKeyFile;
passwordFiles =
let
+12 -2
View File
@@ -196,6 +196,12 @@ in
multiple languages are present in the configuration.
'';
security.acme.certs = lib.mkIf withACME {
${cfg.x509.useACMEHost} = {
reloadServices = [ "dovecot.service" ];
};
};
# for sieve-test. Shelling it in on demand usually doesnt' work, as it reads
# the global config and tries to open shared libraries configured in there,
# which are usually not compatible.
@@ -216,8 +222,8 @@ in
mailGroup = cfg.vmailGroupName;
mailUser = cfg.vmailUserName;
mailLocation = dovecotMaildir;
sslServerCert = certificatePath;
sslServerKey = keyPath;
sslServerCert = x509CertificateFile;
sslServerKey = x509PrivateKeyFile;
enableDHE = lib.mkDefault false;
enableLmtp = true;
mailPlugins.globally.enable = lib.optionals cfg.fullTextSearch.enable [
@@ -455,6 +461,10 @@ in
${genPasswdScript}
''
+ (lib.optionalString cfg.ldap.enable setPwdInLdapConfFile);
reloadTriggers = lib.mkIf (!withACME) [
x509CertificateFile
x509PrivateKeyFile
];
};
systemd.services.postfix.restartTriggers = [
+6 -9
View File
@@ -26,14 +26,11 @@ let
in
{
config = lib.mkIf cfg.enable {
environment.systemPackages =
with pkgs;
[
dovecot
openssh
postfix
rspamd
]
++ (if cfg.certificateScheme == "selfsigned" then [ openssl ] else [ ]);
environment.systemPackages = with pkgs; [
dovecot
openssh
postfix
rspamd
];
};
}
+1 -2
View File
@@ -32,8 +32,7 @@ in
++ lib.optional cfg.enableImapSsl 993
++ lib.optional cfg.enablePop3 110
++ lib.optional cfg.enablePop3Ssl 995
++ lib.optional cfg.enableManageSieve 4190
++ lib.optional (cfg.certificateScheme == "acme-nginx") 80;
++ lib.optional cfg.enableManageSieve 4190;
};
};
}
-59
View File
@@ -1,59 +0,0 @@
# nixos-mailserver: a simple mail server
# Copyright (C) 2016-2018 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 <http://www.gnu.org/licenses/>
{
config,
options,
pkgs,
lib,
...
}:
with (import ./common.nix {
inherit
config
options
lib
pkgs
;
});
let
cfg = config.mailserver;
in
{
config =
lib.mkIf (cfg.enable && (cfg.certificateScheme == "acme" || cfg.certificateScheme == "acme-nginx"))
{
services.nginx = lib.mkIf (cfg.certificateScheme == "acme-nginx") {
enable = true;
virtualHosts."${cfg.fqdn}" = {
serverName = cfg.fqdn;
serverAliases = cfg.certificateDomains;
forceSSL = true;
enableACME = true;
};
};
security.acme.certs."${cfg.acmeCertificateName}" = {
extraDomainNames = lib.mkIf (cfg.certificateScheme == "acme") cfg.certificateDomains;
reloadServices = [
"postfix.service"
"dovecot.service"
];
};
};
}
+13 -2
View File
@@ -279,6 +279,17 @@ in
};
};
security.acme.certs = lib.mkIf withACME {
${cfg.x509.useACMEHost} = {
reloadServices = [ "postfix.service" ];
};
};
systemd.services.postfix.reloadTriggers = lib.mkIf (!withACME) [
x509CertificateFile
x509PrivateKeyFile
];
systemd.services.postfix-setup = lib.mkIf cfg.ldap.enable {
preStart = ''
${appendPwdInVirtualMailboxMap}
@@ -364,8 +375,8 @@ in
# The X509 private key followed by the corresponding certificate
smtpd_tls_chain_files = [
"${keyPath}"
"${certificatePath}"
"${x509PrivateKeyFile}"
"${x509CertificateFile}"
];
# TLS for incoming mail is optional
+1
View File
@@ -40,6 +40,7 @@ let
pkgs.writeShellScript "dkim-keygen-${domain}" ''
if [ ! -f "${privateKey}" ]
then
export PATH=${lib.makeBinPath [ pkgs.openssl ]}
${lib.getExe' pkgs.rspamd "rspamadm"} dkim_keygen \
--domain "${domain}" \
--selector "${cfg.dkimSelector}" \
+7 -38
View File
@@ -33,47 +33,16 @@ with (import ./common.nix {
let
cfg = config.mailserver;
certificatesDeps =
if cfg.certificateScheme == "manual" then
[ ]
else if cfg.certificateScheme == "selfsigned" then
[ "mailserver-selfsigned-certificate.service" ]
else
[ "acme-finished-${cfg.fqdn}.target" ];
certificateDeps = lib.optionals withACME [
"acme-order-renew-${cfg.x509.useACMEHost}.service"
];
in
{
config = lib.mkIf cfg.enable {
# Create self signed certificate
systemd.services.mailserver-selfsigned-certificate =
lib.mkIf (cfg.certificateScheme == "selfsigned")
{
after = [ "local-fs.target" ];
script = ''
# Create certificates if they do not exist yet
dir="${cfg.certificateDirectory}"
fqdn="${cfg.fqdn}"
[[ $fqdn == /* ]] && fqdn=$(< "$fqdn")
key="$dir/key-${cfg.fqdn}.pem";
cert="$dir/cert-${cfg.fqdn}.pem";
if [[ ! -f $key || ! -f $cert ]]; then
mkdir -p "${cfg.certificateDirectory}"
(umask 077; "${pkgs.openssl}/bin/openssl" genrsa -out "$key" 2048) &&
"${pkgs.openssl}/bin/openssl" req -new -key "$key" -x509 -subj "/CN=$fqdn" \
-days 3650 -out "$cert"
fi
'';
serviceConfig = {
Type = "oneshot";
PrivateTmp = true;
};
};
# Create maildir folder before dovecot startup
systemd.services.dovecot = {
wants = certificatesDeps;
after = certificatesDeps;
wants = certificateDeps;
after = certificateDeps;
preStart =
let
directories = lib.strings.escapeShellArgs (
@@ -93,12 +62,12 @@ in
# Postfix requires dovecot lmtp socket, dovecot auth socket and certificate to work
systemd.services.postfix = {
wants = certificatesDeps;
wants = certificateDeps;
after = [
"dovecot.service"
]
++ lib.optional cfg.dkimSigning "rspamd.service"
++ certificatesDeps;
++ certificateDeps;
requires = [ "dovecot.service" ] ++ lib.optional cfg.dkimSigning "rspamd.service";
};
};
+2 -1
View File
@@ -11,6 +11,7 @@ header = """
"""
template = """
({key})=
`````{{option}} {key}
{description}
@@ -25,7 +26,7 @@ options = json.load(f)
groups = [
"mailserver.loginAccounts",
"mailserver.certificate",
"mailserver.x509",
"mailserver.dkim",
"mailserver.srs",
"mailserver.dmarcReporting",
+2 -2
View File
@@ -248,7 +248,7 @@
with subtest("no warnings or errors"):
server.fail("journalctl -u postfix | grep -i error >&2")
server.fail("journalctl -u postfix | grep -i warning >&2")
server.fail("journalctl -u dovecot2 | grep -i error >&2")
server.fail("journalctl -u dovecot2 | grep -i warning >&2")
server.fail("journalctl -u dovecot | grep -i error >&2")
server.fail("journalctl -u dovecot | grep -i warning >&2")
'';
}
+10 -7
View File
@@ -26,7 +26,10 @@
./lib/config.nix
];
environment.systemPackages = with pkgs; [ netcat ];
environment.systemPackages = with pkgs; [
netcat
openssl
];
virtualisation.memorySize = 1024;
@@ -486,9 +489,9 @@
server.wait_until_fails('[ "$(postqueue -p)" != "Mail queue is empty" ]')
client.succeed("imap-mark-spam >&2")
server.wait_until_succeeds("journalctl -u dovecot -u dovecot2 | grep -i rspamd-learn-spam.sh >&2")
server.wait_until_succeeds("journalctl -u dovecot | grep -i rspamd-learn-spam.sh >&2")
client.succeed("imap-mark-ham >&2")
server.wait_until_succeeds("journalctl -u dovecot -u dovecot2 | grep -i rspamd-learn-ham.sh >&2")
server.wait_until_succeeds("journalctl -u dovecot | grep -i rspamd-learn-ham.sh >&2")
with subtest("full text search and indexation"):
# send 2 email from user2 to user1
@@ -506,9 +509,9 @@
# should fail because this folder is not indexed
client.fail("search Junk a >&2")
# check that search really goes through the indexer
server.succeed("journalctl -u dovecot -u dovecot2 | grep 'fts-flatcurve(INBOX): Query ' >&2")
server.succeed("journalctl -u dovecot | grep 'fts-flatcurve(INBOX): Query ' >&2")
# check that Junk is not indexed
server.fail("journalctl -u dovecot -u dovecot2 | grep 'fts-flatcurve(JUNK): Indexing ' >&2")
server.fail("journalctl -u dovecot | grep 'fts-flatcurve(JUNK): Indexing ' >&2")
with subtest("dmarc reporting"):
server.systemctl("start rspamd-dmarc-reporter.service")
@@ -516,10 +519,10 @@
with subtest("no warnings or errors"):
server.fail("journalctl -u postfix | grep -i error >&2")
server.fail("journalctl -u postfix | grep -i warning >&2")
server.fail("journalctl -u dovecot -u dovecot2 | grep -v 'imap-login: Debug: SSL error: Connection closed' | grep -i error >&2")
server.fail("journalctl -u dovecot | grep -v 'imap-login: Debug: SSL error: Connection closed' | grep -i error >&2")
# harmless ? https://dovecot.org/pipermail/dovecot/2020-August/119575.html
server.fail(
"journalctl -u dovecot -u dovecot2 | \
"journalctl -u dovecot | \
grep -v 'Expunged message reappeared, giving a new UID' | \
grep -v 'Time moved forwards' | \
grep -i warning >&2"
+2 -1
View File
@@ -38,7 +38,7 @@ let
inherit password;
}
''
mkpasswd -sm bcrypt <<<"$password" > $out
mkpasswd -s <<<"$password" > $out
'';
hashedPasswordFile = hashPassword "my-password";
@@ -113,6 +113,7 @@ in
''
machine.start()
machine.wait_for_unit("multi-user.target")
machine.wait_for_unit("dovecot.service")
# Regression test for https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/-/issues/205
with subtest("mail forwarded can are locally kept"):
+11
View File
@@ -0,0 +1,11 @@
-----BEGIN CERTIFICATE-----
MIIBizCCATGgAwIBAgIUN4ncJfMVIQSSurMkdE73x4aefTMwCgYIKoZIzj0EAwIw
GzEZMBcGA1UEAwwQdGVzdC5sb2NhbGRvbWFpbjAeFw0yNTEwMTgyMTQ4MTNaFw0z
NTEwMTYyMTQ4MTNaMBsxGTAXBgNVBAMMEHRlc3QubG9jYWxkb21haW4wWTATBgcq
hkjOPQIBBggqhkjOPQMBBwNCAARCJUj4j7eC/7Xso3REUscqHlWPvW9zvl5I6TIy
zEXFsWxM0QxMuNW4oXE56UiCyJklcpk0JfQUGat+kKQqSUJyo1MwUTAdBgNVHQ4E
FgQUW3CnmBf3n/Y30vfj3ERsIQnXu9QwHwYDVR0jBBgwFoAUW3CnmBf3n/Y30vfj
3ERsIQnXu9QwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNIADBFAiEAhwAi
K4xdr8KxD5xRvvzShheh48i8X7NtBIQ3bd01Jx4CIG/kYTDK5nDZri7UYOMsgz2l
iWss56p2dGWTL7LrBHgM
-----END CERTIFICATE-----
+11
View File
@@ -10,6 +10,17 @@
# Keep testing submission with explicit TLS
mailserver.enableSubmission = true;
# Certificate created for testing purposes from RFC9500 private key
# https://datatracker.ietf.org/doc/rfc9500/
# openssl req -x509 -new -key key.pem \
# -subj "/CN=test.localdomain" \
# -sha256 -days 3650 \
# -out cert.pem
mailserver.x509 = {
certificateFile = "${./cert.pem}";
privateKeyFile = "${./key.pem}";
};
# Enable second CPU core
virtualisation.cores = lib.mkDefault 2;
+5
View File
@@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIObLW92AqkWunJXowVR2Z5/+yVPBaFHnEedDk5WJxk/BoAoGCCqGSM49
AwEHoUQDQgAEQiVI+I+3gv+17KN0RFLHKh5Vj71vc75eSOkyMsxFxbFsTNEMTLjV
uKFxOelIgsiZJXKZNCX0FBmrfpCkKklCcg==
-----END EC PRIVATE KEY-----
+4 -3
View File
@@ -15,7 +15,7 @@ let
inherit password;
}
''
mkpasswd -sm bcrypt <<<"$password" > $out
mkpasswd -s <<<"$password" > $out
'';
password = pkgs.writeText "password" "password";
@@ -93,8 +93,9 @@ in
testScript = ''
start_all()
domain1.wait_for_unit("multi-user.target")
domain2.wait_for_unit("multi-user.target")
for domain in [domain1, domain2]:
domain.wait_for_unit("multi-user.target")
domain.wait_for_unit("dovecot.service")
# TODO put this blocking into the systemd units?
domain1.wait_until_succeeds(