Postfix SMTP Multiple Instances with IP Rotation on a Single VPS
This tutorial is going to show you how to set up multiple instances of Postfix SMTP server with IP rotation on a single VPS (virtual private server).
Why Use Multiple IP Addresses
If you send bulk emails using a self-hosted email marketing software like Mautic, it’s a good practice to use multiple IP addresses to spread your email traffic. If mailbox providers observe a large volume of emails coming from a single IP address, then it’s likely to be identified as spam. To maintain good IP reputation, you need to slow down the email traffic sent from a single IP address.
The best Linux VPS hosting provider that allows you to have multiple IP addresses on a single host is Kamatera. The VPS starts at $4/month and each new IP address costs $1/month. Follow the tutorial linked below to create your Linux VPS server with multiple public IP addresses.
Next, you can use iRedMail to quickly set up an email server on the Kamatera VPS.
- How to Easily Set Up Your own Mail Server on Ubuntu 20.04 with iRedMail
- How to Easily Set Up Your own Mail Server on Debian 10 with iRedMail
- How to Easily Set Up Your own Mail Server on CentOS 8 with iRedMail
Once that’s done, come back here to set up Postfix multiple instances with IP rotation.
How many IP addresses should you use for email delivery?
- If you have 10K email subscribers, 1 IP address is enough.
- If you need to send 100K emails at once, I recommend at least 5 IP addresses.
Structure of Postfix Multiple Instances
Postfix SMTP server can be configured to run multiple instances on a single host. All instances share the same program files, but use a unique directory for the following files.
- Configuration files
- Spool/queue
- Data
This tutorial shows you the process of setting up 2 Postfix instances. You can use the same process to add a third, fourth, fifth… instance.
Step 1: Set Up Multiple Postfix Instances
Run the following command to initialize multi-Instance in Postfix.
sudo postmulti -e init
This will add the following two lines at the bottom of the /etc/postfix/main.cf
file.
multi_instance_wrapper = ${command_directory}/postmulti -p -- multi_instance_enable = yes
Next, create a new Postfix instance.
sudo postmulti -e create -I postfix-smtp1
where:
-e
: edit mode-I
: instance name, which must start withpostfix-
.
It automatically creates the /etc/postfix-smtp1/
directory, which includes the master.cf
and main.cf
file. The /etc/postfix-smtp1/main.cf
file has the following lines at the bottom.
readme_directory = no inet_protocols = ipv4 master_service_disable = inet authorized_submit_users = queue_directory = /var/spool/postfix-smtp1 multi_instance_name = postfix-smtp1
Change
master_service_disable = inet
to
master_service_disable =
So the postfix-smtp1
instance can bind to a TCP socket. Each Postfix instance must have a unique value for the following two parameters.
myhostname = inet_interfaces =
For example, the primary instance (/etc/postfix/main.cf
) can use
myhostname = smtp.example.com inet_interfaces = 11.22.33.44
The postfix-smtp1 instance can use
myhostname = smtp01.example.com inet_interfaces = 11.22.33.55
So each instance has a unique hostname and binds to different IP address.
- It’s recommended to add your all IP addresses to the
mynetworks
parameter. - If you have added other custom settings (like TLS configurations) in the
/etc/postfix/main.cf
file, you should copy them to the/etc/postfix-smtp1/main.cf
file. - The
/etc/postfix-smtp1/master.cf
contains the stock content provided by Postfix. Again, you can copy the custom settings from the/etc/postfix/master.cf
file.
Next, create an etc
directory under the queue directory.
sudo mkdir -p /var/spool/postfix-smtp1/etc/
Copy the files from the primary instance.
sudo cp -r /var/spool/postfix/etc/* /var/spool/postfix-smtp1/etc/
Then run the following command to enable the postfix-smtp1
instance.
sudo postmulti -i postfix-smtp1 -e enable
Now restart the primary instance.
sudo systemctl restart postfix
Then start the postfix-smtp1
instance.
sudo postmulti -i postfix-smtp1 -p start
If your config file has duplicate parameters, this command will show you, and you need to remove the duplicate ones. Possible duplicate parameters are:
mynetworks = inet_protocols =
If the postfix-smtp1
instance won’t start, check the mail log file (/var/log/mail.log
or /var/log/maillog
) to see what went wrong.
If you want to stop it, run
sudo postmulti -i postfix-smtp1 -p stop
To reload configuration files, run
sudo postmulti -i postfix-smtp1 -p reload
To list mail queue for the postfix-smtp1
instance, run
sudo postqueue -c /etc/postfix-smtp1/ -p
Note that the sudo systemctl restart postfix
command will only restart the primary instance. To list all Postfix instances, run
sudo postmulti -l -a
Run the following command to check if Postfix is listening on the correct IP addresses.
sudo ss -lnpt | grep :25
If everything is configured correctly, the two instances should be listening to its own IP address.
Step 2: Set Up DNS Load Balancing
You can use a separate hostname for your VPS and create two DNS A records for the hostname. This is called DNS load balancing.
smtp.example.com A 11.22.33.44 A 11.22.33.55
Then configure your SMTP clients (such as your self-hosted email marketing application) to use the hostname (smtp.example.com
). It will try the two IP addresses in a round-robin fashion.
Step 3: Set Up Firewall
By default, your server has a default gateway, and it always uses the gateway IP address to connect to other servers. To achieve better email deliverability, we need to make the following happen.
- If an SMTP client connects to the first IP address on your VPS, then the VPS should use the first IP address to send the email.
- If an SMTP client connects to the second IP address on your VPS, then the VPS should use the second IP address to send the email.
To make this happen, we need to configure SNAT (Source NAT) in the server firewall. SNAT changes the source IP address.
There are several firewall software on Linux. The following are the common ones.
iptables
: The most well-known firewall in the Linux world.nftables
: The new kid on the block that’s supposed to replace iptables.UFW:
a wrapper for iptables, commonly seen on Debian/Ubuntu servers.Firewalld
: a wrapper for iptables/nftables, commonly seen on RHEL, CentOS, Rocky Linux, Alma Linux servers.
iptables
If you use iptables
, then you need to run the following two commands to set up SNAT.
sudo iptables -t nat -A POSTROUTING -s 11.22.33.44 -p tcp --dport 25 -j SNAT --to-source 11.22.33.44 sudo iptables -t nat -A POSTROUTING -s 11.22.33.55 -p tcp --dport 25 -j SNAT --to-source 11.22.33.55
This means
- If the connection is originated from the first IP address, then use it as the source IP address. The recipient’s SMTP server will think the email comes from the first IP address.
- If the connection is originated from the second IP address, then use it as the source IP address. The recipient’s SMTP server will think the email comes from the second IP address.
UFW
If you use UFW firewall, edit the /etc/ufw/before.rules
file.
sudo nano /etc/ufw/before.rules
Add the following lines at the bottom of this file. Replace the IP address as necessary.
# NAT table rules *nat :POSTROUTING ACCEPT [0:0] -A POSTROUTING -s 11.22.33.44 -p tcp --dport 25 -j SNAT --to-source 11.22.33.44 -A POSTROUTING -s 11.22.33.55 -p tcp --dport 25 -j SNAT --to-source 11.22.33.55 # End each table with the 'COMMIT' line or these rules won't be processed COMMIT
Save and close the file. Then restart UFW.
sudo systemctl restart ufw
Firewalld
If you use Firewalld, then run the following two commands to set up SNAT. Replace the IP address as necessary.
sudo firewall-cmd --permanent --direct --add-rule ipv4 nat POSTROUTING 0 -s 11.22.33.44 -p tcp --dport 25 -j SNAT --to-source 11.22.33.44 sudo firewall-cmd --permanent --direct --add-rule ipv4 nat POSTROUTING 1 -s 11.22.33.55 -p tcp --dport 25 -j SNAT --to-source 11.22.33.55
Reload Firewalld for the changes to take effect.
sudo systemctl reload firewalld
Step 4: Set Up SMTP Fallback Relay
What if your outgoing email is bounced, causing email delivery failure? You can tell Postfix to fall back to another SMTP instance, and the email will be re-delivered using another IP address on your VPS. Your SMTP server will rotate sending IP addresses to minimize failed email delivery. This technique is also used by Gmail.
For example, you can open the main.cf
file of the primary Postfix instance.
sudo nano /etc/postfix/main.cf
Add the following line at the end of this file.
smtp_fallback_relay = [11.22.33.55]:25
In this way, the primary Postfix instance will try delivering the email by itself, and if the delivery failed, it will be passed to the second Postfix instance for delivery.
smtp_fallback_relay is not perfect, because it only works when the email is soft bounced (code 4xx). If your outgoing email is hard bounced (code 5xx), then Postfix won’t use the fallback relay.
Fortunately, you can change the SMTP reply code from 5xx to 4xx, so Postfix will think all bounced emails are soft bounces and it will use the fallback SMTP relay. To make this work, add the following line at the bottom of the /etc/postfix/main.cf
file.
smtp_reply_filter = pcre:/etc/postfix/smtp_reply_filter
Save and close the file. Then create the /etc/postfix/smtp_reply_filter
file.
sudo nano /etc/postfix/smtp_reply_filter
Add the following line in this file. Please don’t add any whitespace at the beginning of this line.
/^5(.*)$/ 4$1
Save and close the file. Next, build this lookup table.
sudo postmap /etc/postfix/smtp_reply_filter
Install the PCRE map support for Postfix.
- Debian/Ubuntu:
sudo apt install postfix-pcre
- CentOS/RHEL/Rocky Linux:
sudo dnf install postfix-pcre
Make sure you have added all IP addresses to the Postfix mynetworks
parameter in the main.cf
file, or the SMTP relay won’t work. You need to do this for all Postfix instances.
Restart Postfix for the changes to take effect.
sudo systemctl restart postfix
Step 5: Add PTR Record for Each IP Address
Kamatera doesn’t allow you to edit PTR record in the control panel. Instead, you need to open a support ticket and tell them to add PTR record for you. It’s not convenient, you might think, but this is to keep spammers away from the platform, so legitimate email senders like us will have a great IP reputation.
Step 6: Configure SMTP Authentication
Now we need to configure SMTP authentication for the postfix-smtp1
Postfix instances.
sudo nano /etc/postfix-smtp1/master.cf
Add the following lines to this file, so SMTP clients can authentication on TCP port 587 or 465 and submit outgoing emails.
submission inet n - y - - smtpd -o syslog_name=postfix/submission -o smtpd_tls_security_level=encrypt -o smtpd_tls_wrappermode=no -o smtpd_sasl_auth_enable=yes -o smtpd_relay_restrictions=permit_sasl_authenticated,reject -o smtpd_recipient_restrictions=permit_mynetworks,permit_sasl_authenticated,reject -o smtpd_sasl_type=dovecot -o smtpd_sasl_path=private/auth smtps inet n - y - - smtpd -o syslog_name=postfix/smtps -o smtpd_tls_wrappermode=yes -o smtpd_sasl_auth_enable=yes -o smtpd_relay_restrictions=permit_sasl_authenticated,reject -o smtpd_recipient_restrictions=permit_mynetworks,permit_sasl_authenticated,reject -o smtpd_sasl_type=dovecot -o smtpd_sasl_path=private/auth
Save and close the file. Then stop postfix-smtp01
instance.
sudo postmulti -i postfix-smtp1 -p stop
And start it again.
sudo postmulti -i postfix-smtp1 -p start
Then you need to configure a separate Dovecot SMTP auth socket for the postfix-smtp1
instance.
sudo nano /etc/dovecot/conf.d/10-master.conf
Your service auth
section might look like this:
service auth { unix_listener /var/spool/postfix/private/auth { mode = 0660 user = postfix group = postfix } }
You need to add a new unix_listener
for the postfix-smtp1
instance, which uses /var/spool/postfix-smp1/
directory as the spool directory.
service auth {
unix_listener /var/spool/postfix/private/auth {
mode = 0660
user = postfix
group = postfix
}
unix_listener /var/spool/postfix-smtp1/private/auth {
mode = 0660
user = postfix
group = postfix
}
}
Save and close the file. Then restart Dovecot.
sudo systemctl restart dovecot
Step 7: Testing
Now you can send test emails to see if it’s working.
Troubleshooting
If you see the following error in the mail log (/var/log/mail.log
or /var/log/maillog
)
postfix/submission/smtpd[4125]: warning: SASL: Connect to private/auth failed: No such file or directory postfix/submission/smtpd[4125]: fatal: no SASL authentication mechanisms
This means you didn’t add a new unix_listener
for the postfix-smtp1
instance in the Dovecot 10-master.conf file.
No DKIM Signature?
If you use OpenDKIM, but there’s no DKIM signature in your email, then you should use the following settings.
Open the OpenDKIM configuration file.
sudo nano /etc/opendkim.conf
If your file has a line like below, then OpenDKIM is using Unix socket to accept connections from Postfix.
Socket local:/var/spool/postfix/opendkim/opendkim.sock
Comment it out. We need to configure OpenDKIM to use TCP/IP sockets.
Socket inet:8891@localhost
Save and close the file. Next, edit the main.cf
file of each Postfix instance, add the following lines in the file, so Postfix will connect to OpenDKIM via TCP/IP socket.
# Milter configuration milter_default_action = accept milter_protocol = 6 smtpd_milters = inet:127.0.0.1:8891 non_smtpd_milters = $smtpd_milters
Save and close the file. Then restart each Postfix instance.
Enable Autostart
The main Postfix instance can automatically start at boot time.
sudo systemctl enable postfix
But this doesn’t make other Postfix instances autostart. We need to create a systemd service to make it autostart.
sudo nano /etc/systemd/system/postfix-smtp1.service
Add the following lines to this file.
[Unit] Description=Start the postfix-smtp1 instance After=network.target [Service] Type=forking ExecStartPre=/bin/sleep 5 ExecStart=/bin/bash -c '/usr/sbin/postmulti -i postfix-smtp1 -p start' ExecStop=/bin/bash -c '/usr/sbin/postmulti -i postfix-smtp1 -p stop' ExecReload=/bin/bash -c '/usr/sbin/postmulti -i postfix-smtp1 -p reload' Restart=on-failure [Install] WantedBy=multi-user.target
Save and close the file. Then reload systemd.
sudo systemctl daemon-reload
Enable autostart at boot time.
sudo systemctl enable postfix-smtp1
Stop the current postfix-smtp1
instance.
sudo postmulti -i postfix-smtp1 -p stop
Now you can start it with systemd
sudo systemctl start postfix-smtp1
How to Bypass Email Blacklists
Your outgoing emails might be rejected due to IP address blacklisting. Even if you don’t send spam, sometimes your email server IP address can be blacklisted for reasons out of your control. Follow the tutorial below to learn how to get around blacklists.
Wrapping Up
I hope this tutorial helped you set up multiple instances of Postfix SMTP server with IP rotation on a single VPS. As always, if you found this post useful, then subscribe to our free newsletter to get more tips and tricks. Take care 🙂
Hi,
Thanks for your tutorial. I used a multi-domain certificate, following the previous tutorial. Each IP address is bound to a sending domain name. But I have a problem that other than the main domain name cannot send mail with ssl encryption. To be precise, the server verification certificate only has the certificate of the main domain name, and the certificate under the main domain name cannot be verified. So the sending fails.
The issue:
I have detected the server openssl corresponding as follows
How to fix this problem?Thank you.
For email submission, STARTTLS should be used with port 587. Port 465 should be used when you want to use the SMTPS protocol.
Also be sure to copy the SSL/TLS setting from
/etc/postfix/main.cf
file to/etc/postfix-smtp1/main.cf
.Hi mail is only sending primary smtp not postfix-smtp1. Need to change anything or rate limit.
Are you using Debian, Ubuntu or CentOS/Rocky Linux?
It’s CentOS 7.
Thank you. It’s very advance and hard for me. Do you have any package that can be installed and can do all of this without the manual configuration? I already installed iRedMail and I want to make SMTP rotation on the same email server installed, is it possible? Thanks.
hi,
sorry for the silly question and I’m very new to this but can to tell me where change myhostname = smtp.example.com
inet_interfaces = for smtp and smtp1.
thank you.
This is a great article. Thanks for writing it.
If you are like me and not spamming the universe with marketing emails and you just want a way to relay email from a datacenter to the outside world another configuration option is running each instance on a different port by defining a different service in the master.cf – i.e. “smtp” and “2525”)
Configured this way you don’t need unique myhostname and inet_interfaces defined.
I use this to only allow relay locally (from mydomain.com to mydomain.com) anything received on port 2525. On port 25 I relay to any destination but only from a defined network list – “mynetworks=192.168.1.1/24, 10.10.2.5”.
Thank you for this brilliant article, I’ve been using it for a while. Some questions from me:
What’s the best way to set up DNS MX records? Does it matter?
Under Fallback Relay, you write “Your SMTP server will rotate sending IP addresses to minimize failed email delivery”. How does this work? In the example there is one specific fallback IP address.
Is there a risk of an infinite loop when setting up fallback relay on all instances?
Thank you again!
Need a better write-up to include dovecot in this. It’s not working.