===== Setting up a Postfix + Dovecot mailserver in Debian 10 (`Buster`)=====
\\
Adapted from [[https://wiki.quietlife.nl/doku.php?id=manuals:servers:mailserver|Quietlife on Setting up a Postfix + Dovecot mailserver]].
==== Firewall ====
The following ports have to be opened in your firewall:
25/tcp # SMTP
80/tcp # HTTP (for autoconfiguration)
587/tcp # Submission
993/tcp # IMAP SSL
----
\\
==== MariaDB ====
> [[https://en.wikipedia.org/wiki/MariaDB|MariaDB]] is a community-developed fork of the [[https://en.wikipedia.org/wiki/MySQL|MySQL]] relational database management system intended to remain free under the GNU GPL.
Install the database server:
sudo apt install mariadb-server
Harden it:
sudo mysql_secure_installation
Use one file per InnoDB table:
[mysqld]
innodb_file_per_table=1
Restart the daemon:
sudo systemctl restart mariadb.service
\\
Add a database management script:
#!/usr/bin/env python3
import argparse
import getpass
import subprocess
INITDB_SQL = """
CREATE DATABASE mailserver;
GRANT SELECT ON mailserver.*
TO 'mailuser'@'localhost' IDENTIFIED BY '{mailserver_password}';
CREATE TABLE `mailserver`.`virtual_domains` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(50) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `mailserver`.`virtual_users` (
`email` VARCHAR(100) NOT NULL,
`domain_id` INT(11) NOT NULL,
`password` VARCHAR(106) NOT NULL,
PRIMARY KEY (`email`),
FOREIGN KEY (domain_id) REFERENCES virtual_domains(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `mailserver`.`virtual_aliases` (
`source` VARCHAR(100) NOT NULL,
`domain_id` INT(11) NOT NULL,
`destination` VARCHAR(100) NOT NULL,
PRIMARY KEY (`source`),
FOREIGN KEY (domain_id) REFERENCES virtual_domains(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
"""
CHECK_DOMAIN_SQL = """
SELECT id FROM `mailserver`.`virtual_domains`
WHERE name = '{domain}'
"""
ADD_DOMAIN_SQL = """
INSERT INTO `mailserver`.`virtual_domains` (`name`)
VALUES ('{domain}');
"""
ADD_USER_SQL = """
INSERT INTO `mailserver`.`virtual_users`
(`email`, `domain_id`, `password`)
VALUES
('{email}', '{domain_id}',
ENCRYPT('{user_password}', CONCAT('$6$', SUBSTRING(SHA(RAND()), -16))))
"""
ADD_ALIAS_SQL = """
INSERT INTO `mailserver`.`virtual_aliases`
(`domain_id`, `source`, `destination`)
VALUES
('{domain_id}', '{source}', '{destination}');
"""
CHANGE_PASSWORD_SQL = """
UPDATE `mailserver`.`virtual_users`
SET password = ENCRYPT('{user_password}', CONCAT('$6$', SUBSTRING(SHA(RAND()), -16)))
WHERE email = '{email}';
"""
def parse_arguments():
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest='subcommand', help='Sub command')
subparsers.add_parser('initdb', help='Initialze the mailaccounts database')
adduser = subparsers.add_parser('adduser', help='Add a new mail user')
adduser.add_argument('email', metavar='EMAIL', help='The email address')
changepass = subparsers.add_parser(
'changepassword',
help='Change the password of a mail user')
changepass.add_argument('email', metavar='EMAIL', help='The email address')
subparsers.add_parser('removeuser', help='Remove a mail user')
addalias = subparsers.add_parser('addalias', help='Add a new mail alias')
addalias.add_argument('source', metavar='SOURCE',
help='The source email address (alias)')
addalias.add_argument('destination', metavar='DEST',
help='The destination email address')
subparsers.add_parser('removealias', help='Remove a mail user')
subparsers.required = True
return parser.parse_args()
def execute_query(query):
output = subprocess.check_output([
'mysql', '--execute', '%s' % query]).decode('utf-8')
return output
def initdb():
mailserver_password = getpass.getpass('Enter new password for the mailserver user: ')
query = INITDB_SQL.format(mailserver_password=mailserver_password)
execute_query(query)
def get_domain_id(domain):
result = execute_query(CHECK_DOMAIN_SQL.format(domain=domain))
if len(result.split()) == 2:
return result.split()[1]
def get_and_add_domain(email):
assert email.count('@') == 1, 'Email address is not correct!'
domain = email.split('@')[1]
domain_id = get_domain_id(domain)
if not domain_id:
execute_query(ADD_DOMAIN_SQL.format(domain=domain))
domain_id = get_domain_id(domain)
print('Added domain %s' % domain)
return domain_id
def adduser(email):
domain_id = get_and_add_domain(email)
user_password = getpass.getpass('Enter new password for the mail user: ')
execute_query(ADD_USER_SQL.format(email=email,
domain_id=domain_id,
user_password=user_password))
print('Added user %s' % email)
def addalias(source, destination):
domain_id = get_and_add_domain(source)
execute_query(ADD_ALIAS_SQL.format(source=source,
domain_id=domain_id,
destination=destination))
print('Added alias %s with destination %s' % (source, destination))
def changepass(email):
user_password = getpass.getpass('Enter new password for the mail user: ')
execute_query(CHANGE_PASSWORD_SQL.format(email=email,
user_password=user_password))
print('Changed password of user %s' % email)
def main():
args = parse_arguments()
subcommand = args.subcommand
if subcommand == 'initdb':
initdb()
elif subcommand == 'adduser':
adduser(args.email)
elif subcommand == 'addalias':
addalias(args.source, args.destination)
elif subcommand == 'changepassword':
changepass(args.email)
elif subcommand in ('removeuser','removealias'):
raise NotImplementedError('%s is not yet implemented' % subcommand)
if __name__ == '__main__':
main()
Make it executable:
chmod 770 ./mailaccount
Create a database called ''mailserver'' and a user called ''mailuser'':
sudo ./mailaccount initdb
=== Add users and aliases ===
Users:
sudo ./mailaccount adduser user1@quietlife.nl
Aliases:
sudo ./mailaccount addalias postmaster@quietlife.nl root@quietlife.nl
sudo ./mailaccount addalias root@quietlife.nl user1@quietlife.nl
----
\\
==== Postfix ====
> [[https://en.wikipedia.org/wiki/Postfix_(software)|Postfix]] is a free and open-source [[https://en.wikipedia.org/wiki/Mail_transfer_agent|mail transfer agent]] (MTA) that routes and delivers electronic mail, intended as an alternative to Sendmail MTA.
sudo apt install postfix postfix-mysql
\\
smtpd_banner = $myhostname ESMTP
biff = no
append_dot_mydomain = no
readme_directory = no
compatibility_level = 2
# TLS parameters
smtp_tls_cert_file = /etc/letsencrypt/live/quietlife.nl/fullchain.pem
smtp_tls_key_file = /etc/letsencrypt/live/quietlife.nl/privkey.pem
smtp_tls_security_level = may
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
smtpd_tls_auth_only = yes
smtpd_tls_cert_file = /etc/letsencrypt/live/quietlife.nl/fullchain.pem
smtpd_tls_key_file = /etc/letsencrypt/live/quietlife.nl/privkey.pem
smtpd_tls_security_level = may
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtpd_tls_received_header = yes
# Use strong ciphers
smtpd_tls_ciphers = high
smtpd_tls_mandatory_ciphers = high
smtpd_tls_protocols = TLSv1.2, !TLSv1.1, !TLSv1, !SSLv3, !SSLv2
smtpd_tls_mandatory_protocols = TLSv1.2, !TLSv1.1, !TLSv1, !SSLv3, !SSLv2
smtpd_tls_exclude_ciphers = MD5, DES, ADH, RC4, PSD, SRP, 3DES, eNULL, aNULL
smtpd_tls_mandatory_exclude_ciphers = MD5, DES, ADH, RC4, PSD, SRP, 3DES, eNULL, aNULL
smtpd_tls_eecdh_grade = ultra
tls_eecdh_ultra_curve = secp384r1
tls_high_cipherlist = AES384+EECDH:AES384+EDH:AES256+EECDH:AES256+EDH
tls_preempt_cipherlist = yes
tls_ssl_options = NO_RENEGOTIATION
# Enable SMTP for authenticated users and hand off authentication to Dovecot
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
smtpd_recipient_restrictions =
permit_sasl_authenticated,
permit_mynetworks,
reject_unauth_destination
# Network and host parameters
myhostname = vitas.quietlife.nl
myorigin = /etc/mailname
mydestination = localhost
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
inet_interfaces = all
inet_protocols = all
# Mail queue parameters
maximal_queue_lifetime = 12h
bounce_queue_lifetime = 12h
maximal_backoff_time = 1h
minimal_backoff_time = 5m
queue_run_delay = 5m
# Mailbox parameters
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
relayhost =
mailbox_size_limit = 51200000
message_size_limit = 51200000
recipient_delimiter = +
disable_vrfy_command = yes
# Hand off local delivery to Dovecot's LMTP and tell it where to store mail
virtual_transport = lmtp:unix:private/dovecot-lmtp
# Virtual domains, users and aliases
virtual_mailbox_domains = mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf
virtual_mailbox_maps = mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf
virtual_alias_maps = mysql:/etc/postfix/mysql-virtual-alias-maps.cf, mysql:/etc/postfix/mysql-virtual-email2email.cf
# Strip MUA headers
mime_header_checks = regexp:/etc/postfix/header_checks
header_checks = regexp:/etc/postfix/header_checks
quietlife.nl
user = mailuser
password = example-password
hosts = 127.0.0.1
dbname = mailserver
query = SELECT 1 FROM virtual_domains WHERE name='%s'
user = mailuser
password = example-password
hosts = 127.0.0.1
dbname = mailserver
query = SELECT 1 FROM virtual_users WHERE email='%s'
user = mailuser
password = example-password
hosts = 127.0.0.1
dbname = mailserver
query = SELECT destination FROM virtual_aliases WHERE source='%s'
user = mailuser
password = example-password
hosts = 127.0.0.1
dbname = mailserver
query = SELECT email FROM virtual_users WHERE email='%s'
# ==========================================================================
# service type private unpriv chroot wakeup maxproc command + args
# (yes) (yes) (no) (never) (100)
# ==========================================================================
smtp inet n - y - - smtpd
#smtp inet n - y - 1 postscreen
#smtpd pass - - y - - smtpd
#dnsblog unix - - y - 0 dnsblog
#tlsproxy unix - - y - 0 tlsproxy
submission inet n - y - - smtpd
-o syslog_name=postfix/submission
-o smtpd_tls_security_level=encrypt
-o smtpd_sasl_auth_enable=yes
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
-o milter_macro_daemon_name=ORIGINATING
# -o smtpd_reject_unlisted_recipient=no
# -o smtpd_helo_restrictions=$mua_helo_restrictions
# -o smtpd_sender_restrictions=$mua_sender_restrictions
# -o smtpd_recipient_restrictions=
# -o smtpd_relay_restrictions=permit_sasl_authenticated,reject
#smtps inet n - y - - smtpd
# -o syslog_name=postfix/smtps
# -o smtpd_tls_wrappermode=yes
# -o smtpd_sasl_auth_enable=yes
# -o smtpd_reject_unlisted_recipient=no
# -o smtpd_client_restrictions=$mua_client_restrictions
# -o smtpd_helo_restrictions=$mua_helo_restrictions
# -o smtpd_sender_restrictions=$mua_sender_restrictions
# -o smtpd_recipient_restrictions=
# -o smtpd_relay_restrictions=permit_sasl_authenticated,reject
# -o milter_macro_daemon_name=ORIGINATING
#628 inet n - y - - qmqpd
pickup unix n - y 60 1 pickup
-o content_filter=
-o receive_override_options=no_header_body_checks
cleanup unix n - y - 0 cleanup
qmgr unix n - n 300 1 qmgr
#qmgr unix n - n 300 1 oqmgr
tlsmgr unix - - y 1000? 1 tlsmgr
rewrite unix - - y - - trivial-rewrite
bounce unix - - y - 0 bounce
defer unix - - y - 0 bounce
trace unix - - y - 0 bounce
verify unix - - y - 1 verify
flush unix n - y 1000? 0 flush
proxymap unix - - n - - proxymap
proxywrite unix - - n - 1 proxymap
smtp unix - - y - - smtp
relay unix - - y - - smtp
# -o smtp_helo_timeout=5 -o smtp_connect_timeout=5
showq unix n - y - - showq
error unix - - y - - error
retry unix - - y - - error
discard unix - - y - - discard
local unix - n n - - local
virtual unix - n n - - virtual
lmtp unix - - y - - lmtp
anvil unix - - y - 1 anvil
scache unix - - y - 1 scache
/^Received:.*with ESMTPSA/ IGNORE
/^X-Originating-IP:/ IGNORE
/^X-Mailer:/ IGNORE
/^Mime-Version:/ IGNORE
\\
Refresh aliases:
sudo newaliases
sudo postmap /etc/aliases
----
\\
==== Dovecot ====
> [[https://en.wikipedia.org/wiki/Dovecot_(software)|Dovecot]] is an open-source IMAP and POP3 server for Linux/UNIX-like systems, written primarily with security in mind.
sudo apt install dovecot-core dovecot-imapd dovecot-lmtpd dovecot-mysql
Create a ''vmail'' user and ''vmail'' group and set permissions:
sudo groupadd -g 5000 vmail
sudo useradd -g vmail -u 5000 vmail -d /var/mail
sudo chown -R vmail:vmail /var/mail
sudo mkdir -p /var/mail/vhosts/quietlife.nl
sudo chmod 2700 /var/mail/vhosts/*
sudo chown -R vmail:dovecot /etc/dovecot
\\
# Enable installed protocols
!include_try /usr/share/dovecot/protocols.d/*.protocol
protocols = imap lmtp
# Location for users' mailboxes.
mail_location = maildir:/var/mail/vhosts/%d/%n
[...]
# Group to enable temporarily for privileged operations.
mail_privileged_group = mail
# Disable LOGIN command and all other plaintext authentications unless
# SSL/TLS is used (LOGINDISABLED capability).
disable_plaintext_auth = yes
[...]
# Space separated list of wanted authentication mechanisms:
auth_mechanisms = plain login
[...]
## Password and user databases
##
#!include auth-system.conf.ext
!include auth-sql.conf.ext
passdb {
driver = sql
args = /etc/dovecot/dovecot-sql.conf.ext
}
[...]
userdb {
driver = static
args = uid=vmail gid=vmail home=/var/mail/vhosts/%d/%n
}
# Database driver: mysql, pgsql, sqlite
driver = mysql
[...]
# Database connection string. This is driver-specific setting.
connect = host=127.0.0.1 dbname=mailserver user=mailuser password=example_password
[...]
# Default password scheme.
default_pass_scheme = SHA512-CRYPT
[...]
# passdb query to retrieve the password.
password_query = SELECT email as user, password FROM virtual_users WHERE email='%u';
# Enable imaps on port 993 only (disable imap on port 143)
service imap-login {
inet_listener imap {
port = 0
}
inet_listener imaps {
port = 993
ssl = yes
}
[...]
# Disable pop3s and pop3
service pop3-login {
inet_listener pop3 {
port = 0
}
inet_listener pop3s {
port = 0
#ssl = yes
}
}
# Enable lmtp for local delivery
service lmtp {
unix_listener /var/spool/postfix/private/dovecot-lmtp {
mode = 0600
user = postfix
group = postfix
}
}
[...]
service auth {
unix_listener auth-userdb {
mode = 0600
user = vmail
#group =
}
# Postfix smtp-auth
unix_listener /var/spool/postfix/private/auth {
mode = 0666
user = postfix
group = postfix
}
# Auth process is run as this user.
user = dovecot
}
service auth-worker {
user = vmail
}
# SSL/TLS support: yes, no, required.
ssl = required
[...]
# PEM encoded X.509 SSL/TLS certificate and private key.
ssl_cert =
----
\\
==== Sender Policy Framework ====
> [[https://en.wikipedia.org/wiki/Sender_Policy_Framework|Sender Policy Framework]] (SPF) is a simple email-validation system designed to detect email spoofing by providing a mechanism to allow receiving mail exchangers to check that incoming mail from a domain comes from a host authorized by that domain's administrators.
sudo apt install postfix-pcre postfix-policyd-spf-python
\\
Add SPF to the Postfix configuration:
Change
smtpd_recipient_restrictions =
permit_sasl_authenticated,
permit_mynetworks,
reject_unauth_destination
to
smtpd_recipient_restrictions =
permit_sasl_authenticated,
permit_mynetworks,
reject_unauth_destination,
check_policy_service unix:private/policyd-spf
policyd-spf_time_limit = 3600
(Mind the comma!)
[...]
# SPF configuration
policyd-spf unix - n n - 0 spawn
user=policyd-spf argv=/usr/bin/policyd-spf
\\
Finally, add a DNS TXT record for ''@'' (or ''quietlife.nl.''), containing:
"v=spf1 mx -all"
This tells the receiving mailserver that all mails coming from your domain should originate from the IP's in your A / AAAA records.
----
\\
==== OpenDKIM ====
> [[https://en.wikipedia.org/wiki/DomainKeys_Identified_Mail|DomainKeys Identified Mail]] (DKIM) is an email authentication method designed to detect email spoofing. It allows the receiver to check that an email claimed to have come from a specific domain was indeed authorized by the owner of that domain.
sudo apt install opendkim opendkim-tools unbound
Add the ''opendkim'' user to the ''postfix'' group:
sudo adduser postfix opendkim
Create an ''/etc/opendkim'' directory to store the tables:
sudo mkdir /etc/opendkim
\\
# Log to syslog
Syslog yes
# Required to use local socket with MTAs that access the socket as a non-
# privileged user (e.g. Postfix)
UMask 002
# Sign for example.com with key in /etc/dkimkeys/dkim.key using
# selector '2007' (e.g. 2007._domainkey.example.com)
# Domain example.com
# KeyFile /etc/mail/dkim.key
# Selector 2007
KeyTable /etc/opendkim/key.table
SigningTable refile:/etc/opendkim/signing.table
ExternalIgnoreList /etc/opendkim/trusted.hosts
InternalHosts /etc/opendkim/trusted.hosts
# Commonly-used options; the commented-out versions show the defaults.
Canonicalization relaxed/simple
Mode sv
SubDomains no
OversignHeaders From
[...]
TrustAnchorFile /usr/share/dns/root.key
Change the ''201708'' example to the current year/month:
quietlife quietlife.nl:201708:/etc/dkimkeys/quietlife.private
*@quietlife.nl quietlife
Add localhost, your hostname, your domain name(s) and your FQDN to the trusted hosts:
127.0.0.1
::1
localhost
vitas
quietlife.nl
vitas.quietlife.nl
# Change to /var/spool/postfix/var/run/opendkim to use a Unix socket with
# postfix in a chroot:
RUNDIR=/var/spool/postfix/var/run/opendkim
[...]
# Uncomment to specify an alternate socket
SOCKET=local:$RUNDIR/opendkim.sock
[...]
USER=opendkim
GROUP=postfix
PIDFILE=$RUNDIR/$NAME.pid
Generate a systemd unit file:
sudo /lib/opendkim/opendkim.service.generate
sudo systemctl daemon-reload
\\
Add OpenDKIM to the Postfix configuration:
sudo mkdir /var/spool/postfix/var/run/opendkim
sudo chown opendkim:postfix /var/spool/postfix/var/run/opendkim
[...]
# Use OpenDKIM to sign and verify mail
milter_default_action = accept
milter_protocol = 6
smtpd_milters = unix:var/run/opendkim/opendkim.sock
non_smtpd_milters = unix:var/run/opendkim/opendkim.sock
\\
Generate keys (use the current year/month instead of the example ''201708''):
opendkim-genkey -b 2048 -h rsa-sha256 -r -s 201708 -d quietlife.nl -v
sudo mv 201708.private /etc/dkimkeys/quietlife.private
mv 201708.txt dns.txt
\\
Finally, add a DNS TXT record with the contents of ''dns.txt'':
201708._domainkey 3600 IN TXT "v=DKIM1; h=sha256; k=rsa; s=email; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA63ggTqo80JaQBGV2uNreiX2/2yQx3PHbh9/4k+gIYO71ujqjGblk5z2FgzbWrTaIU7fZ0nN09bZAVDYavc9817fpYIYvnenDdKPJazl4hiVbBJL8jZ8/0ndu5WkCIzY60ukI423IAK+ppx7UW7Tpq38RokyFW8Wq96RAuhqeGkdxQN03N//yAtRCmeWwHw+jdGGq1WGbOKE7LcigRBMW9xPdJOk/rQPU2OjRh3b/BLohMYY0NX+0+Ybp0+5JuO6NZeYqWKbvezhtltTPrsYJU1m3cJTv11UxYiI8QPmSPGMJKVUevQv6Pn2aCARuNPIxSqfGwW6iwBhUZuxb1zQPCwIDAQAB"
(Change ''h=rsa-sha256'' to ''h=sha256'' and cut the key starting with ''v=DKIM1; ...'')
----
\\
==== Amavis ====
> [[https://en.wikipedia.org/wiki/Amavis|Amavis]] is an open source content filter for electronic mail, implementing mail message transfer, decoding, some processing and checking, and interfacing with external content filters to provide protection against spam, viruses and other malware.
sudo apt install amavisd-new pyzor razor p7zip-full spamassassin
Set up razor:
sudo su - amavis -s /bin/bash
razor-admin -create
razor-admin -register
exit
\\
# Default SPAM checking mode
# Please note, that anti-spam checking is DISABLED by
# default.
# If You wish to enable it, please uncomment the following lines:
@bypass_spam_checks_maps = (
\%bypass_spam_checks, \@bypass_spam_checks_acl, \$bypass_spam_checks_re);
$undecipherable_subject_tag = undef;
$virus_admin = undef;
$spam_admin = undef;
# To manually set $myhostname, edit the following line with the correct Fully
# Qualified Domain Name (FQDN) and remove the # at the beginning of the line.
$myhostname = "localhost";
Add Amavis to the Postfix configuration:
[...]
# Use Amavis to filter content
content_filter = smtp-amavis:[127.0.0.1]:10024
[...]
# Amavis configuration
smtp-amavis unix - - - - 2 smtp
-o smtp_data_done_timeout=1200
-o smtp_send_xforward_command=yes
-o disable_dns_lookups=yes
-o max_use=20
127.0.0.1:10025 inet n - - - - smtpd
-o content_filter=
-o local_recipient_maps=
-o relay_recipient_maps=
-o smtpd_restriction_classes=
-o smtpd_delay_reject=no
-o smtpd_client_restrictions=permit_mynetworks,reject
-o smtpd_helo_restrictions=
-o smtpd_sender_restrictions=
-o smtpd_recipient_restrictions=permit_mynetworks,reject
-o smtpd_data_restrictions=reject_unauth_pipelining
-o smtpd_end_of_data_restrictions=
-o mynetworks=127.0.0.0/8
-o smtpd_error_sleep_time=0
-o smtpd_soft_error_limit=1001
-o smtpd_hard_error_limit=1000
-o smtpd_client_connection_count_limit=0
-o smtpd_client_connection_rate_limit=0
-o receive_override_options=no_header_body_checks,no_unknown_recipient_checks,no_milters
----
\\
==== Postgrey ====
> [[https://en.wikipedia.org/wiki/Greylisting|Greylisting]] is a method of defending email users against spam. A mail transfer agent (MTA) using greylisting will "temporarily reject" any email from a sender it does not recognize. If the mail is legitimate the originating server will try again after a delay, and if sufficient time has elapsed the email will be accepted.
sudo apt install postgrey libnet-rblclient-perl libparse-syslog-perl
\\
POSTGREY_OPTS="--inet=10023 --delay=60"
Add Postgrey to the Postfix configuration:
Change
smtpd_recipient_restrictions =
permit_sasl_authenticated,
permit_mynetworks,
reject_unauth_destination,
check_policy_service unix:private/policyd-spf
to
smtpd_recipient_restrictions =
permit_sasl_authenticated,
permit_mynetworks,
reject_unauth_destination,
check_policy_service unix:private/policyd-spf,
check_policy_service inet:127.0.0.1:10023
(Mind the comma!)
----
\\
==== Fail2ban ====
> [[https://en.wikipedia.org/wiki/Fail2ban|Fail2Ban]] is an intrusion prevention software framework that protects computer servers from brute-force attacks.
sudo apt install fail2ban
Copy ''jail.conf'' to ''jail.local'':
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
\\
# Mail servers
[postfix]
enabled = true
port = smtp,465,submission
logpath = %(postfix_log)s
backend = %(postfix_backend)s
[postfix-rbl]
enabled = true
port = smtp,465,submission
logpath = %(postfix_log)s
backend = %(postfix_backend)s
maxretry = 1
[...]
[dovecot]
enabled = true
port = pop3,pop3s,imap,imaps,submission,465,sieve
logpath = %(dovecot_log)s
backend = %(dovecot_backend)s
[...]
# Mail servers authenticators: might be used for smtp,ftp,imap servers, so
# all relevant ports get banned
[postfix-auth]
enabled = true
filter = postfix-auth
action = iptables-multiport[name=postfix, port="http,https,smtp,submission,pop3,pop3s,imap,imaps,sieve", protocol=tcp]
logpath = /var/log/mail.log
[postfix-sasl]
enabled = true
port = smtp,465,submission,imap3,imaps,pop3,pop3s
logpath = %(postfix_log)s
backend = %(postfix_backend)s
By default, Fail2ban does not ship with a Postfix SMTP auth filter, so create one:
[Definition]
failregex = lost connection after (AUTH|UNKNOWN|EHLO) from (.*)\[\]
ignoreregex =
----
\\
==== Client autoconfiguration ====
> The goal of [[https://developer.mozilla.org/docs/Mozilla/Thunderbird/Autoconfiguration|autoconfiguration]] is to make it very easy for users to configure the connection to their email servers.
This guide assumes you use Apache or nginx, but any HTTP server will suffice.
The result is an autoconfiguration URL that mail clients like Thunderbird can parse to preconfigure settings.
=== Apache ===
ServerName autoconfig.quietlife.nl
DocumentRoot /var/www/autoconfig.quietlife.nl
Order allow,deny
allow from all
Enable it:
sudo a2ensite autoconfig.quietlife.nl.conf
sudo systemctl reload apache2.service
\\
=== nginx ===
server {
listen 80;
listen [::]:80;
server_name autoconfig.quietlife.nl;
root /var/www/autoconfig.quietlife.nl;
}
Enable it:
cd /etc/nginx/sites-enabled/
sudo ln -s ../sites-available/autoconfig.quietlife.nl autoconfig.quietlife.nl
sudo systemctl reload nginx.service
\\
=== Configuration ===
quietlife.nl
quietlife.nl
quietlife
quietlife.nl
993
SSL
password-cleartext
%EMAILADDRESS%
quietlife.nl
587
STARTTLS
password-cleartext
%EMAILADDRESS%
----
\\
==== Starting everything up ====
sudo systemctl restart postfix.service dovecot.service opendkim.service postgrey.service amavis.service fail2ban.service
----
\\
==== Testing ====
> [[https://en.wikipedia.org/wiki/Failure|Failure]] is the state or condition of not meeting a desirable or intended objective, and may be viewed as the opposite of success.
=== Test your mail server status ===
Go to [[https://mxtoolbox.com/domain/|MxToolBox]] and run a test. Ideally, you should not see any problems.\\
\\
=== Test DKIM DNS record ===
opendkim-testkey -d quietlife.nl -s 201708
If nothing is shown, your DNS record is set up properly.\\
\\
=== Test signatures ===
Send an empty email to [[check-auth@verifier.port25.com|port25.com's verifier]]. It should return this:
==========================================================
Summary of Results
==========================================================
SPF check: pass
DKIM check: pass
SpamAssassin check: ham
----
\\
==== Author Domain Signing Practices ====
> In computing, [[https://en.wikipedia.org/wiki/Author_Domain_Signing_Practices|Author Domain Signing Practices]] (ADSP) is an optional extension to the DKIM email authentication scheme, whereby a domain can publish the signing practices it adopts when relaying mail on behalf of associated authors.
If DKIM is working well, you can set up an ADSP record, telling the receiving mailserver that all mails coming from your domain should have a valid DKIM signature.
Add a DNS TXT record containing this:
_adsp._domainkey 3600 IN TXT "dkim=all"
----
\\
==== Domain-based Message Authentication, Reporting & Conformance ====
> [[https://en.wikipedia.org/wiki/DMARC|Domain-based Message Authentication, Reporting and Conformance]] (DMARC) is an email-validation system designed to detect and prevent email spoofing. It is intended to combat certain techniques often used in phishing and email spam, such as emails with forged sender addresses that appear to originate from legitimate organizations.
If SPF and DKIM are working well, you can set up a DMARC record.
Add a DNS TXT record containing this:
_dmarc 3600 IN TXT "v=DMARC1; p=reject"
\\
If you want to receive aggregate reports, you can set a ''rua'' option:
_dmarc 3600 IN TXT "v=DMARC1; p=reject; rua=mailto:postmaster@quietlife.nl"
If you also want to receive failure reports, you can set a ''ruf'' option:
_dmarc 3600 IN TXT "v=DMARC1; p=reject; rua=mailto:postmaster@quietlife.nl; ruf=mailto:postmaster@quietlife.nl"
\\
More information about DMARC records can be found [[https://dmarc.org/wiki/FAQ|here]].
----