2021.10.07 - Postfix setup, with DKIM and Dovecot

Setting up Postfix on EL8 with DKIM signing and Dovecot for POP and SASL

Intro

There's alot to setting up a fully functional email server, and a bunch of differant ways to do it. Since I'm very much stuck in the early 2010's I like Postfix, Amavis, Clamav, Dovecot, Procmail and POP/IMAP. But I still want to follow all the current email best practices like DKIM signing for emails. In a world were most people just use Google Apps or Office 365 this puts me in a wierd place. If you also find yourself in that wierd place then this is the guide for you. Needless to say I got information for this from a bunch of different places. I'll list them below. If you are just looking to setup one part of my crazy system then you might be better off just reading that guide:

Getting Started

First you'll need to install all the things:

yum install postfix alpine postgrey postfix-pcre dovecot amavis clamav clamav-lib clamav-data clamav-update

(yes I'm stubbornly sticking to yum instead of dnf; I know they are the same command) So this will install Postfix, Alpine (cli email reader), Postgrey (for greylisting), Amavis and Clamav. If you get an error about missing Perl packages then you'll probably need to enable the powertools repo: yum config-manager --enable powertools. Once everything is installed just start at the top and work your way down configuring things. First, Postfix.

Configuring Postfix (main.cf)

So Postfix has a main.cf and master.cf file where most of the config goes. There's also a bunch of other files I'll be adding to the /etc/postfix directory. First, starting with main.cf:

myhostname = mail.5i5.org mydomain = 5i5.org myorigin = $myhostname
inet_interfaces = all inet_protocols = ipv4 # This one is important if you don't have IPv6 connectivity
mydestination = $myhostname, $mydomain mynetworks = /etc/postfix/networks virtual_maps = hash:/etc/postfix/virtual
mailbox_command = /usr/bin/procmail
body_checks_size_limit = 51200 body_checks = regexp:/etc/postfix/body_checks header_checks = regexp:/etc/postfix/header_checks mime_header_checks = regexp:/etc/postfix/mime_header_checks
smtpd_banner = $myhostname ESMTP $mail_name # the whole TLS CONFIGURATION section at the end of the file is deleted as I'll be replacing that

# Settings to enable SASL Auth with Dovecot in Postfix (still need to conf Dovecot) smtpd_sasl_type = dovecot smtpd_sasl_path = private/auth smtpd_sasl_auth_enable = yes smtpd_sasl_security_options = noanonymous smtp_sasl_security_options = noanonymous

# I choose to put all my spam filtering under smtpd_recipient_restrictions. # This means the email is only filtered once the whole message has been recevied # If you are concerned about server resources you might want to break this up. smtpd_recipient_restrictions =
permit_mynetworks, sleep 5,# in theory helps slow down people trying to bruteforce SASL passwords permit_sasl_authenticated, reject_unauth_destination,
check_recipient_access hash:/etc/postfix/rcpt, check_sender_access hash:/etc/postfix/mailfrom, ### USE /etc/postfix/postgrey_whitelist_recipients to bypass greylisting for some accounts
reject_invalid_hostname, reject_non_fqdn_hostname, check_helo_access hash:/etc/postfix/helo_access,
reject_non_fqdn_recipient, reject_non_fqdn_sender, reject_unknown_sender_domain, reject_unknown_recipient_domain,
reject_rbl_client psbl.surriel.com=127.0.0.2, reject_rbl_client b.barracudacentral.org=127.0.0.2, reject_rbl_client xbl.spamhaus.org=127.0.0.4,
reject_rhsbl_reverse_client multi.surbl.org=127.0.0.[2..254], reject_rhsbl_helo multi.surbl.org=127.0.0.[2..254], reject_rhsbl_sender multi.surbl.org=127.0.0.[2..254],
reject_unknown_reverse_client_hostname, check_policy_service unix:postgrey/socket, check_client_access pcre:/etc/postfix/default_filter.pcre
smtpd_relay_restrictions = permit_mynetworks, sleep 5, permit_sasl_authenticated, reject_unauth_destination
smtpd_data_restrictions = reject_unauth_pipelining smtpd_helo_required = yes non_fqdn_reject_code = 404 # Changed from the default of 504 in case of DNS issues disable_vrfy_command = yes
# These next lines impose limits on servers connecting, these numbers don't seem to cause any issues, # but could further optimized if you wanted to smtpd_soft_error_limit = 3 smtpd_hard_error_limit = 3 smtpd_client_connection_count_limit = 6 smtpd_client_connection_rate_limit = 10 smtpd_client_event_limit_exceptions = $mynetworks anvil_rate_time_unit = 120s
# These two lines help to avoid hitting rate limits on popular free email services smtp_destination_concurrency_limit = 1 smtp_destination_rate_delay = 10s

# Just two small last settings: smtpd_proxy_options = speed_adjust # Helps keep Amavis happy content_filter = amavisfeed:[127.0.0.1]:10023 # Feeds any local email into Amavis for DKIM signing # Remote email that passes the spam checks is feed into Amavis via the check_client_access line

Of course it's not required but encrypting communications is just a good practice now-a-days and free SSL Certs are so easy to get. I've started using acme.sh to get free Certs from Let's Encrypt. For a server just doing email and nothing else you can get a quick cert with a command like this: acme.sh --force --days 90 --issue --server letsencrypt --preferred-chain "ISRG Root X1" --cert-file /root/mail.example.com.cer --key-file /root/mail.example.com.key --fullchain-file /root/mail.example.com.fc.cer --standalone -d mail.example.com

With an SSL cert here's how to enable it in postfix:

smtp_tls_security_level = may smtp_tls_loglevel = 1 smtp_tls_cert_file = /root/mail.example.com.cer smtp_tls_key_file = /root/mail.example.com.key smtp_tls_CAfile = /root/mail.example.com.fc.cer
smtp_tls_session_cache_database = btree:/var/lib/postfix/smtp_tls_session_cache
smtp_tls_ciphers = export smtp_tls_protocols = !SSLv2
smtpd_tls_security_level = may smtpd_tls_loglevel = 1 smtpd_tls_cert_file = /root/mail.example.com.cer smtpd_tls_key_file = /root/mail.example.com.key smtpd_tls_CAfile = /root/mail.example.com.fc.cer
smtpd_tls_session_cache_database = btree:/var/lib/postfix/smtpd_tls_session_cache
smtpd_tls_eecdh_grade = strong smtpd_tls_ciphers = medium smtpd_tls_protocols = !SSLv2, !SSLv3

Configuring Postfix (master.cf)

Master.cf controls all the port and network connections that Postfix uses. We'll be enabling an alt port 587 (submission) and 465 (smtps) to receive email on and setting up some ports for Amavis.

submission inet n - n - - smtpd -o smtpd_sasl_auth_enable=yes -o smtpd_client_restrictions=permit_sasl_authenticated,permit_mynetworks,reject -o content_filter=amavisfeed:[127.0.0.1]:10023 smtps inet n - n - - smtpd -o smtpd_tls_wrappermode=yes -o smtpd_sasl_auth_enable=yes -o smtpd_client_restrictions=permit_sasl_authenticated,permit_mynetworks,reject -o content_filter=amavisfeed:[127.0.0.1]:10023
amavisfeed unix - - n - 2 lmtp -o lmtp_data_done_timeout=1200 -o lmtp_send_xforward_command=yes -o disable_dns_lookups=yes -o max_use=20 127.0.0.1:10025 inet n - n - - smtpd -o content_filter= -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 smtpd_restriction_classes= -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,no_address_mappings -o local_header_rewrite_clients= -o smtpd_milters= -o local_recipient_maps= -o relay_recipient_maps=

Configuring Postfix (Other Files)

There's a handful of other files in the /etc/postfix directory that I'll change/create:

/etc/postfix/body_checks: ~^[[:alnum:]+/]{60,}$~ OK # First skip over base 64 encoded text to save CPU cycles. # Some obvious spam email to dump: /how to purchase bitcoin/ Reject Spam line 1 /how to buy bitcoin/ Reject Spam line 2 /I hacked this mailbox/ Reject Spam line 3 /if you do not know how to do this, write to Google/ Reject Spam line 4 /Your account has been hacked by me/ Reject Spam line 5 /how to replenish btc wallet/ Reject Spam line 6 /how to transfer money to a bitcoin wallet/ Reject Spam line 7 /how to make a payment on a bitcoin wallet/ Reject Spam line 8 /how to send money to btc wallet/ Reject Spam line 9

/etc/postfix/default_filter.pcre: /./ FILTER amavisfeed:[127.0.0.1]:10024

/etc/postfix/helo_access: # Stop some obvious spammers: example.com REJECT E-mail error, please contact your ISP mail.example.com REJECT E-mail error, please contact your ISP

/etc/postfix/mailfrom: # Again, stop some obvious spammers (they would probably get caught by SPF) support@example.com Reject You cannot send out email as support support@mail.example.com Reject You cannot send out email as support info@example.com Reject You do not own this address info@mail.example.com Reject You do not own this address postmaster@mail.example.com Reject You do not own this address postmaster@example.com Reject You do not own this address

/etc/postfix/mime_header_checks: # Block undesirable email attachements /name=[^>]*\.(js|exe|vbs|pif|scr|bat|cmd|cpl|dll|rar|arc|arj|zoo|ade|adp|app|bas|bat|chm|cmd|cpl|crt|emf|exe|fxp|grp|hlp|hta|inf|ins|isp|cab|jse|lnk|mda|mde|mdw|mdt|mdz|msc|msi|msp|mst|ops|pcd|pif|prg|reg|scr|sct|shb|shs|vb|vbe|vbs|wmf|wsc|wsf|wsh)/ REJECT We are sorry, but due to complaints we are no longer able to accept emails with this kind of attachment.

/etc/postfix/networks: # List of networks that are permitted unrestricted access to Postfix 127.0.0.1/32, 192.168.200.0/24

/etc/postfix/rcpt: # List of email addresses to do minimal checking on support@example.com OK postmaster@example.com OK

/var/scripts/viup: #!/bin/bash # Handy script to run after changing a postfix/amavis/postgrey config file # to rebuild/refresh everything echo "Rebuilding Transport Database" /usr/sbin/postmap /etc/postfix/transport   echo "Rebuilding Local Virual Database" /usr/sbin/postmap /etc/postfix/virtual   echo "Rebuilding Denied Senders Database" /usr/sbin/postmap /etc/postfix/mailfrom   echo "Rebuilding Rejected Server Access Map Database" /usr/sbin/postmap /etc/postfix/rcpt /usr/sbin/postmap /etc/postfix/helo_access   echo "Rebuilding Alias Database" newaliases sleep 1   service amavisd restart service postgrey restart sleep 1   /usr/sbin/postfix reload

/etc/aliases: # Most of this file is probably fine, just set someone to get root's email root: support

Configuring Amavis

There's a ton of options for Amavis, I'll be focusing on what needs to be changed to enable spam filtering, virus scanning, and DKIM signing. First file to edit is /etc/amavisd/amavisd.conf

$mydomain = 'example.com'; $QUARANTINEDIR = "/var/virusmails"; $helpers_home = "$MYHOME/var"; @mynetworks = qw( 127.0.0.0/8 [::1] [FE80::]/10 [FEC0::]/10 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 {add other IPs here} ); $inet_socket_port = [10022,10023,10024]; $policy_bank{'MYNETS'} = { bypass_spam_checks_maps => [1], bypass_banned_checks_maps => [1], originating => 1, os_fingerprint_method => undef, }; $interface_policy{'10023'} = 'SUBMISSION'; $policy_bank{'SUBMISSION'} = {bypass_spam_checks_maps => [1], bypass_banned_checks_maps => [1], originating => 1, smtpd_discard_ehlo_keywords => ['8BITMIME'], }; $policy_bank{'ORIGINATING'} = { originating => 1, allow_disclaimers => 1, warnbadhsender => 1, forward_method => 'smtp:[127.0.0.1]:10027', smtpd_discard_ehlo_keywords => ['8BITMIME'], bypass_spam_checks_maps => [1], bypass_banned_checks_maps => [1], terminate_dsn_on_notify_success => 0, }; $sa_tag_level_deflt = -999; $virus_admin = ''; $spam_admin = ''; $mailfrom_notify_admin = "root\@$mydomain"; $mailfrom_notify_recip = "root\@$mydomain"; $mailfrom_notify_spamadmin = "root\@$mydomain"; $myhostname = 'example.com'; $notify_method = 'smtp:[127.0.0.1]:10025'; $forward_method = 'smtp:[127.0.0.1]:10025'; $final_bad_header_destiny = D_PASS; $bad_header_quarantine_method = undef;

To setup DKIM there's a couple of commands to run to prep directories and generate the key:

mkdir /etc/amavisd/dkim/ chown root:amavis /etc/amavisd/dkim/ chmod 750 /etc/amavisd/dkim/ amavisd -c /etc/amavisd/amavisd.conf genrsa /etc/amavisd/dkim/example.com.dkim2021.pem 4096

Once the key is generated add these lines to the /etc/amavisd/amavisd.conf:

dkim_key( 'example.com', 'dkim2021', '/etc/amavisd/dkim/example.com.dkim2021.pem' ); dkim_key( 'mail.example.com', 'dkim2021', '/etc/amavisd/dkim/example.com.dkim2021.pem' ); @dkim_signature_options_bysender_maps = ( { "." => { a => 'rsa-sha256', c => 'relaxed/simple', ttl => 10*24*3600 } } );

There's also some records you'll need to put in the DNS. To generate them run this command: amavisd -c /etc/amavisd/amavisd.conf showkeys example.com The TXT record that it generates is going to look weird, it's just because the TXT record is so long, it's fine, enter it as displayed (assuming you are using BIND). Then to check to see if it works run: amavisd -c /etc/amavisd/amavisd.conf testkeys example.com

The last thing to do is add some custom weights to the spamassassin config (/etc/mail/spamassassin/local.cf):

required_hits 6.5 header RCVD_IN_WPBL eval:check_rbl('wpbl-lastexternal','db.wpbl.info.','127.0.0.2') describe RCVD_IN_WPBL Listed in db.wpbl.info tflags RCVD_IN_WPBL net score RCVD_IN_WPBL 5.0 score BAYES_00 0.0 score BAYES_05 0.0 score SPF_PASS 0.0 score SPF_FAIL 6.0 score SPF_SOFTFAIL 1.0 score SPF_HELO_PASS 0.0 score SPF_HELO_FAIL 6.0 score SPF_HELO_SOFTFAIL 0.0 score LOTS_OF_MONEY 0.0 score RDNS_NONE 5.0 score URIBL_BLACK 6.5 score URIBL_DBL_SPAM 6.0 score RP_MATCHES_RCVD -0.001 score MISSING_HEADERS 3.0 score FH_FAKE_RCVD_LINE_B 2.0 score ADVANCE_FEE_3_NEW 1.0 score RCVD_IN_SORBS_SPAM 0.4 score FORGED_MUA_MOZILLA 0 score DKIM_VALID -0.5 score URI_TRY_3LD 0.0 score BITCOIN_BOMB 6.5 score BITCOIN_EXTORT_01 6.5 score BITCOIN_DEADLINE 6.5 score BITCOIN_MALWARE 6.5 score BITCOIN_PAY_ME 6.5 score BITCOIN_SPAM_07 6.5 score BITCOIN_SPAM_08 6.5 trusted_networks 192.168.0.0/16 10.0.0.0/8 internal_networks 192.168.0.0/16 10.0.0.0/8

Configuring Dovecot

So we'll be configuring Dovecot for POP3/POP3s, IMAP and SASL Auth. I only use IMAP for the local webmail so no need to waste encryption on it, only the local server can connect to it. There's a bunch of different files so just like with postfix I'll call out the file and what I changed in it.

/etc/dovecot/dovecot.conf: protocols = imap pop3 listen = *

/etc/dovecot/conf.d/10-auth.conf: disable_plaintext_auth = no # if you dont need this for legacy then PLEASE set to yes auth_username_format = %Ln auth_mechanisms = plain login

/etc/dovecot/conf.d/10-logging.conf: auth_verbose = yes auth_verbose_passwords = plain auth_debug_passwords = yes

/etc/dovecot/conf.d/10-mail.conf: mail_location = mbox:~:INBOX=/var/spool/mail/%u mail_privileged_group = mail first_valid_uid = 500 mbox_read_locks = dotlock mbox_write_locks = dotlock

/etc/dovecot/conf.d/10-master.conf: service imap-login { inet_listener imap { port = 143 } service pop3-login { inet_listener pop3 { port = 110 } inet_listener pop3s { port = 995 ssl = yes } } service auth { unix_listener /var/spool/postfix/private/auth { mode = 0660 user = postfix group = postfix } }

/etc/dovecot/conf.d/10-ssl.conf: ssl = yes ssl_cert = </root/mail.example.com.fc.cer ssl_key = </root/mail.example.com.key ssl_dh = </etc/dovecot/dh.pem #Generate this file using 'openssl dhparam -out /etc/dovecot/dh.pem 4096' ssl_min_protocol = TLSv1 ssl_prefer_server_ciphers = yes

/etc/dovecot/conf.d/15-mailboxes.conf: auto = create # add to both mailbox Drafts, Trash and Sent

/etc/dovecot/conf.d/20-pop3.conf: pop3_lock_session = no pop3_uidl_format = %08Xv%08Xu pop3_logout_format = del=%d/%m, size=%s

Configuring Postgrey

Greylisting was a great spam filtering tool when it came out. Now I'm not really sure how much of a difference it makes (other than slowing down the delivery of wanted emails). I'm leaving it configured, but it could be easily turned off in the /etc/postfix/main.cf file. There's just one file to change for postgrey:

/etc/sysconfig/postgrey: POSTGREY_DELAY="--delay=59" POSTGREY_OPTS="--lookup-by-subnet --auto-whitelist-clients=1"

Finishing Up

All that's left to do is adjust any firewall rules (at least you'll want to let port 25 and 110 through, probably also 465, 587 and 995). Then start all the services:

service clamav-freshclam start service postgrey start service amavisd start service dovecot start service postfix start

Assuming everything started ok then do some testing and if everything checks out just set the services to start automatically on boot (I like using ntsysv for that). MOST IMPORTANTLY: reboot the server after you've done all this and make sure that it still works and you didn't miss enabling auto start on anything!

-Nick