Create your own mail server
Drop Yahoo, Google or Microsoft mail - they are reading your mail.Debian, Postfix, Dovecot, MariaDb, rspamd
This is the second (and last) part of setting up your own internet tools in order to gain back control. Goal is to set up an email server (receive and send), secure it, and filter spam.Hardware considerations
I used an abandoned ASRock ION330, where I replaced the 5400rpm harddisk for a SSD. I planned using an ODroid C2, but could not get rspamd running within a reasonable amount of time (days, that is...). The SSD is small, by today's standards, but 120GB is plenty of mail. YMMV, adapt storage to your needs.A colleague had some RAM laying around, so I have an ION330 with maxed out RAM: 4GB...
Basic setup
This time no Etcher, but a bootable CD. Download Debian (debian-9.4.0-amd64-netinst.iso), burn it to CD, and boot from it.Install, uncheck all options when selecting what to install. Set a root password.
Let's get cracking: security!
Basically, follow the instructions of the previous entry regarding setting up daily users, not allowing password based logins and prohibiting root logins.You may have to install sudo:
su -
apt update && apt upgrade -y && apt dist-upgrade
apt install openssh-server sudo -y
visodo
change:# User privilege specification
root ALL=(ALL:ALL) ALL
to
# User privilege specification
root ALL=(ALL:ALL) ALL
frank ALL=(ALL:ALL) ALL
Save (Ctrl-X, return).
Logout of the elevated Super User (su) session (Ctrl-D), and type:
sudo apt update
You should be asked for your own(not root) password, and apt should be executed. You are now sudo'ed.
Security: enable logins over SSH
Installing the latest ssh server version is easier than with Ubuntu:
sudo -s
cd /usr/local/src
wget http://ftp.nl.debian.org/debian/pool/main/o/openssl/libssl1.1_1.1.0h-2_amd64.deb
dpkg -i ./libssl1.1_1.1.0h-2_amd64.deb
wget http://ftp.nl.debian.org/debian/pool/main/o/openssl/openssl_1.1.0h-2_amd64.deb
dpkg -i openssl_1.1.0h-2_amd64.deb
You should do this before generating long keys, etc.
Your internet exposure
As a result of the previous entry, you have a contract with Domain Registrar. Your IPv4 (A record) and IPv6 (AAAA record) addresses point to [YOUR.DOMAIN], www.[YOUR.DOMAIN] and cloud.[YOUR.DOMAIN].Now it is time to add your mail exchange (MX) record, and the IPv4 (A) and IPv6 (AAAA) records for your mail server. Your referrals should look like this example zone file:
.
# General referral for your TLD to a mail server:
[YOUR.DOMAIN]. 86400 IN MX 0 mail.[YOUR.DOMAIN].
# mail server itself should have IPv4 and IPv6 addresses:
mail.[YOUR.DOMAIN]. 3600 IN A 11.22.33.999
mail.[YOUR.DOMAIN]. 3600 IN AAAA 2001:aa:bbcc:1:2:ff:43:1234
# Often used aliases, based on protocol:
smtp.[YOUR.DOMAIN]. 86400 IN CNAME mail.[YOUR.DOMAIN].
imap.[YOUR.DOMAIN]. 86400 IN CNAME mail.[YOUR.DOMAIN].
# DMARC protection. Generate your own at https://elasticemail.com/dmarc based on your liking
_dmarc.[YOUR.DOMAIN]. 3600 IN TXT "v=DMARC1\; p=reject\; rua=mailto:postmaster@[YOUR.DOMAIN]\; aspf=s\; adkim=s\;"
# SPF - nice try to avaoid spam
[YOUR.DOMAIN]. 3600 IN TXT "v=spf1 a:mail.[YOUR.DOMAIN] ?all"
The smtp and imap entries are not necessary, just common abbreviations for incoming and outgoing mail servers. In fact, these are the names of protocols being used. The CNAME type indicates smtp.[YOUR.DOMAIN] is an alias for your mail.[YOUR.DOMAIN]. Same applies to imap.[YOUR.DOMAIN].I'll come to spf and dmarc later (and add DKIM as well)
Install: Letsenrypt certificates
Once more, I will use Letsencrypt certificates. Getting them to work is a little different.
sudo -s
apt install certbot
wget https://dl.eff.org/certbot-auto
chmod a+x ./certbot-auto
cd /usr/local/src
wget http://ftp.nl.debian.org/debian/pool/main/o/openssl/libssl-dev_1.1.0h-2_amd64.deb
dpkg -i ./libssl-dev_1.1.0h-2_amd64.deb
exit
sudo ./certbot-auto certonly --standalone --rsa-key-size 4096 -d mail.[YOUR.DOMAIN] -d imap.[YOUR.DOMAIN] -d smtp.[YOUR.DOMAIN]
sudo crontab -e
@weekly /root/renewal.sh > /home/frank/renewal.txt 2>&1
cat <<'EOF'>>/root/renewal.sh
#!/bin/bash
echo "-------------------------------------"
echo "Renewals:"
/root/certbot-auto renew
echo "-------------------------------------"
result=$(find /etc/letsencrypt/live/ -type l -mtime -1 )
if [ -n "$result" ]; then
echo "Restarting services..."
/bin/systemctl postfix reload
/bin/systemctl dovecot reload
/usr/sbin/service redis-server restart
echo "-------------------------------------"
fi
mail -s "certbot Mail renewal" frank@[YOUR.DOMAIN] < /home/frank/renewal.txt
exit 0
EOF
Installation: mail
Mail consists of a Mail transfer Agent (MTA) and a Mail User Agent (MUA). The configuration is kept in a database (MariaDb), and I want filtering against spammers as well as my server to be trusted.All in all, I will install Postfix, Dovecot, MariaDb, rspamd DKIM, spf, DMARC.
Install postfix (Mail Transfer Agent)
sudo apt install postfix postfix-mysql dovecot-core dovecot-imapd dovecot-lmtpd dovecot-mysql dovecot-sieve dovecot-managesieved mariadb-server
In the Postfix configuration, choose internet site (default), and your [YOUR.DOMAIN] (without the mail prefix)
sudo service dovecot stop
sudo service postfix stop
sudo -s
cd /etc/postfix/
vi main.cf
# check/alter:
myhostname = mail.[YOUR.DOMAIN]
inet_protocols = all
#or: inet_protocols = ipv4
mydestination = localhost
MariaDb install & setup
mysql_secure_installation
set a new root password
Remove anonymous users (Y - default)
Disallow remote root (Y - default)
Remove demo and Test databases (Y - default)
Reload tables (Y - default)
# Done. Now, for the db and tables:
mysqladmin -p create maildb;
mysql -p maildb
grant select on maildb.* to mailowner@'127.0.0.1' identified by 'SomeMailPassword';
flush privileges;
CREATE or replace TABLE domains (
id int(11) NOT NULL auto_increment,
domain varchar(50) NOT NULL,
PRIMARY KEY (id),
UNIQUE KEY (domain)
) ENGINE=InnoDB;
create or replace table users (
id int(11) NOT NULL auto_increment,
domain_id int(11) NOT NULL,
password varchar(255) NOT NULL,
email varchar(127) NOT NULL,
quota int unsigned DEFAULT 1024,
enabled boolean DEFAULT 0,
sendonly boolean DEFAULT 0,
PRIMARY KEY (id),
UNIQUE KEY ( email),
FOREIGN KEY (domain_id) REFERENCES domains(id) ON DELETE CASCADE
) ENGINE=InnoDB;
CREATE or replace TABLE aliases (
id int(11) NOT NULL AUTO_INCREMENT,
domain_id int(11) NOT NULL,
source varchar(100) NOT NULL,
destination varchar(100) NOT NULL,
enabled boolean DEFAULT 0,
PRIMARY KEY (id),
FOREIGN KEY (domain_id) REFERENCES domains (id) ON DELETE CASCADE
) ENGINE=InnoDB;
CREATE or REPLACE TABLE tlspolicies (
id int(11) NOT NULL AUTO_INCREMENT,
domain varchar(127) NOT NULL,
policy enum('none', 'may', 'encrypt', 'dane', 'dane-only', 'fingerprint', 'verify', 'secure') NOT NULL,
params varchar(255),
PRIMARY KEY (id),
UNIQUE KEY (domain)
)ENGINE=InnoDB;
insert into domains (domain) values ('[YOUR.DOMAIN]');
insert into domains (domain) values ('mail.[YOUR.DOMAIN]');
insert into domains (domain) values ('localhost');
insert into domains (domain) values ('home.local');
INSERT INTO maildb.aliases (domain_id, source, destination, enabled) VALUES
('1', 'webmaster@[YOUR.DOMAIN]', 'frank@[YOUR.DOMAIN]',0);
INSERT INTO maildb.aliases (domain_id, source, destination, enabled) VALUES
('1', 'postmaster@[YOUR.DOMAIN]', 'frank@[YOUR.DOMAIN]',1);
INSERT INTO maildb.aliases (domain_id, source, destination, enabled) VALUES
('1', 'cloudadmin@[YOUR.DOMAIN]', 'frank@[YOUR.DOMAIN]',1);
INSERT INTO maildb.aliases (domain_id, source, destination, enabled) VALUES
('1', 'info@[YOUR.DOMAIN]', 'frank@[YOUR.DOMAIN]',1);
INSERT INTO maildb.aliases (domain_id, source, destination, enabled) VALUES
('1', 'frank@home.local', 'frank@[YOUR.DOMAIN]',1);
INSERT INTO maildb.aliases (domain_id, source, destination, enabled) VALUES
('1', 'root@home.local', 'frank@[YOUR.DOMAIN]',1);
insert into tlspolicies (domain, policy, params) values ('gmx.de', 'secure', 'match=.gmx.net');
commit;
quit
postfix (Mail Transfer Agent) - connect to MariaDb
mv /etc/postfix/main.cf /etc/postfix/main.cf.sav
cat <<'EOF'>>/etc/postfix/main.cf
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
mydestination = localhost
relayhost =
inet_interfaces = all
inet_protocols = all
myhostname = mail.[YOUR.DOMAIN]
#############################
### mail queue config
#############################
maximal_queue_lifetime = 1h
bounce_queue_lifetime = 1h
maximal_backoff_time = 15m
minimal_backoff_time = 5m
queue_run_delay = 5m
#############################
### TLS config
#############################
tls_preempt_cipherlist = yes
tls_ssl_options = NO_COMPRESSION
tls_high_cipherlist = EDH+CAMELLIA:EDH+aRSA:EECDH+aRSA+AESGCM:E6:EECDH:+CAMELLIA128:+AES128:+SSLv3:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!DSS:!RC4:!SEED:!IDEA:!ECDSA:kEDH:CAMELLIA128-SHA:AES128-SHA
#############################
### outgoing SMTP (Postfix sending)
#############################
smtp_tls_security_level = dane
smtp_dns_support_level = dnssec
smtp_tls_policy_maps = mysql:/etc/postfix/sql/tls-policy.cf
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
smtp_tls_protocols = !SSLv2, !SSLv3
smtp_tls_ciphers = high
smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt
#############################
### incoming SMTP
#############################
smtpd_tls_security_level = may
smtpd_tls_protocols = !SSLv2, !SSLv3
smtpd_tls_ciphers = high
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtpd_tls_cert_file=/etc/letsencrypt/live/mail.[YOUR.DOMAIN]/fullchain.pem
smtpd_tls_key_file=/etc/letsencrypt/live/mail.[YOUR.DOMAIN]/privkey.pem
#############################
### local assignment to Dovecot
#############################
virtual_transport = lmtp:unix:private/dovecot-lmtp
#############################
### Spamfilter & DKIM through rspamd
#############################
smtpd_milters = inet:localhost:11332
non_smtpd_milters = inet:localhost:11332
milter_protocol = 6
milter_mail_macros = i {mail_addr} {client_addr} {client_name} {auth_authen}
milter_default_action = accept
#############################
### Server Restrictions (Clients, Relay, Receiptients)
### Server to server only. Client stuff is in master.cf (Submission part)
#############################
### Allow clients to forward mail, using postfix:
#############################
smtpd_relay_restrictions = reject_non_fqdn_recipient
reject_unknown_recipient_domain
permit_mynetworks
reject_unauth_destination
#############################
### Make Postfix accept incoming email, check_recipient_access checks if client is sendonly
#############################
smtpd_recipient_restrictions = check_recipient_access mysql:/etc/postfix/sql/recipient-access.cf
#############################
### SMTP-Clients requirements (sending Server)
#############################
smtpd_client_restrictions = permit_mynetworks
check_client_access hash:/etc/postfix/without_ptr
reject_unknown_client_hostname
#############################
### External servers should have valid Hostname in HELO.
#############################
smtpd_helo_required = yes
smtpd_helo_restrictions = permit_mynetworks,
permit_sasl_authenticated,
reject_invalid_helo_hostname,
reject_non_fqdn_helo_hostname,
reject_unknown_helo_hostname,
check_helo_access hash:/etc/postfix/helo_access
#############################
### Clients sending too soon need to be blocked
smtpd_data_restrictions = reject_unauth_pipelining
#############################
### MUA Restrictions (Mail User Agent)
#############################
mua_relay_restrictions = reject_non_fqdn_recipient,reject_unknown_recipient_domain,permit_mynetworks,permit_sasl_authenticated,reject
mua_sender_restrictions = permit_mynetworks,reject_non_fqdn_sender,reject_sender_login_mismatch,permit_sasl_authenticated,reject
mua_client_restrictions = permit_mynetworks,permit_sasl_authenticated,reject
#############################
### Postscreen Filter
#############################
### Postscreen Whitelist / Blocklist
postscreen_access_list = permit_mynetworks
cidr:/etc/postfix/postscreen_access
postscreen_blacklist_action = drop
#############################
### Incoming speed to high? drop connection (spam...)
#############################
postscreen_greet_action = drop
#############################
### DNS blocklists
#############################
postscreen_dnsbl_threshold = 2
postscreen_dnsbl_sites = ix.dnsbl.manitu.net*2
zen.spamhaus.org*2
postscreen_dnsbl_action = drop
#############################
### MySQL config
#############################
virtual_alias_maps = mysql:/etc/postfix/sql/aliases.cf
virtual_mailbox_maps = mysql:/etc/postfix/sql/accounts.cf
virtual_mailbox_domains = mysql:/etc/postfix/sql/domains.cf
local_recipient_maps = $virtual_mailbox_maps
#############################
### miscellaneous
#############################
mailbox_command=
mailbox_transport = lmtp:unix:private/dovecot-lmtp
#############################
### Maximal Size all Mailboxes (register with Dovecot, 0 = unlimited)
#############################
mailbox_size_limit = 0
#############################
### Maximal size incoming email in byte (50 MB)
#############################
message_size_limit = 52428800
#############################
### Notify user with new email
#############################
biff = no
#############################
### appending .domain should be done by MUA
#############################
append_dot_mydomain = no
#############################
### "Address Tagging" symbol
#############################
recipient_delimiter = +
compatibility_level = 2
EOF
cat <<'EOF'>>/etc/postfix/mysql-virtual-mailbox-domains.cf
user = mailowner
password = SomeMailPassword
hosts = 127.0.0.1
dbname = maildb
query = SELECT 1 FROM domains WHERE domain ='%s'
EOF
cat <<'EOF'>>/etc/postfix/mysql-virtual-mailbox-maps.cf
user = mailowner
password = SomeMailPassword
hosts = 127.0.0.1
dbname = maildb
query = SELECT 1 FROM users WHERE email='%s'
EOF
cat <<'EOF'>>/etc/postfix/mysql-virtual-alias-maps.cf
user = mailowner
password = SomeMailPassword
hosts = 127.0.0.1
dbname = maildb
query = SELECT destination FROM aliases WHERE source='%s' and enabled=1
EOF
cat <<'EOF'>>/etc/postfix/mysql-virtual-email2email.cf
user = mailowner
password = SomeMailPassword
hosts = 127.0.0.1
dbname = maildb
query = SELECT email FROM users WHERE email='%s'
EOF
cat <<'EOF'>>/etc/postfix/helo_access
[YOUR.DOMAIN] REJECT Get lost - you are not who you say you are!
mail[YOUR.DOMAIN] REJECT Get lost - you are not who you say you are!
imap.[YOUR.DOMAIN] REJECT Get lost - you are not who you say you are!
smtp.[YOUR.DOMAIN] REJECT Get lost - you are not who you say you are!
www.[YOUR.DOMAIN] REJECT Get lost - you are not who you say you are!
EOF
service postfix restart
postmap /etc/postfix/helo_access
service postfix reload
Now, TEST the entries:
postmap -q [YOUR.DOMAIN] mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf (result: 1)
postmap -q admin@[YOUR.DOMAIN] mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf (result: 1)
postmap -q webmaster@[YOUR.DOMAIN] mysql:/etc/postfix/mysql-virtual-alias-maps.cf (no result)
postmap -q info@[YOUR.DOMAIN] mysql:/etc/postfix/mysql-virtual-alias-maps.cf (result: frank@[YOUR.DOMAIN])
cp /etc/postfix/master.cf /etc/postfix/master.cf.bak
vi /etc/postfix/master.cf:
#
# Postfix master process configuration file. For details on the format
# of the file, see the master(5) manual page (command: "man 5 master" or
# on-line: http://www.postfix.org/master.5.html).
#
# Do not forget to execute "postfix reload" after editing this file.
#
# ==========================================================================
# 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
-o smtpd_sasl_auth_enable=no
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_sasl_type=dovecot
-o smtpd_sasl_path=private/auth
-o smtpd_sasl_security_options=noanonymous
# -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=$mua_client_restrictions
-o smtpd_relay_restrictions=$mua_relay_restrictions
-o smtpd_sender_login_maps=mysql:/etc/postfix/sql/sender-login-maps.cf
-o smtpd_helo_required=no
-o smtpd_helo_restrictions=
-o cleanup_service_name=submission-header-cleanup
-o milter_macro_daemon_name=ORIGINATING
#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
cleanup unix n - y - 0 cleanup
qmgr unix n - n 300 1 qmgr
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
#
# Clean up MUA header:
submission-header-cleanup unix n - n - 0 cleanup
-o header_checks=regexp:/etc/postfix/submission_header_cleanup
# ====================================================================
# Interfaces to non-Postfix software. Be sure to examine the manual
# pages of the non-Postfix software to find out what options it wants.
#
# Many of the following services use the Postfix pipe(8) delivery
# agent. See the pipe(8) man page for information about ${recipient}
# and other message envelope options.
# ====================================================================
#
# maildrop. See the Postfix MAILDROP_README file for details.
# Also specify in main.cf: maildrop_destination_recipient_limit=1
#
maildrop unix - n n - - pipe
flags=DRhu user=vmail argv=/usr/bin/maildrop -d ${recipient}
#
# ====================================================================
#
# Recent Cyrus versions can use the existing "lmtp" master.cf entry.
#
# Specify in cyrus.conf:
# lmtp cmd="lmtpd -a" listen="localhost:lmtp" proto=tcp4
#
# Specify in main.cf one or more of the following:
# mailbox_transport = lmtp:inet:localhost
# virtual_transport = lmtp:inet:localhost
#
# ====================================================================
#
# Cyrus 2.1.5 (Amos Gouaux)
# Also specify in main.cf: cyrus_destination_recipient_limit=1
#
#cyrus unix - n n - - pipe
# user=cyrus argv=/cyrus/bin/deliver -e -r ${sender} -m ${extension} ${user}
#
# ====================================================================
# Old example of delivery via Cyrus.
#
#old-cyrus unix - n n - - pipe
# flags=R user=cyrus argv=/cyrus/bin/deliver -e -m ${extension} ${user}
#
# ====================================================================
#
# See the Postfix UUCP_README file for configuration details.
#
uucp unix - n n - - pipe
flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)
#
# Other external delivery methods.
#
ifmail unix - n n - - pipe
flags=F user=ftn argv=/usr/lib/ifmail/ifmail -r $nexthop ($recipient)
bsmtp unix - n n - - pipe
flags=Fq. user=bsmtp argv=/usr/lib/bsmtp/bsmtp -t$nexthop -f$sender $recipient
scalemail-backend unix - n n - 2 pipe
flags=R user=scalemail argv=/usr/lib/scalemail/bin/scalemail-store ${nexthop} ${user} ${extension}
mailman unix - n n - - pipe
flags=FR user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py
${nexthop} ${user}
chmod -R o-rwx /etc/postfix
service postfix restart
cat<<"EOF'>>/etc/postfix/submission_header_cleanup
##########
### MUA header cleanup - this file is referenced in master.cf
#########
/^Received:/ IGNORE
/^X-Originating-IP:/ IGNORE
/^X-Mailer:/ IGNORE
/^User-Agent:/ IGNORE
Virtual Mail setup
mkdir -p /var/vmail/mailboxes
mkdir -p /var/vmail/sieve/global
chown -R vmail /var/vmail
chgrp -R vmail /var/vmail
chmod -R 770 /var/vmail
## Create the mail user - there is a standard "mail" one, so we'll create a virtual one:
adduser --disabled-login --disabled-password --home /var/vmail vmail
Dovecot - Mail User Agent
service stop dovecot
rm -rf /etc/dovecot/*
cat <<'EOF'>>/etc/dovecot/dovecot.conf
#############################
### Activated Protocols
#############################
protocols = imap lmtp sieve
#############################
### SSL Config
#############################
ssl = required
ssl_cert = </etc/letsencrypt/live/mail.[YOUR.DOMAIN]/fullchain.pem
ssl_key = </etc/letsencrypt/live/mail.[YOUR.DOMAIN]/privkey.pem
ssl_dh_parameters_length = 4096
ssl_protocols = !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
#############################
### Dovecot services
#############################
service imap-login {
inet_listener imap {
port = 0
}
inet_listener imaps {
port = 993
ssl = yes
}
}
service managesieve-login {
inet_listener sieve {
port = 4190
}
}
service lmtp {
unix_listener /var/spool/postfix/private/dovecot-lmtp {
# mode = 0660
mode = 0600
group = postfix
user = postfix
}
# user = vmail
}
service auth {
### Postfix Auth socket
unix_listener /var/spool/postfix/private/auth {
mode = 0660
user = postfix
group = postfix
}
### LMTP Auth socket
unix_listener auth-userdb {
mode = 0660
user = vmail
group = vmail
}
}
#############################
### Protocol settings
#############################
protocol imap {
mail_plugins = $mail_plugins quota imap_quota imap_sieve
mail_max_userip_connections = 20
imap_idle_notify_interval = 29 mins
}
protocol lmtp {
postmaster_address = postmaster@[YOUR.DOMAIN]
mail_plugins = $mail_plugins sieve
}
#############################
### Client authentication
#############################
disable_plaintext_auth = yes
auth_mechanisms = plain login
passdb {
driver = sql
args = /etc/dovecot/dovecot-sql.conf
}
userdb {
driver = sql
args = /etc/dovecot/dovecot-sql.conf
}
#############################
### Mail location
#############################
mail_uid = vmail
mail_gid = vmail
mail_privileged_group = vmail
mail_home = /var/vmail/mailboxes/%d/%n
mail_location = maildir:~/mail:LAYOUT=fs
#############################
### Mailbox configuration
#############################
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
}
}
#############################
### Mail plugins
#############################
plugin {
sieve_plugins = sieve_imapsieve sieve_extprograms
sieve_before = /var/vmail/sieve/global/spam-global.sieve
sieve = file:/var/vmail/sieve/%d/%n/scripts;active=/var/vmail/sieve/%d/%n/active-script.sieve
###
### Spam learning
###
# From elsewhere to Spam folder
imapsieve_mailbox1_name = Spam
imapsieve_mailbox1_causes = COPY
imapsieve_mailbox1_before = file:/var/vmail/sieve/global/learn-spam.sieve
# From Spam folder to elsewhere
imapsieve_mailbox2_name = *
imapsieve_mailbox2_from = Spam
imapsieve_mailbox2_causes = COPY
imapsieve_mailbox2_before = file:/var/vmail/sieve/global/learn-ham.sieve
sieve_pipe_bin_dir = /usr/bin
sieve_global_extensions = +vnd.dovecot.pipe
quota = maildir:User quota
quota_exceeded_message = Gebruiker %u gebruikt meer ruimte dan toegestaan. / User %u has exhausted allowed storage space.
}
EOF
Dovecot (MUA) - connect to MariaDb
cat<<'EOF'>>/etc/dovecot/dovecot-sql.conf
# There are a few special variables you can use, eg.:
#
# %u - username
# %n - user part in user@domain, same as %u if there's no domain
# %d - domain part in user@domain, empty if there's no domain
# %h - home directory
#
driver=mysql
connect = "host=127.0.0.1 dbname=maildb user=mailowner password=SomeMailPassword"
default_pass_scheme = SHA512-CRYPT
# select u.email as user, d.domain as domain from users u, domains d where u.domain_id = d.id;
password_query = SELECT email AS user, password FROM users where email = '%u' AND enabled = true;
user_query = SELECT concat('*:storage=', quota, 'M') AS quota_rule FROM users WHERE email = '%u' AND sendonly = false;
iterate_query = SELECT u.email as username, d.domain FROM users u, domains d where u.domain_id = d.id AND u.sendonly = false;
EOF
chmod 440 /etc/dovecot/dovecot-sql.conf
Files, mentioned in main.cf
mkdir /etc/postfix/sql
cd /etc/postfix/sql
cat<<'EOF'>>accounts.cf
user = mailowner
password = SomeMailPassword
hosts = 127.0.0.1
dbname = maildb
query = select 1 as found FROM users WHERE email = '%s' AND enabled = true LIMIT 1;
EOF
cat<<'EOF'>>aliases.cf:
user = mailowner
password = SomeMailPassword
hosts = 127.0.0.1
dbname = maildb
query = select destination FROM aliases WHERE source = '%s' AND enabled=TRUE
EOF
cat<<'EOF'>>domains.cf:
user = mailowner
password = SomeMailPassword
hosts = 127.0.0.1
dbname = maildb
query = select domain FROM domains WHERE domain='%s'
EOF
cat<<'EOF'>>recipient-access.cf
user = mailowner
password = SomeMailPassword
hosts = 127.0.0.1
dbname = maildb
query = select if(sendonly = true, 'REJECT', 'OK') AS access from users where email = '%s' and enabled = true LIMIT 1;
EOF
cat<<'EOF'>>sender-login-maps.cf
user = mailowner
password = SomeMailPassword
hosts = 127.0.0.1
dbname = maildb
query = select email as 'owns' from users where email = '%s' AND enabled=TRUE union select destination as 'owns' from aliases where source = '%s' AND enabled=TRUE
EOF
cat<<'EOF'>>tls-policy.cf
# option not being used
user = mailowner
password = SomeMailPassword
hosts = 127.0.0.1
dbname = maildb
query = SELECT policy, params FROM tlspolicies WHERE domain = '%s'
EOF
cat<<'EOF'>>/etc/postfix/without_ptr
# use postmap /etc/postfix/without_ptr
127.0.0.1 OK
EOF
# make postfix aware... Need to do after every alteration...
postmap /etc/postfix/without_ptr
touch /etc/postfix/postscreen_access
chmod -R 640 /etc/postfix/sql
service postfix restart
Anti Spam - filter & rspamd
cat<<'EOF'>>/var/vmail/sieve/global/spam-global.sieve
require "fileinto";
if header :contains "X-Spam-Flag" "YES" {
fileinto "Spam";
}
if header :is "X-Spam" "Yes" {
fileinto "Spam";
}
EOF
cat<<'EOF'>>/var/vmail/sieve/global/learn-spam.sieve
require ["vnd.dovecot.pipe", "copy", "imapsieve"];
pipe :copy "rspamc" ["learn_spam"];
EOF
cat<<'EOF'>>/var/vmail/sieve/global/learn-ham.sieve
require ["vnd.dovecot.pipe", "copy", "imapsieve"];
pipe :copy "rspamc" ["learn_ham"];
EOF
apt install -y lsb-release
wget -O- https://rspamd.com/apt-stable/gpg.key | apt-key add -
echo "deb http://rspamd.com/apt-stable/ $(lsb_release -c -s) main" > /etc/apt/sources.list.d/rspamd.list
echo "deb-src http://rspamd.com/apt-stable/ $(lsb_release -c -s) main" >> /etc/apt/sources.list.d/rspamd.list
apt update
apt install -y rspamd
systemctl stop rspamd
cd /etc/rspamd/local.d/
cat<<'EOF'>>/etc/rspamd/local.d/options.inc
local_addrs = "127.0.0.0/8, ::1";
dns {
nameserver = ["192.168.4.200:53:10"];
}
EOF
cat<<'EOF'>>worker-normal.inc
bind_socket = "localhost:11333";
### Number of Workers. Defaults to # of cores (4).
# count = 1
EOF
root@mail:/etc/rspamd/local.d# rspamadm help
Rspamadm 1.7.4
Usage: rspamadm [global_options] command [command_options]
Available commands:
pw Manage rspamd passwords
keypair Create encryption key pairs
configtest Perform configuration file test
fuzzy_merge Merge fuzzy databases
configdump Perform configuration file dump
control Manage rspamd main control interface
confighelp Shows help for configuration options
statconvert Convert statistics from sqlite3 to redis
fuzzyconvert Convert fuzzy hashes from sqlite3 to redis
grep Search for patterns in rspamd logs
signtool Sign and verify files tool
lua Run LUA interpreter
dkim_keygen Create dkim key pairs
configwizard Perform guided configuration for Rspamd daemon
corpus_test Create logs files from email corpus
rescore Estimate optimal symbol weights from log files
root@mail:/etc/rspamd/local.d# rspamadm pw
[YOUR.RSPAMD.PASSWORD]
$2$7..(snipped)..db
cat<<'EOF'>>worker-controller.inc
password=$2$7..(snipped)..db
EOF
cat<<'EOF'>>worker-proxy.inc
bind_socket = "localhost:11332";
milter = yes;
timeout = 120s;
upstream "local" {
default = yes;
self_scan = yes;
}
EOF
cat<<'EOF'>>logging.inc
type = "file";
filename = "/var/log/rspamd/rspamd.log";
level = "error";
debug_modules = [];
EOF
cat<<'EOF'>>milter_headers.conf
use = ["x-spamd-bar", "x-spam-level", "authentication-results"];
authenticated_headers = ["authentication-results"];
EOF
cat<<'EOF'>>classifier-bayes.conf
backend = "redis";
EOF
DKIM
mkdir /var/lib/rspamd/dkim/
rspamadm dkim_keygen -b 2048 -s 2018 -k /var/lib/rspamd/dkim/2018.key > /var/lib/rspamd/dkim/2018.txt
chown -R _rspamd:_rspamd /var/lib/rspamd/dkim
chmod 440 /var/lib/rspamd/dkim/*
cat /var/lib/rspamd/dkim/2018.txt (it's the DKIM DNS record!)
2018._domainkey IN TXT ( "v=DKIM1; k=rsa; "
"p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzi6rHX6lDrUSsteJFB1r4tv6y+rJ8Yb9Ma6Bf+B0hdLAqh2JBoV1TiqNu8ChuR795wsm6NzwG6l+zU6OxtzsahjwqothX8AFEdpdR0ToagUpVUB6h8VkWds4GtUcw/GLJDt7L++hUUcnMK2yZ0gbeD2hC1dLeDSiA20CHyesIAAld+8QpHQx9uPEKSmUo0JBGLEys5F3NbSv/mBIa"
"aha2GPJU6sIb6KVArXp9wFCUaXT26qiEIXck0upcLE7ml9zzUgmyHkqp723o9RW9YJ87GyNk6rzRN5aIUNBeKpcQyTaDHL/UlR8tl31WChw0Tq0vA1WXaHEwV1xf5SBhhElzQIDAQAB"
) ;
Add a TXT record, named 2018._domainkey.
It should contain all between the quotes, without the quotes, extra whitespace, etc:
v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzi6rHX6lDrUSsteJFB1r4tv6y+rJ8Yb9Ma6Bf+B0hdLAqh2JBoV1TiqNu8ChuR795wsm6NzwG6l+zU6OxtzsahjwqothX8AFEdpdR0ToagUpVUB6h8VkWds4GtUcw/GLJDt7L++hUUcnMK2yZ0gbeD2hC1dLeDSiA20CHyesIAAld+8QpHQx9uPEKSmUo0JBGLEys5F3NbSv/mBIaaha2GPJU6sIb6KVArXp9wFCUaXT26qiEIXck0upcLE7ml9zzUgmyHkqp723o9RW9YJ87GyNk6rzRN5aIUNBeKpcQyTaDHL/UlR8tl31WChw0Tq0vA1WXaHEwV1xf5SBhhElzQIDAQAB
cat<<'EOF'>>/etc/rspamd/local.d/dkim_signing.conf
path = "/var/lib/rspamd/dkim/$selector.key";
selector = "2018";
### Enable DKIM signing for alias sender addresses
allow_username_mismatch = true;
EOF
Copy to ARC (see: https://rspamd.com/doc/modules/arc.html) config:
cp -R /etc/rspamd/local.d/dkim_signing.conf /etc/rspamd/local.d/arc.conf
Redis cache
apt install -y redis-server
cat<<'EOF'>>/etc/rspamd/local.d/redis.conf
servers = "127.0.0.1";
EOF
systemctl start rspamd
FINALIZE
Add users
Add email users to the database. The passwords are encrypted, and need some work to generate:
doveadm pw -s SHA512-CRYPT
Enter new password: [PASSWORD FOR MAIL USER GOES HERE]
retype new password: [ Same Password ]
{SHA512-CRYPT}$6$...(snipped)...
mysql -p
use maildb
insert into users (domain_id, password , email, enabled, sendonly)
values (1, '{SHA512-CRYPT}$6$...(snipped)...', 'frank@[YOUR.DOMAIN]',true, false);
Repeat for admin@[YOUR.DOMAIN] (send-only account):
insert into users (domain_id, password , email, enabled, sendonly)
values (1, '{SHA512-CRYPT}$6$...(snipped)...', 'admin@[YOUR.DOMAIN]',true, true);
Connect
Connecting your email program is not straightforward (that is: androids wizards will fail); the account to be used is frank@[YOUR.DOMAIN], not just frank.The server uses SSL/TLS on port 993 for IMAP, and STARTTLS on port 587 for SMTP.
You may use imap.[YOUR.DOMAIN] for imap (incoming) mail, smtp.[YOUR.DOMAIN] as sending server, of mail.[YOUR.DOMAIN] for either, or both. Your choice.
You will have to go into the details to alter the username; it will probably default to frank where it should be frank@[YOUR.DOMAIN].