1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
|
---
date: 2016-06-11
title: NixOS mail server
draft: true
---
<!--more-->
This is my working, but in progress [NixOS]({{< ref "nixos-intro.md" >}}) mail server configuration. These are the relevant configuration parts, they are *not* tested and **not guaranteed to be secure, deploy at your own risk**. The configuration is based on [this](https://thomas-leister.de/allgemein/sicherer-mailserver-dovecot-postfix-virtuellen-benutzern-mysql-ubuntu-server-xenial/) blog post (German).
For an easier overview, I created a seperate `mail.nix` that is included in the main `configuration.nix`. The firewall needs to be open for ports 993 (imps), 25 (smtp) and 587 (smtps).
```nix
imports =
[
./mail.nix
];
networking.firewall.allowedTCPPorts = [ 993 25 587 ];
```
The server is built with postfix. Postfix transports the mail via smtp(s). Dovecot is the interface between user and provides pop3(s) and/or imap(s). Opendkim signs outgoing mail so that it is less likely to be marked as spam by other providers.
DNS records must be and a PTR record can be set up. This is not covered here.
It is advisable to use SSL certificates. NixOS has a module that gets Let's Encrypt certificates:
```nix
security.acme.certs = {
"yourdomain.tld" = {
webroot = "/var/www/challenges";
extraDomains = { "mail.yourdomain.tld" = null; };
email = "mail@provider.net";
postRun = "systemctl reload nginx.service postfix.service dovecot2.service";
};
};
```
A web server is needed for the certification process.
```nix
services.nginx = {
enable = true;
httpConfig = ''
include ${pkgs.nginx}/conf/mime.types;
server {
listen 80;
listen [::]:80;
server_name mail.yourdomain.tld;
location /.well-known/acme-challenge {
root /var/www/challenges/;
}
}
'';
};
```
After retrieving certificates once: `systemctl start acme-yourdomain.tld`, they will be regenerated regularly and placed in `/var/lib/acme/yourdomain.tld/` by default. Now comes the main configuration. The user `vmail` is the owner of the mailing system.
```nix
users.users.vmail = {
home = "/var/vmail";
createHome = true;
group = "vmail";
};
users.groups = { vmail = {}; };
```
Dovecot requires an external configuration file. I put it in `/etc/nixos/mail/dovecot.conf`.
```nix
services.dovecot2 = {
enable = true;
configFile = "/etc/nixos/mail/dovecot.conf";
sslCACert = "/var/lib/acme/yourdomain.tld/fullchain.pem";
sslServerCert = "/var/lib/acme/yourdomain.tld/fullchain.pem";
sslServerKey = "/var/lib/acme/yourdomain.tld/key.pem";
};
```
This is the dovecot config. It exposes imap, lmtp and auth ports. imap is for the user. lmtp and auth are for exchanging data between dovecot and postfix. Postfix will authenticate via dovecot. `passdb` and `userdb` set to `pam` and `passwd` will allow every local unix user to authenticate with their username and password. Each user has a `~/Maildir` with their mail, each mailbox contains the folders "Spam", "Trash", "Drafts" and "Sent".
```perl
default_internal_user = dovecot2
protocols = imap lmtp
ssl = required
ssl_cert = </var/lib/acme/yourdomain.tld/fullchain.pem
ssl_key = </var/lib/acme/yourdomain.tld/key.pem
ssl_dh_parameters_length = 2048
ssl_protocols = !SSLv2 !SSLv3
ssl_cipher_list = EDH+CAMELLIA:EDH+aRSA:EECDH+aRSA+AESGCM:EECDH+aRSA+SHA256:EECDH:+CAMELLIA128:+AES128:+SSLv3:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!DSS:!RC4:!SEED:!IDEA:!ECDSA:kEDH:CAMELLIA128-SHA:AES128-SHA
ssl_prefer_server_ciphers = yes
service imap-login {
inet_listener imap {
port = 143
}
}
service lmtp {
inet_listener {
port = 8458
}
}
service auth {
inet_listener {
port = 2847
}
}
protocol imap {
mail_plugins = $mail_plugins
mail_max_userip_connections = 20
imap_idle_notify_interval = 29 mins
}
protocol lmtp {
postmaster_address = postmaster@yourdomain.tld
mail_plugins = $mail_plugins
}
disable_plaintext_auth = yes
auth_mechanisms = plain login
auth_username_format = %Ln
passdb {
driver = pam
args = dovecot2
}
userdb {
driver = passwd
args = blocking=no
}
mail_uid = vmail
mail_gid = vmail
mail_privileged_group = vmail
mail_home = /var/vmail/mailboxes/%d/%n
mail_location = maildir:~/Maildir
namespace inbox {
inbox = yes
mailbox Spam {
auto = subscribe
special_use = \Junk
}
mailbox Trash {
auto = subscribe
special_use = \Trash
}
mailbox Drafts {
auto = subscribe
special_use = \Drafts
}
mailbox Sent {
auto = subscribe
special_use = \Sent
}
}
```
Now comes postfix. Postfix is configured to authenticate via dovecot. Postscreen and dnsblog filter some spam mails.
```nix
services.postfix = {
enable = true;
user = "vmail";
group = "vmail";
domain = "mail.yourdomain.tld";
hostname = "mail.yourdomain.tld";
sslCACert = "/var/lib/acme/yourdomain.tld/fullchain.pem";
sslCert = "/var/lib/acme/yourdomain.tld/fullchain.pem";
sslKey = "/var/lib/acme/yourdomain.tld/key.pem";
recipientDelimiter = "+";
destination = [ "yourdomain.tld" "mail.yourdomain.tld" ];
virtual = ''
onealias@yourdomain.tld youruser
anotheralias@yourdomain.tld youruser
'';
extraMasterConf = ''
smtp inet n - n - 1 postscreen
-o smtpd_sasl_auth_enable=no
smtpd pass - - n - - smtpd
-o smtpd_sasl_auth_enable=no
dnsblog unix - - n - 0 dnsblog
tlsproxy unix - - n - 0 tlsproxy
submission inet n - n - - smtpd
-o syslog_name=postfix/submission
-o smtpd_tls_security_level=encrypt
-o smtpd_sasl_auth_enable=yes
-o smtpd_sasl_type=dovecot
-o smtpd_sasl_path=inet:127.0.0.1:2847
-o smtpd_sasl_security_options=noanonymous
-o smtpd_relay_restrictions=reject_non_fqdn_recipient,reject_unknown_recipient_domain,permit_mynetworks,permit_sasl_authenticated,reject
-o smtpd_sender_restrictions=permit_mynetworks,reject_non_fqdn_sender,permit_sasl_authenticated,reject
-o smtpd_client_restrictions=permit_mynetworks,permit_sasl_authenticated,reject
-o smtpd_helo_required=no
-o smtpd_helo_restrictions=
-o milter_macro_daemon_name=ORIGINATING
-o cleanup_service_name=submission-header-cleanup
submission-header-cleanup unix n - n - 0 cleanup
-o header_checks=pcre:/etc/nixos/mail/anonymize_headers.pcre
'';
extraConfig = ''
maximal_queue_lifetime = 1h
bounce_queue_lifetime = 1h
maximal_backoff_time = 15m
minimal_backoff_time = 5m
queue_run_delay = 5m
tls_ssl_options = NO_COMPRESSION
tls_high_cipherlist = EDH+CAMELLIA:EDH+aRSA:EECDH+aRSA+AESGCM:EECDH+aRSA+SHA256:EECDH:+CAMELLIA128:+AES128:+SSLv3:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!DSS:!RC4:!SEED:!IDEA:!ECDSA:kEDH:CAMELLIA128-SHA:AES128-SHA
smtp_tls_security_level = dane
smtp_dns_support_level = dnssec
smtp_tls_session_cache_database = btree:''${data_directory}/smtp_scache
smtp_tls_protocols = !SSLv2, !SSLv3
smtp_tls_ciphers = high
smtpd_tls_security_level = may
smtpd_tls_protocols = !SSLv2, !SSLv3
smtpd_tls_ciphers = high
smtpd_tls_eecdh_grade = strong
smtpd_tls_dh1024_param_file=/var/lib/acme/yourdomain.tld/dhparams.pem
smtpd_tls_session_cache_database = btree:''${data_directory}/smtpd_scache
smtpd_relay_restrictions =
reject_non_fqdn_recipient
reject_unknown_recipient_domain
permit_mynetworks
reject_unauth_destination
smtpd_client_restrictions = permit_mynetworks
reject_unknown_client_hostname
smtpd_helo_required = yes
smtpd_helo_restrictions = permit_mynetworks
reject_invalid_helo_hostname
reject_non_fqdn_helo_hostname
reject_unknown_helo_hostname
smtpd_data_restrictions = reject_unauth_pipelining
mailbox_transport = lmtp:inet:127.0.0.1:8458
milter_default_action = accept
milter_protocol = 2
smtpd_milters = unix:/run/opendkim/opendkim.sock
non_smtpd_milters = unix:/run/opendkim/opendkim.sock
# Postscreen
postscreen_access_list = permit_mynetworks
postscreen_blacklist_action = drop
postscreen_greet_action = drop
# DNS blocklists
postscreen_dnsbl_threshold = 2
postscreen_dnsbl_sites = dnsbl.sorbs.net*1, bl.spamcop.net*1, ix.dnsbl.manitu.net*2, zen.spamhaus.org*2
postscreen_dnsbl_action = drop
# turn off biff notifications for performance
biff = no
append_dot_mydomain = no
'';
};
```
`/etc/nixos/mail/anonymize_headers.pcre` replaces sensitive header data.
```
/^\s*(Received: from)[^\n]*(.*)/ REPLACE $1 [127.0.0.1] (localhost [127.0.0.1])$2
/^\s*User-Agent/ IGNORE
/^\s*X-Enigmail/ IGNORE
/^\s*X-Mailer/ IGNORE
/^\s*X-Originating-IP/ IGNORE
```
Finally, the opendkim configuration. Generate a key once with `opendkim-genkey -r -d yourdomain.tld`. Add the public key as DNS record.
```nix
services.opendkim = {
enable = true;
domains = "yourdomain.tld,mail.yourdomain.tld";
keyFile = "/etc/nixos/mail/key.private";
selector = "key";
socket = "local:/run/opendkim/opendkim.sock";
user = "vmail";
group = "vmail";
};
```
|