Centralized mail relay server on CentOS 7

Lets say you have dozens or hundreds of servers that all need to send mail out directly to the internet. This becomes a headache as you need to open up your firewall to allow all these servers outbound access over port 25 and your mail logs are scattered among all those servers.

Having a centralized mail relay server solves for this by serving as a central location for mail logs and only opening the firewall for one server to allow outbound port 25 access. All the other servers simply send their mail to this central mail relay server to handle sending mail, which alleviates the need for unnecessary outbound access for those other nodes.

This guide will discuss how to setup a centralized mail relay server for the sole purpose of sending only outbound email. The servers used in this guide as an example will be:

smtp-relay001.example.com - 192.168.1.100
web01.example.com - 192.168.1.101
web02.example.com - 192.168.1.102

There are some basic prerequisites that must be meet before beginning to help ensure successful email delivery:

  • The hostname of the relay server must be a FQDN, ie: smtp-relay001.example.com
  • There must be a corresponding A record setup in DNS that matches the hostname
  • There must be a corresponding PTR record (reverse DNS) setup in that matches the hostname
  • Setup an SPF record in DNS for your central mail relay server
  • Ensure your relay server is configured to ONLY accept mail from your private network to prevent it from becoming an open relay!

To reiterate the last point, ensure that your central mail relay server ONLY accepts mail from your private network. Opening it up to the world makes you an open relay which will get you blacklisted quickly. Use a dedicated firewall to block inbound 25 and 587 access to the relay server for added protection against a configuration error.

Setup central mail relay server (smtp-relay001.example.com)

First, confirm your hostname is setup properly:

[root@smtp-relay001 ~]# vim /etc/hosts
...
192.168.1.100 smtp-relay001.example.com smtp-relay001
...

[root@smtp-relay001 ~]# hostnamectl set-hostname smtp-relay001.example.com
[root@smtp-relay001 ~]# hostname smtp-relay001.example.com
[root@smtp-relay001 ~]# systemctl restart rsyslog

Now install postfix if it is not already installed:

[root@smtp-relay001 ~]# yum install postfix
[root@smtp-relay001 ~]# systemctl enable postfix

Set postfix to listen on your private IP address and only answer to servers within your network, which in my case is the 192.168.1.0/24 network:

[root@smtp-relay001 ~]# vim /etc/postfix/main.cf
...
inet_interfaces = 192.168.1.100
mydestination = $myhostname, localhost.$mydomain, $mydomain
mynetworks = 192.168.1.0/24, 127.0.0.0/8
...

Then setup a SSL certificate for use with TLS:

[root@smtp-relay001 ~]# openssl genrsa -out /etc/postfix/server.key 2048
[root@smtp-relay001 ~]# openssl req -new -x509 -key /etc/postfix/server.key -out /etc/postfix/server.crt -days 3650
[root@smtp-relay001 ~]# chmod 600 /etc/postfix/server.key

Add the following TLS configuration to the bottom of the postfix configuration:

[root@smtp-relay001 ~]# vim /etc/postfix/main.cf
...
# Enable TLS
smtpd_use_tls = yes
smtpd_tls_key_file = /etc/postfix/server.key
smtpd_tls_cert_file = /etc/postfix/server.crt
smtpd_tls_loglevel = 1
smtpd_tls_received_header = yes
smtpd_tls_session_cache_timeout = 3600s
tls_random_source = dev:/dev/urandom
smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1

Set the server to accept TLS connections by:

[root@smtp-relay001 ~]# vim /etc/postfix/master.cf
...
submission inet n       -       n       -       -       smtpd
  -o syslog_name=postfix/submission
  -o smtpd_tls_security_level=encrypt
...

Confirm postfix syntax looks good

[root@smtp-relay001 ~]# postfix check

Now restart Postfix to apply the changes:

[root@smtp-relay001 ~]# systemctl restart postfix

Finally, open up the software firewall (or the dedicated firewall) to allow inbound 25 and 587 requests from other servers within your private network by:

# Firewalld
[root@smtp-relay001 ~]# firewall-cmd --permanent --new-zone=postfix
[root@smtp-relay001 ~]# firewall-cmd --permanent --zone=postfix --add-port=25/tcp
[root@smtp-relay001 ~]# firewall-cmd --permanent --zone=postfix --add-port=587/tcp
[root@smtp-relay001 ~]# firewall-cmd --permanent --zone=postfix --add-source=192.168.1.0/24
[root@smtp-relay001 ~]# firewall-cmd --reload

# iptables
[root@smtp-relay001 ~]# vim /etc/sysconfig/iptables
...
-A INPUT -p tcp -m tcp --dport 25 -s 192.168.1.0/24 -m comment --comment "postfix" -j ACCEPT
-A INPUT -p tcp -m tcp --dport 587 -s 192.168.1.0/24 -m comment --comment "postfix" -j ACCEPT
...
[root@smtp-relay001 ~]# service iptables restart

Setup client servers running postfix to relay through smtp-relay001

First, confirm postfix is installed:

[root@web01 ~]# yum install postfix
[root@web01 ~]# systemctl enable postfix

Configure postfix to relay mail to smtp-relay001, only accept mail from localhost, and configure the relay host:

[root@web01 ~]# vim /etc/postfix/main.cf
...
inet_interfaces = loopback-only
mydestination= # leave blank
myhostname = ENTER_SERVER_HOSTNAME_HERE
mynetworks=127.0.0.0/8 [::1]/128
myorigin = $myhostname
relayhost = 192.168.1.100
local_transport=error: local delivery disabled
...

Confirm postfix syntax looks good:

[root@web01 ~]# postfix check

Restart postfix to apply the changes:

[root@web01 ~]# systemctl restart postfix

Confirm email can send outbound by sending a message, then checking the mail logs to ensure you see it relay through the relay server:

[root@web01 ~]# yum install mailx
[root@web01 ~]# echo "Testing" | mail -s "Test from web01" [email protected]
[root@web01 ~]# tail -f /var/log/maillog

Setup client servers running sendmail to relay through smtp-relay001

While I rarely run across sendmail nowadays, there are still some servers that are using it. If one of your servers is running sendmail, you can set the relay host by replacing DS with DS192.168.1.100 in your sendmail configuration as shown below:

[root@web01 ~]# vim /etc/mail/sendmail.cf
...
DS192.168.1.100
...
[root@web01 ~]# service sendmail restart

Confirm email can send outbound by sending a message, then checking the mail logs to ensure you see it relay through the relay server:

[root@web01 ~]# yum install mailx
[root@web01 ~]# echo "Testing" | mail -s "Test from web01" [email protected]
[root@web01 ~]# tail -f /var/log/maillog  # or /var/log/mail.log

Postfix – Flush mail queue

I have seen servers where the Postfix mail queue is jammed up with mail, perhaps from a programming error on the application, or maybe spam if they were web hacked. During these times, you may just want to purge the queue since you don’t want the messages going out. Below are some very simple methods of doing this:

How to remove all mail in the postfix queue:

[root@web01 ~]# postsuper -d ALL

How to remove all email in the deferred queue

[root@web01 ~]# postsuper -d ALL deferred

Remove all email in the queue for a specific domain:

[root@web01 ~]# postqueue -p | tail -n +2 | awk 'BEGIN { RS = "" } /@example\.com/ { print $1 }' | tr -d '*!' | postsuper -d -

Remove all email in the queue from a specific email address:

[root@web01 ~]# postqueue -p | tail -n +2 | awk 'BEGIN { RS = "" } /user@example\.com/ { print $1 }' | tr -d '*!' | postsuper -d -