Prerequisite : https://www.sandeeprao.net/preparing-for-configuring-secure-mail-server-using-postfix-dovecot-spamassassin-and-opendkim/
Install required packages
#apt install -y razor #apt install -y amavisd-new dovecot-core dovecot-imapd dovecot-lmtpd dovecot-mysql dovecot-sieve haveged mailutils mariadb-server opendkim opendkim-tools p7zip postfix postfix-mysql postgrey spamassassin
Create require vmail user and group
#groupadd -g 5000 vmail
#useradd -g vmail -u 5000 vmail -d /var/vmail
Create mailbox directory
#mkdir -p /var/vmail
#chown -R vmail:vmail /var/vmail
Secure mariadb (set password for root user, default answers) and create postfix database, user table and aliases table
root@vm:~# mysql_secure_installation ... Set root password? [Y/n] Y New password: Re-enter new password: Password updated successfully! ... Remove anonymous users? [Y/n] Y ... Disallow root login remotely? [Y/n] Y ... Remove test database and access to it? [Y/n] Y ... Reload privilege tables now? [Y/n] Y … Success! Cleaning up… All done! If you've completed all of the above steps, your MariaDB installation should now be secure. Thanks for using MariaDB! root@vm:~# mysql -uroot -p Enter password: ... ... MariaDB [(none)]> CREATE DATABASEpostfix
; Query OK, 1 row affected (0.000 sec) MariaDB [(none)]> GRANT SELECT ONpostfix
.* TOpostfix
@127.0.0.1
IDENTIFIED BY 'postfix'; Query OK, 0 rows affected (0.000 sec) MariaDB [(none)]> FLUSH PRIVILEGES; Query OK, 0 rows affected (0.000 sec) MariaDB [(none)]> USE postfix; Database changed MariaDB [postfix]> CREATE TABLEdomains
( ->id
int(11) NOT NULL auto_increment, ->domain
varchar(50) NOT NULL, -> PRIMARY KEY (id
) -> ) ENGINE=InnoDB DEFAULT CHARSET=utf8; Query OK, 0 rows affected (0.013 sec) MariaDB [postfix]> CREATE TABLEusers
( ->id
int(11) NOT NULL auto_increment, ->domain
int(11) NOT NULL, ->password
varchar(106) NOT NULL, ->id
), -> UNIQUE KEYaliases
( ->id
int(11) NOT NULL auto_increment, ->domain
int(11) NOT NULL, ->source
varchar(100) NOT NULL, ->destination
varchar(100) NOT NULL, -> PRIMARY KEY (id
), -> FOREIGN KEY (domain) REFERENCES domains(id) ON DELETE CASCADE -> ) ENGINE=InnoDB DEFAULT CHARSET=utf8; Query OK, 0 rows affected (0.008 sec) MariaDB [postfix]> exit Bye root@vm:~#
Update postfix configurations. Edit /etc/postfix/master.cf . I understand that smtpd_delay_reject is required for the combinations of restrictions I had applied.
submission inet n - y - - smtpd -o smtpd_tls_security_level=encrypt -o content_filter= amavis unix - - n - 2 smtp -o smtp_send_xforward_command=yes -o smtp_tls_security_level=none 127.0.0.1:10025 inet n - n - - smtpd -o content_filter=
Update /etc/postfix/main.cf – Comment out all configurations and add the following. Note: 10.1.1.0 and 192.168.100.0 are two network subnets from where I connect to my server (mynetworks configuration – change it matching yours). Since this is public internet facing server, did not add smtpd_use_tls and smtp_use_tls.
Edit /etc/postfix/main.cf (Final contents of edited file below in my case – except for change in domain name)
#Retained biff = no append_dot_mydomain = no readme_directory = no mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 10.1.2.0/24 10.1.3.0/24 10.1.4.0/24 10.1.5.0/24 192.168.100.0/24 smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated permit_auth_destination defer_unauth_destination #Added or modified existing smtp_bind_address = 0.0.0.0 alias_maps = hash:/etc/aliases compatibility_level = 2 mailbox_size_limit = 0 myhostname = mail.example.com recipient_delimiter = + inet_protocols = ipv4 smtpd_banner = $myhostname ESMTP content_filter = amavis:[127.0.0.1]:10024 message_size_limit = 20480000 non_smtpd_milters = inet:[127.0.0.1]:12301 smtpd_milters=inet:[127.0.0.1]:12301 smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_invalid_hostname, reject_non_fqdn_hostname, reject_non_fqdn_sender, reject_non_fqdn_recipient, reject_unknown_sender_domain, r$ smtpd_sasl_auth_enable = yes smtpd_sasl_path = private/auth smtpd_sasl_type = dovecot smtpd_tls_CApath = /etc/ssl/certs smtpd_tls_cert_file = /etc/letsencrypt/live/example.com/fullchain.pem smtpd_tls_key_file = /etc/letsencrypt/live/example.com/privkey.pem smtpd_tls_eecdh_grade = strong smtpd_tls_security_level = may smtp_header_checks = regexp:/etc/postfix/header_checks smtp_mime_header_checks = regexp:/etc/postfix/header_checks smtp_tls_CApath = /etc/ssl/certs smtp_tls_cert_file = $smtpd_tls_cert_file smtp_tls_key_file = $smtpd_tls_key_file smtp_tls_security_level = may smtp_use_tls = yes tls_preempt_cipherlist = yes virtual_alias_maps = mysql:/etc/postfix/mysql_virtual_alias_emails.cf, mysql:/etc/postfix/mysql_virtual_alias_maps.cf virtual_gid_maps = static:5000 virtual_mailbox_base = /var/vmail virtual_mailbox_domains = mysql:/etc/postfix/mysql_virtual_mailbox_domains.cf virtual_mailbox_maps = mysql:/etc/postfix/mysql_virtual_mailbox_maps.cf virtual_transport = lmtp:unix:private/dovecot-lmtp virtual_uid_maps = static:5000
Update Mariadb credentials for the postfix operations
Edit /etc/postfix/mysql_virtual_mailbox_domains.cf
user = postfix
password = postfix
hosts = 127.0.0.1
dbname = postfix
query = SELECT 1 FROM domains WHERE domain='%s'
Edit /etc/postfix/mysql_virtual_mailbox_maps.cf
user = postfix
password = postfix
hosts = 127.0.0.1
dbname = postfix
query = SELECT 1 FROM users WHERE email='%s'
Edit /etc/postfix/mysql_virtual_alias_maps.cf
user = postfix password = postfix hosts = 127.0.0.1 dbname = postfix query = SELECT destination FROM aliases WHERE source='%s'
Edit /etc/postfix/mysql_virtual_alias_emails.cf
user = postfix password = postfix hosts = 127.0.0.1 dbname = postfix query = SELECT email FROM users WHERE email='%s'
Prevent outgoing mails from leaking privacy related information like internal IP addresses or the mail client’s name.
Edit /etc/postfix/header_checks
/^Received:.*with ESMTP/ IGNORE /^X-Mailer:/ IGNORE /^User-Agent:/ IGNORE /^Mime-Version:/ IGNORE
Generate Postfix map
postmap /etc/postfix/header_checks
Generate alias map
newaliases
Restart Postfix service
systemctl restart postfix
Update Dovecot configuration – Add the following at the end of configuraiton file
listen = * mail_location = maildir:/var/vmail/%d/%n/ protocols = imap lmtp ssl = required ssl_cert = < /etc/letsencrypt/live/example.com/fullchain.pem ssl_key = < /etc/letsencrypt/live/example.com/privkey.pem ssl_prefer_server_ciphers = yes namespace inbox { inbox = yes location = separator = / mailbox Drafts { auto = subscribe special_use = \Drafts } mailbox "Sent Messages" { auto = subscribe special_use = \Sent } mailbox Junk { auto = subscribe special_use = \Junk } mailbox "Deleted Messages" { auto = subscribe special_use = \Trash } mailbox Archive { auto = subscribe special_use = \Archive } mailbox Notes { auto = subscribe } } passdb { driver = sql args = /etc/dovecot/dovecot-sql.conf.ext } userdb { driver = static args = uid=vmail gid=vmail home=/var/vmail/%d/%n } service auth { unix_listener /var/spool/postfix/private/auth { group = postfix mode = 0660 user = postfix } unix_listener auth-userdb { mode = 0600 user = vmail } user = dovecot } service auth-worker { user = vmail } service imap-login { inet_listener imap { port = 0 } inet_listener imaps { port = 993 } } service lmtp { unix_listener /var/spool/postfix/private/dovecot-lmtp { group = postfix mode = 0600 user = postfix } } protocol lmtp { postmaster_address = postmaster@example.com hostname = example.com mail_plugins = sieve } plugin { sieve_before = /etc/dovecot/spam.sieve }
Update Mariadb configurations :
Edit /etc/dovecot/dovecot-sql.conf.ext
driver = mysql connect = host=127.0.0.1 dbname=postfix user=postfix password=postfix default_pass_scheme = SHA512-CRYPT password_query = SELECT email as user, password FROM users WHERE email='%u';
Edit /etc/dovecot/spam.sieve
require ["fileinto", "imap4flags"]; if header :contains "X-Spam-Flag" "YES" { setflag "\\Seen"; fileinto "Junk"; stop; }
Compile Sieve spam rules
sievec /etc/dovecot/spam.sieve
Restart Dovecot service
systemctl restart dovecot
Antispam configurations :
Update Greylisting whitelist
wget -O /etc/postgrey/whitelist_clients https://raw.githubusercontent.com/schweikert/postgrey/master/postgrey_whitelist_clients
Restart post-grey service
systemctl restart postgrey
Edit /etc/opendkim.conf (comment out all existing configurations and add the following at the end of configuraiton file)
AutoRestart Yes AutoRestartRate 10/1h UMask 002 Syslog yes SyslogSuccess Yes LogWhy Yes Canonicalization relaxed/simple ExternalIgnoreList refile:/etc/opendkim/TrustedHosts InternalHosts refile:/etc/opendkim/TrustedHosts KeyTable refile:/etc/opendkim/KeyTable SigningTable refile:/etc/opendkim/SigningTable Mode sv PidFile /var/run/opendkim/opendkim.pid SignatureAlgorithm rsa-sha256 UserID opendkim:opendkim Socket inet:12301@localhost
Create OpenDKIM config directory and
mkdir -p /etc/opendkim
Update /etc/opendkim/TrustedHosts file
127.0.0.1 localhost
Edit /etc/opendkim/KeyTable
Note : mail2019 is the selector opted by me, it can be any string, ensure that you use the same in all places.
mail2019._domainkey.example.com example.com:mail2019:/etc/opendkim/keys/example.com/mail2019.private
Edit /etc/opendkim/SigningTable
*@example.com mail2019._domainkey.example.com
Create Domain Key directory
mkdir -p /etc/opendkim/keys/
example.com
Generate Domain Key
opendkim-genkey -s mail2019 -d example.com -D /etc/opendkim/keys
/example.com
Set permissions on Domain Key
chown opendkim:opendkim /etc/opendkim/keys/example.com/mail2019.private chmod 0400 /etc/opendkim/keys/example.com /mail2019.private
Restart OpenDKIM service
systemctl restart opendkim
Get DKIM record from /etc/opendkim/keys/example.com/mail2019.txt
and create a new DNS record from it (TXT Entry – in DNS management)
Host = mail2019_.domainkey TXT value = (starting from "v=" and upto "p=xxxxxx" )
Add amavis
user to vmail
group
usermod -aG vmail amavis
Edit /etc/amavis/conf.d/50-user
Note : Yet to understand the spam scoring and related configuration. With -999 value for sa_tag_level_deflt almost all legit mails were marked as spam and moved to Spam folder. So with some little understanding have put values here for my current needs. It may not be recommended, but satisfies my needs – Check for the specific values your requirement needs.
use strict; $smtp_connection_cache_on_demand = 0; $smtp_connection_cache_enable = 0; @bypass_spam_checks_maps = ( \%bypass_spam_checks, \@bypass_spam_checks_acl, \$bypass_spam_checks_re); $sa_tag_level_deflt = 2.9; $sa_tag2_level_deflt = 2.9; $sa_kill_level_deflt = 5.0; $sa_dsn_cutoff_level = 2.9; $final_banned_destiny = D_BOUNCE; $final_spam_destiny = D_PASS; $final_bad_header_destiny = D_BOUNCE; $undecipherable_subject_tag=undef; @lookup_sql_dsn = ( ['DBI:mysql:database=postfix;host=127.0.0.1;port=3306', 'postfix', 'postfix']); $sql_select_policy = 'SELECT domain FROM domains WHERE CONCAT("@",domain) IN (%k)'; 1;
Restart Amavis service
systemctl restart amavis
Configure Spamassasin – download and extract samples (Note the URL – last part file name is dynamic – check before you use it).
cd /tmp wget http://untroubled.org/spam/2019-08.7z p7zip -d 2019-08.7z chown -R amavis:amavis 2019/ cd -
Make Spamassassin learn from spam samples to populate the local ham/spam database
su - amavis -c 'sa-learn --progress --spam /tmp/2019/'
Add cronjobs for Spamassassin (run crontab -e
)
@hourly su amavis -c 'sa-learn --ham /var/vmail/*/*/cur/'
@hourly su amavis -c 'sa-learn --spam /var/vmail/*/*/.Junk/cur/'
Initialize Razor
su - amavis -c 'razor-admin -create'
su - amavis -c 'razor-admin -register'
su - amavis -c 'razor-admin -discover'
Domains, Mailboxes & Aliases
Create domain mailbox directory
su vmail -c 'mkdir -p -m 0770 /var/vmail/example.com'
Add domain entry to MySQL database [For now this mail server will serve for one domain only 🙂 ]
INSERT INTO `postfix`.`domains` (`id` ,`domain`) VALUES ('1', 'example.com');
Add mailbox entry to MySQL database [Create users as you need – For me for now only one is required]
INSERT INTO `postfix`.`users` (`id`, `domain`, `password` , `email`) VALUES ('1', '1', ENCRYPT('<PASSWORD>', CONCAT('$6$', SUBSTRING(SHA(RAND()), -16))), 'admin@example.com');
Initialize mailbox directory (optional)
doveadm mailbox create -u admin@example.com INBOX
Configurations done – Secure mail server is up and running. Use the following information for client side configurations
IMAP: Server: datachronicles.net
Port: 993
Encryption: SSL/TLS
SMTP:Server: datachronicles.net
Port: 587
Encryption: STARTTLS
1 thought on “Configuring secure mail server using Postfix with Dovecot, Amavis, Spamassasin, Postgrey and OpenDKIM”
Comments are closed.