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
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
|
<!DOCTYPE html>
<html lang=en>
<head>
<title></title>
<meta charset="utf-8"/>
<link rel="shortcut icon" href="favicon.ico"/>
<link rel='stylesheet' href='../style.css'/>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<header><h1>Postfix and Dovecot Mail Server</h1></header>
<main>
<p>Postfix and dovecot will be the two primary pieces of our mail sever.
Postfix is the mail transport agent that handles the sending and
receiving of mail and dovecot is the IMAP server that will allow us to
access our mail from a mail client such as mutt. The server will also
have several other supporting components, a complete list of which is:</p>
<ul>
<li><em>SpamAssassin</em> for spam filtering</li>
<li><em>OpenDKIM</em> for DKIM verification and signing</li>
<li><em>Postgrey</em> for greylisting</li>
<li><em>Policyd-SPF</em> for SPF verification</li>
<li><em>OpenDMARC</em> for DMARC verification</li>
</ul>
<p>You can use <a href=https://git.chudnick.com/mail-tools/tree/server/deploy-server>
this script</a> I have written to automate this process, but I would
recommend that you run through the tutorial first to understand
what is being done.</p>
<p>Please note that this tutorial is loosely intended for small personal mail
servers. Using PAM for authentication, as is done here, is not a scalable solution
for working with a large number of users. I do plan on covering Dovecot LDAP
authentication at some point which would be a better solution in an enterprise
setting.</p>
<h2>Install Packages</h2>
<p>Let's start by installing the required packages. Note that if you already
have Apache installed on the server, replace <em>python3-certbot-nginx</em>
with <em>python3-certbot-apache</em>.</p>
<pre><code>apt install postfix dovecot-imapd dovecot-sieve opendkim opendkim-tools spamassassin gnupg postgrey postfix-policyd-spf-python opendmarc dbconfig-no-thanks certbot python3-certbot-nginx</code></pre>
<p>During the installation of Postfix you will get a Debconf prompt in which
you need to select "Internet Site" and then provide your domain name,
<strong>example.com</strong>.</p>
<h2>Get a certificate</h2>
<p>Now we'll use Certbot to get a certificate for our server. If you are
using Apache replace <em>nginx</em> with <em>apache2</em>.</p>
<pre><code>systemctl stop nginx
certbot certonly --standalone -d <strong>mail.example.com</strong>
systemctl start nginx</code></pre>
<h2>Postfix Main Configuration</h2>
<p>In this section we will be doing the bulk of the postfix configuration.
The postconf command used throughout appends (or changes)
the specified configuration item in /etc/postfix/main.cf</p>
<h3>Network Configuration</h3>
<p>Let's start by configuring some network and domain information.</p>
<pre><code>postconf -e "myorigin = <strong>example.com</strong>"
postconf -e "mydestination = \$myhostname, \$mydomain, localhost"
postconf -e "mynetworks = 127.0.0.0/8 [::1]/128"
postconf -e "myhostname = <strong>mail.example.com</strong>"
</code></pre>
<p>Next, point postfix to the cerbot key and certificate, as well as the distro's
CA certificates.</p>
<pre><code>postconf -e "smtpd_tls_key_file=/etc/letsencrypt/live/<strong>mail.example.com</strong>/privkey.pem"
postconf -e "smtpd_tls_cert_file=/etc/letsencrypt/live/<strong>mail.example.com</strong>/fullchain.pem"
postconf -e "smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt"
</code></pre>
<p>Harden the TLS configuration by forcing strong
protocols and ciphers, and requiring that authentication occur only over an
encrypted session.</p>
<pre><code><em># Require authentication over TLS and optionally use it for sending and receiving mail</em>
postconf -e "smtpd_tls_auth_only = yes"
postconf -e "smtpd_tls_security_level = may"
postconf -e "smtp_tls_security_level = may"
<em># Force the use of TLSv1.2 or TLSv1.3</em>
postconf -e 'smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1'
postconf -e 'smtpd_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1'
postconf -e 'smtp_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1'
postconf -e 'smtp_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1'
<em># Prefer server ciphers</em>
postconf -e "tls_preempt_cipherlist = yes"
<em># Force strong ciphers</em>
postconf -e "smtpd_tls_ciphers = high"
postconf -e "smtpd_tls_mandatory_ciphers = high"
postconf -e "smtp_tls_ciphers = high"
postconf -e "smtp_tls_mandatory_ciphers = high"
postconf -e "smtpd_tls_exclude_ciphers = aNULL, eNULL, EXP, LOW, MEDIUM, PSK, SRP, SHA1, kRSA, CAMELLIA, ARIA, DSS, RSA+AES, ADH, AECDH"
postconf -e "smtp_tls_exclude_ciphers = aNULL, eNULL, EXP, LOW, MEDIUM, PSK, SRP, SHA1, kRSA, CAMELLIA, ARIA, DSS, RSA+AES, ADH, AECDH"
</code></pre>
<h3>Local Recipients and Aliases</h3>
<p>Here we configure the bulk of the postfix built-in security settings which are
structured as a series of access restrictions. Do not edit these settings without
first reading the Postfix documentation as an incorrect change could inadvertently
make your server an open relay.</p>
<pre><code>postconf -e "smtpd_helo_required = yes"
postconf -e "smtpd_sender_login_maps = proxy:hash:/etc/postfix/login_maps"
postconf -e "smtpd_helo_restrictions = reject_unknown_helo_hostname, reject_non_fqdn_helo_hostname"
postconf -e "smtpd_sender_restrictions = reject_sender_login_mismatch, reject_non_fqdn_sender, reject_unknown_sender_domain"
postconf -e "smtpd_recipient_restrictions = reject_non_fqdn_recipient, reject_unknown_recipient_domain, permit_sasl_authenticated, reject_unauth_destination, check_policy_service unix:private/postgrey, check_policy_service unix:private/policyd-spf, reject_rbl_client zen.spamhaus.org"
postconf -e "smtpd_relay_restrictions = permit_sasl_authenticated, reject_unauth_destination"
postconf -e "smtpd_data_restrictions = reject_unauth_pipelining"
<em># Disable VRFY command to prevent harvesting of user accounts on system</em>
postconf -e "disable_vrfy_command = yes"
<em># Change smptd banner (hide distribution)</em>
postconf -e "smtpd_banner = \$myhostname ESMTP \$mail_name"</code></pre>
<p>Now, configure the local mail recipients and some aliases. We'll create
an account called <strong>mailadmin</strong> to receive mail addressed to
several other accounts. This is to keep <em>administrative</em> mail separate, but
you can certainly alias these to your main account later if you would prefer to see
it there.</p>
<pre><code><em># Set a custom local_recipient_maps here in order to avoid accepting mail for all local accounts</em>
postconf -e "local_recipient_maps = proxy:hash:/etc/postfix/local_maps \$alias_maps"
<em># You will need to manually set a password later to login as mailadmin</em>
adduser --disabled-login --shell /usr/sbin/nologin --gecos "" mailadmin
echo "# postfix aliases
postmaster: mailadmin
root: mailadmin
dmarc: mailadmin
" > /etc/aliases
<em># Update address databases</em>
echo "mailadmin@<em>mail.example.com</em> mailadmin" > /etc/postfix/login_maps
echo "mailadmin mailadmin" > /etc/postfix/local_maps
newaliases
postmap /etc/postfix/login_maps
postmap /etc/postfix/local_maps
</code></pre>
<h3>Mail Delivery</h3>
<p>These commands configure our mail delivery preferences. Mail will be
delivered inside a user's home folder with a maildir-style mailbox using
dovecot.</p>
<pre><code><em># Maildir delivery to $HOME/Mail/Inbox/</em>
postconf -e "home_mailbox = Mail/Inbox/"
<em># Deliver mail with Dovecot</em>
postconf -e "mailbox_command = /usr/lib/dovecot/deliver"</code></pre>
<h3>Header and Body Checks</h3>
<p>Header and body checks allow for some simple content filtering within Postfix.
This is done by scanning a message line by line for a configured regex string,
nothing more. For example, the first header check listed will reject a message
with an attachment of <em>ransomware.exe</em> but will not block it if sent with
no extension. This is mostly a protection against uneducated users and poorly
written mail clients. Other checks block vulnerabilities and improve privacy.</p>
<p>Create a new file <strong>/etc/postfix/header_checks</strong>, then open it in a
text editor and add the following</p>
<pre><code><em># Block files with common executable extensions</em>
/name=[^>]*\.(exe|pif|com|dll|vbs|bat|sh|bash|so|zip|tar|gz|cpio)/ REJECT
<em># Block message/partial vulnerability</em>
/message\/partial/ REJECT
<em># Remove Received string that is created when spamassassin reinjects message into postfix</em>
<em># This is to prevent leaking the userid of the spamassassin user</em>
/^Received:.*userid.*/ IGNORE
<em># Remove User-Agent strings from headers</em>
/^User-Agent: .*/ IGNORE</code></pre>
<p>Create another new file <strong>/etc/postfix/body_checks</strong>, and add this</p>
<pre><code><em># Block messages with iframes</em>
/<iframe/ REJECT" > /etc/postfix/body_checks</code></pre>
<p>And then run these commands to point postfix to the check files.</p>
<pre><code>postconf -e "header_checks = regexp:/etc/postfix/header_checks"
postconf -e "body_checks = regexp:/etc/postfix/body_checks"</code></pre>
<h2>Postfix Master Configuration</h2>
<h3>SMTP client</h3>
<p>This simple command configures the SMTP client process that is responsible
for sending your mail to other mail servers.</p>
<pre><code>postconf -M "smtp/unix=smtp unix - - y - - smtp"</code></pre>
<h3>Postscreen and SMTP Recipient</h3>
<p>Postscreen is a kind of firewall that sits in front of the Postfix SMTPD
process and receives all incoming traffic. Postscreen will drop connections
from IPs on a DNS blacklst, or from clients that violate the SMTP protocol by
speaking out of turn or sending non-SMTP commands. This adds up to less spam
connections and therefore a much lighter workload for your server.</p>
<pre><code>postconf -M "smtp/inet=smtp inet n - y - 1 postscreen"
postconf -M "smtpd/pass=smtpd pass - - y - - smtpd"
postconf -P "smtpd/pass/content_filter=spamassassin"
postconf -M "tlsproxy/unix=tlsproxy unix - - y - 0 tlsproxy"
postconf -M "dnsblog/unix=dnsblog unix - - y - 0 dnsblog"
postconf -e "postscreen_dnsbl_sites = zen.spamhaus.org"
postconf -e "postscreen_dnsbl_action = enforce"
postconf -e "postscreen_greet_action = enforce"
</code></pre>
<h3>Submission over TLS (submissions)</h3>
<p>Submission over TLS (aka submissions) is the process you will use to submit
mail to your server from a mail client. These commands configure submissions to
use a fully-encrypted session, as opposed to STARTTLS, and to only allow access
to authenticated clients.</p>
<pre><code>postconf -M "submissions/inet=submissions inet n - y - - smtpd"
postconf -P "submissions/inet/smtpd_tls_wrappermode=yes"
postconf -P "submissions/inet/smtpd_tls_security_level=encrypt"
postconf -P "submissions/inet/smtpd_tls_auth_only=yes"
postconf -P "submissions/inet/smtpd_sasl_auth_enable=yes"
postconf -P "submissions/inet/smtpd_client_restrictions=permit_sasl_authenticated,reject"
postconf -P "submissions/inet/smtpd_helo_restrictions="
postconf -P "submissions/inet/smtpd_sender_restrictions=reject_sender_login_mismatch"
postconf -P "submissions/inet/smtpd_recipient_restrictions=reject_non_fqdn_recipient,reject_unknown_recipient_domain,permit_sasl_authenticated,reject"
postconf -P "submissions/inet/syslog_name=postfix/submissions"
postconf -P 'submissions/inet/smtpd_tls_protocols=!SSLv2,!SSLv3,!TLSv1,!TLSv1.1'
postconf -P 'submissions/inet/smtpd_tls_mandatory_protocols=!SSLv2,!SSLv3,!TLSv1,!TLSv1.1'</code></pre>
<h3>OPTIONAL - submission with mandatory STARTTLS</h3>
<p>Having configured submission over TLS on port 465 this step is optional.
STARTTLS is considered by some to be less secure than full-session TLS and
may be vulnerable to exploitation.</p>
<pre><code>postconf -M "submission/inet=submission inet n - y - - smtpd"
postconf -P "submission/inet/smtpd_tls_security_level=encrypt"
postconf -P 'submission/inet/smtpd_tls_protocols=!SSLv2,!SSLv3,!TLSv1,!TLSv1.1'
postconf -P 'submission/inet/smtpd_tls_mandatory_protocols=!SSLv2,!SSLv3,!TLSv1,!TLSv1.1'
postconf -P "submission/inet/smtpd_sasl_auth_enable=yes"
postconf -P "submission/inet/smtpd_tls_auth_only=yes"
postconf -P "submission/inet/syslog_name=postfix/submission"
postconf -P "submission/inet/smtpd_helo_restrictions="
postconf -P "submission/inet/smtpd_client_restrictions=permit_sasl_authenticated,reject"
postconf -P "submission/inet/smtpd_helo_restrictions="
postconf -P "submission/inet/smtpd_sender_restrictions=reject_sender_login_mismatch"
postconf -P "submission/inet/smtpd_recipient_restrictions=reject_non_fqdn_recipient,reject_unknown_recipient_domain,permit_sasl_authenticated,reject"
</code></pre>
<h3>SpamAssassin Configuration</h3>
<p>Finally, this command tells Postfix how to interact with SpamAssassin.</p>
<pre><code>postconf -M "spamassassin/unix=spamassassin unix - n n - - pipe user=debian-spamd argv=/usr/bin/spamc --socket=/var/run/spamd.sock -e /usr/sbin/sendmail -oi -f \${sender} \${recipient}" </code></pre>
<h2>Dovecot Configuration</h2>
<p>Dovecot configuration is usually split up into many different files under
<strong>/etc/dovecot/conf.d/</strong> but here will be doing all of the
configuration in the primary config file
<strong>/etc/dovecot/dovecot.conf</strong>. Open that file with your editor
of choice, clear all of its contents, and then replace it with the following.</p>
<pre><code><em># /etc/dovecot/conf.d/10-auth.conf</em>
disable_plaintext_auth = yes
auth_username_format = %n
auth_mechanisms = plain
userdb {
driver = passwd
}
passdb {
driver = pam
}
<em># /etc/dovecot/conf.d/10-mail.conf</em>
mail_location = maildir:~/Mail:INBOX=~/Mail/Inbox:LAYOUT=fs
namespace inbox {
type = private
prefix =
separator = /
inbox = yes
subscriptions = yes
list = yes
}
<em># /etc/dovecot/conf.d/10-master.conf</em>
service imap-login {
# Run login processes in high-security mode (see: LoginProcess.txt in dovecot docs)
service_count = 1
# Disable unencrypted IMAP by setting port for plain IMAP to 0
inet_listener imap {
port = 0
}
inet_listener imaps {
port = 993
ssl = yes
}
}
<em># Allow postfix to use dovecot SASL</em>
service auth {
unix_listener /var/spool/postfix/private/auth {
mode = 0660
user = postfix
group = postfix
}
}
<em># /etc/dovecot/conf.d/10-ssl.conf</em>
ssl = required
ssl_key = </etc/letsencrypt/live/<strong>mail.example.com</strong>/privkey.pem
ssl_cert = </etc/letsencrypt/live/<strong>mail.example.com</strong>/fullchain.pem
ssl_client_ca_dir = /etc/ssl/certs
ssl_dh = </usr/share/dovecot/dh.pem
<em># Mozilla intermediate compatibility</em>
ssl_min_protocol = TLSv1.2
ssl_cipher_list = ECDHE+ECDSA+AESGCM:ECDHE+aRSA+AESGCM:ECDHE+ECDSA+CHACHA20:ECDHE+aRSA+CHACHA20:DHE+aRSA+AESGCM:!aNULL:!eNULL
ssl_prefer_server_ciphers = yes
ssl_client_require_valid_cert = yes
<em># /etc/dovecot/conf.d/15-lda.conf</em>
protocol lda {
mail_plugins = \$mail_plugins sieve
}
<em># /etc/dovecot/conf.d/15-mailboxes.conf</em>
namespace inbox {
mailbox Sent {
special_use = \Sent
auto = subscribe
}
mailbox Trash {
special_use = \Trash
auto = create
autoexpunge = 30d
}
mailbox Drafts {
special_use = \Drafts
auto = subscribe
}
mailbox Spam {
special_use = \Junk
auto = create
autoexpunge = 30d
}
mailbox Archive {
special_use = \Archive
auto = create
}
}
<em># /etc/dovecot/conf.d/20-imap.conf</em>
imap_capability = +SPECIAL-USE
<em># /etc/dovecot/conf.d/90-sieve.conf</em>
plugin {
sieve = ~/.dovecot.sieve
sieve_default = /var/lib/dovecot/sieve/default.sieve
sieve_global = /var/lib/dovecot/sieve/
}</code></pre>
<p>Then create the default sieve filtering script at
<strong>/var/lib/dovecot/sieve/default.sieve</strong></p>
<pre><code>require ["fileinto", "mailbox"];
/*
* Discard mail that has a spam score greater than or equal to 10
*/
if header :contains "X-Spam-Level" "**********" {
discard;
stop;
}
/*
* Discard messages marked as infected by a virus scanner
*/
if header :contains "X-Virus-Scan" "infected" {
discard;
stop;
}
/*
* If message is marked as spam (and falls below discard threshold) put into spam mailbox
*/
if header :contains "X-Spam-Flag" "YES" {
fileinto "Spam";
}</code></pre>
<p>And compile the script</p>
<pre><code>sievec /var/lib/dovecot/sieve/default.sieve</code></pre>
<p>Finally, configure PAM authentication for dovecot at
<strong>/etc/pam.d/dovecot</strong>. Append these changes leaving any include
statements intact.</p>
<pre><code>auth required pam_unix.so
account required pam_unix.so</code></pre>
<h2>OpenDKIM</h2>
<p>DKIM is a mail-verification method that cryptographically signs mail
to allow receivers to verify the authenticity of the sender. Our mail server
will use DKIM to validate signatures on incoming mail and sign outgoing mail. DKIM
requires a public key to be published via DNS, which will be done near the end of
the guide.</p>
<p>Start by generating the DKIM key</p>
<pre><code>opendkim-genkey -D /etc/dkimkeys -d <em>example.com</em> -s mail
chown opendkim: /etc/dkimkeys/*
chmod 600 /etc/dkimkeys/*
mv /etc/dkimkeys/mail.private /etc/dkimkeys/mail.pem</code></pre>
<p>Here we make a directory for the opendkim socket inside the postfix chroot and
make it accessible to the postfix user.</p>
<pre><code>mkdir /var/spool/postfix/opendkim
chmod 770 /var/spool/postfix/opendkim
chown opendkim:opendkim /var/spool/postfix/opendkim
usermod -aG opendkim postfix</code></pre>
<p>Edit the configuration file at <strong>/etc/opendkim.conf</strong>
to be as follows:</p>
<pre><code>On-BadSignature reject
On-Security reject
Syslog yes
SyslogSuccess yes
LogResults yes
Canonicalization simple
Mode sv
OversignHeaders From
Domain <strong>example.com</strong>
Selector mail
KeyFile /etc/dkimkeys/mail.pem
UserID opendkim
UMask 007
Socket local:/var/spool/postfix/opendkim/opendkim.sock
PidFile /run/opendkim/opendkim.pid
TemporaryDirectory /run/opendkim
InternalHosts 127.0.0.1
TrustAnchorFile /usr/share/dns/root.key
RequireSafeKeys True
AlwaysAddARHeader True
</code></pre>
<h2>OpenDMARC</h2>
<p>DMARC is another mail-verification technology that provides verification of the
address seen by end-users and either or both of SPF and DKIM.
<p>Like with OpenDKIM, we need to make a directory inside the postfix chroot
for the socket and assign proper permissions.</p>
<pre><code>mkdir /var/spool/postfix/opendmarc
chmod 770 /var/spool/postfix/opendmarc
chown opendmarc:opendmarc /var/spool/postfix/opendmarc
usermod -aG opendmarc postfix
</code></pre>
<p>Now we write the configuration file at <strong>/etc/opendmarc.conf</strong></p>
<pre><code>PidFile /run/opendmarc/opendmarc.pid
PublicSuffixList /usr/share/publicsuffix/public_suffix_list.dat
RejectFailures True
Socket local:/var/spool/postfix/opendmarc/opendmarc.sock
Syslog True
SyslogFacility mail
UMask 002
UserID opendmarc
HistoryFile /var/run/opendmarc/opendmarc.hist
SPFIgnoreResults True
SPFSelfValidate True
</code></pre>
<p>Then create the history file and set permissions.</p>
<pre><code>touch /var/run/opendmarc/opendmarc.hist
chown opendmarc:opendmarc /var/run/opendmarc/opendmarc.hist
chmod 664 /var/run/opendmarc/opendmarc.hist
</code></pre>
<p>Now that both OpenDKIM and OpenDMARC are configured we can define them as milters
in postfix. This will tell postfix to route mail through one or both of these milters
depending on whether it is incoming or outgoing.</p>
<pre><code>postconf -P "smtpd/pass/smtpd_milters=unix:opendkim/opendkim.sock,unix:opendmarc/opendmarc.sock"
postconf -P "submissions/inet/smtpd_milters=unix:opendkim/opendkim.sock"
<em># If you enabled submission on port 587 run this too</em>
postconf -P "submission/inet/smtpd_milters=unix:opendkim/opendkim.sock"
</code></pre>
<h2>Postgrey</h2>
<p>Postgrey implements a spam-filter technique known as greylisting, which
always rejects mail on the first try and for a period of time afterwards known
as the greylist period. The idea behind this being that legitimate senders will
send the mail again later, while spammers, in a rush to send as many messages as
possible before being blacklisted, will not.</p>
<p>Postgrey ships with an extensive whitelist domains that are known
to cause issues (mainly large providers that constantly send from different
addresses). This whitelist file is located at
<strong>/etc/postgrey/whitelist_clients</strong> and can be appended to include
any domain you do not wish to be subject to greylisting.</p>
<p>The configuration needed here is minimal, just open
<strong>/etc/default/postgrey</strong> and make these changes</p>
<pre><code>POSTGREY_OPTS="--unix=/var/spool/postfix/private/postgrey --privacy"
POSTGREY_TEXT="Greylisted - see https://www.greylisting.org"</code></pre>
<p>And then enable the service</p>
<pre><code>systemctl enable --now postgrey</code></pre>
<h2>Policyd-SPF</h2>
<p>SPF is yet another mail-verification technology that uses DNS records to
delegate specific servers as being authorized to send mail for the domain
(and implicitly all other servers as unauthorized). Policyd-SPF will perform
SPF checking of received mail and reject mail that fails SPF verfication.</p>
<p>First, tell postfix how to access Policyd-SPF</p>
<pre><code>postconf -e "policyd-spf_time_limit = 3600"
postconf -M "policyd-spf/unix=policyd-spf unix - n n - 0 spawn user=policyd-spf argv=/usr/bin/policyd-spf"</code></pre>
<p>And then edit the configuration file at
<strong>/etc/postfix-policyd-spf-python/policyd-spf.conf</strong></p>
<pre><code>debugLevel = 1
TestOnly = 1
HELO_reject = Fail
Mail_From_reject = Fail
Header_Type = AR
<em># These settings increase false-positive risk</em>
<em># Comment them if you want to reduce that risk</em>
PermError_reject = True
TempError_Defer = True</code></pre>
<h2>SpamAssassin</h2>
<p>SpamAssassin is a spam-filter that will scan all received mail and assign
a spam score based on configured rules. SpamAssassin is much heavier and more
resource-intensive than any of the previous spam-filtering/verification programs
we have configured. The postfix spam-filtering philosophy emphasizes the use
of lightweight checks before passing to an external content filter such as
SpamAssassin. Ideally, non-legitimate mail will have already been caught by one
of the previous methods, and SpamAssassin will only have to operate on a much
smaller subset of the mail that is sent to our server.</p>
<p>We have actually already told postfix to use SpamAssassin as a content filter
so in this section we just need to edit the configuration file
<strong>/etc/spamassassin/local.cf</strong>.</p>
<pre><code><em># Clearly indicate message is spam to user</em>
rewrite_header Subject *****SPAM*****
rewrite_header From *****SPAM*****
<em># Set required score to be marked as spam, 5.0 is default.</em>
<em># Lower to make policy more strict or raise to be more lenient.</em>
required_score 5.0
<em># Attach original messages as text/plain instead of message/rfc822 to spam reports</em>
report_safe 2
<em>Do not implicitly trust mail based on IP address except localhost</em>
trusted_networks 127.0.0.1/32
</code></pre>
<p>And finally make a few changes to the defaults file at
<strong>/etc/default/spamassassin</strong></p>
<pre><code>OPTIONS="--listen /var/run/spamd.sock --max-children 5"
PIDFILE=/var/run/spamd.pid
CRON=1</code></pre>
<h2>Wrapping Up</h2>
<p>At this point we have done all of the necessary configuration of the mail
server programs. We have just a few more minor tasks before your mail server
is operational.</p>
<h3>Configure Firewall</h3>
<p>We need to open the proper ports in the firewall. This example uses UFW.</p>
<pre><code>ufw allow 25 comment "smtp"
ufw allow 465 comment "submission over TLS"
<em># Run this next command only if you enabled submission on port 587</em>
ufw allow 587 comment "mail submission"
ufw allow 993 comment "IMAP over TLS"
ufw reload</code></pre>
<h3>Restart services</h3>
<p>Now let's restart the services to pick up any configuration changes.</p>
<pre><code>systemctl restart postfix
systemctl restart dovecot
systemctl restart opendkim
systemctl restart opendmarc
systemctl enable --now spamassassin
systemctl restart spamassassin
systemctl restart postgrey</code></pre>
<h3>DNS Entries</h3>
<p>Finally, we needs to set some required DNS records to enable mail flow and
verification. Begin by logging into your registrar or DNS host and editing
your DNS records.</p>
<h3>A Record</h3>
<p>If you did not set a wildcard A record earlier, you will need to set one now
for <strong>mail</strong>.
Alternatively, if you are running the mail server on the same server as your
website, you may want to instead make a CNAME record pointing mail to www.</p>
<h3>MX Record</h3>
<p>MX records tell servers attempting to send you mail where to send it. Open the
MX records section on your registrar and add a new record. An MX
record consists of a priority and a destination. Set the priority to 10 and the
destination to <strong>mail</strong>, or whatever your subdomain for this mail
server is. The host value can be left blank or may need to be set to "@"
depending on your registrar.</p>
<h3>DKIM TXT Record</h3>
<p>Now we will set the three TXT records we need. Open the TXT records tab on
your registrar.</p>
<p>We'll set the DKIM record first. The command we ran to
generate our DKIM keys also generates a DNS record for us which will be helpful
here. Print that to the screen with:</p>
<pre><code>cat /etc/dkimkeys/mail.txt</code></pre>
<p>You should get a lengthy output that looks something like the following. The
bolded portion is the value.</p>
<pre><code>mail._domainkey IN TXT ( <strong>"v=DKIM1; h=sha256; k=rsa; "
"p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz50PSYL0Ob+OlF/0B77rwlzLe7zF6JKnxQNtMqcOCZ0Dar2FPhSUSz1FR0YmNuoShjMogdgKeojIzgRUqwK5GZ5Lz456qiXWkfAtLPc6UQ/WPoyEBGbJpRBYPGWdN4VoNcHkk/I4csvXW6MOI55ghPOwDmootPkCzNPR6gmNAXMe0duS4Lb+bIjy9QMOxGYVUaQ/b+7xar+fWw"
"bA3DjQa3jTLCydzzJpjEMfVaKqNhQ4N+ve7O2Mb3LF5k5B977mtok/6POjVG5HY8g6Pba+GzMFItR6nJO5EE2fyfv6cNbRLsZiM+WQmqvDBst5ejaeapy86F5PdJFlX/TUgXjtuwIDAQAB"</strong> ) ; ----- DKIM key mail for example.com</code></pre>
<p>You can cleanup the spacing of the value as your registrar should automatically
handle any needed splitting of the record. The parts you need to paste into your
registrar's web interface should then look like this.</p>
<pre><code><em># Name/Host</em>
mail._domainkey
<em># TXT Value</em>
"v=DKIM1; h=sha256; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz50PSYL0Ob+OlF/0B77rwlzLe7zF6JKnxQNtMqcOCZ0Dar2FPhSUSz1FR0YmNuoShjMogdgKeojIzgRUqwK5GZ5Lz456qiXWkfAtLPc6UQ/WPoyEBGbJpRBYPGWdN4VoNcHkk/I4csvXW6MOI55ghPOwDmootPkCzNPR6gmNAXMe0duS4Lb+bIjy9QMOxGYVUaQ/b+7xar+fWwbA3DjQa3jTLCydzzJpjEMfVaKqNhQ4N+ve7O2Mb3LF5k5B977mtok/6POjVG5HY8g6Pba+GzMFItR6nJO5EE2fyfv6cNbRLsZiM+WQmqvDBst5ejaeapy86F5PdJFlX/TUgXjtuwIDAQAB"</code></pre>
<h3>DMARC TXT Record</h3>
<p>The DMARC record should be as follows:</p>
<pre><code><em># Name/Host</em>
_dmarc
<em># Value</em>
"v=DMARC1; p=reject; rua=mailto:dmarc@<strong>example.com</strong>; fo=1"
</code></pre>
<h3>SPF Record</h3>
<p>Your SPF record will look like this. Remember to replace
<strong>mail.example.com</strong> with your server name.</p>
<pre><code><em># Name/Host</em>
@
<em># Value</em>
"v=spf1 a:<strong>mail.example.com</strong> -all"
</code></pre>
<h3>PTR Record</h3>
<p>Many mail servers rely on PTR records for verification purposes so we need
to make sure our server's IP address resolves to the proper domain name. If
your mail server is residing on a VPS, you will need to add this record on your
VPS provider's interface, consult their documentation for details.</p>
<h2>Creating your own Mail User</h2>
<p>Your mail server is now up and running. Let's create an email for you to
receive mail.</p>
<pre><code>useradd --shell /usr/sbin/nologin --create-home --user-group <strong>user</strong>
echo "<strong>user@example.com user</strong>" >> /etc/postfix/login_maps
echo "<strong>user user</strong>" >> /etc/postfix/local_maps
postmap /etc/postfix/login_maps
postmap /etc/postfix/local_maps
postfix reload
</code></pre>
<p>I have a script available for adding and removing users that you can find
<a href=https://git.chudnick.com/mail-tools/tree/server/mailadm>here</a>.
<h3>Connecting From a Mail Client</h3>
<p>When connecting your account to a mail client you need to use these settings.</p>
<ul>
<li>Username: <strong>user@example.com</strong> </li>
<li>Password: the password for <strong>user@example.com</strong> </li>
<li>Server name: <strong>mail.example.com</strong> </li>
<li>IMAP Port: 993</li>
<li>IMAP Connection: SSL/TLS</li>
<li>SMTP Port: 465</li>
<li>SMTP Connection Type: SSL/TLS</li>
</ul>
<p>
<hr>
Consider <a href=../donate.html>donating</a> if this article was useful.
<a class=qr href=../images/bitcoin.png>[BTC]</a>
</p>
</main>
<footer>
<a href=../kb.html>Knowledge Base</a>
<br>
<a href=../index.html>www.chudnick.com</a>
</footer>
</body>
</html>
|