Set Up SMTP & IMAP Proxy with HAProxy (Debian, Ubuntu, CentOS)
In previous tutorials, we discussed how to set up a mail server from scratch on Linux (Ubuntu version, CentOS/Rocky Linux/RHEL version), and how to use iRedMail or Modoboa to quickly set up your own mail server without having to manually configure each component of the mail server stack. This tutorial is going to show you how to set up SMTP and IMAP proxy for your mail server with HAProxy.
Hint: I have written a new tutorial on setting mail proxy server with VPN port forwarding, which is way easier than the method described in this tutorial. I highly recommend using the VPN port forwarding method.
When Do You Need SMTP and IMAP Proxy?
Some folks run email servers at home, but may have the following problems:
- Port 25 is blocked.
- They don’t have a static IP address.
- They can’t create PTR record.
If port 25 is blocked, you can’t send emails directly to recipients. And if you don’t have a static IP address or PTR record, your emails are likely to be rejected or land into the spam folder. If you are in this situation, you can run a VPS (Virtual Private Server) at a data center and use it as a proxy for your mail server. The VPS has a static IP address and you can create PTR record for the IP address. Other email servers would think that the VPS runs your mail service and when you send an email, they would think the email comes from your VPS.
Yes, you can also use SMTP relay services such as Sendinblue to solve these problems, but there’s a limit on how many emails you can send each day and each month. If you upgrade to a paid account with Mailjet, it costs at least $25 each month. The more emails you send, the higher your monthly cost will be. If you run a VPS and set up mail proxy, it costs about $4 per month no matter how many emails you are going to send.
If you run a mail server for lots of people, you might need to set up mail proxy for load balancing and high availability. In this article, I will set up SMTP and IMAP proxy with HAProxy, which is a free, open-source high availability load balancer and proxy server for TCP and HTTP-based applications.
Step 1: Choose the Right VPS for Mail Proxy
You need a VPS that
- allows you to create PTR record
- doesn’t block port 25
- allows you to send unlimited emails without restrictions.
Not all VPS providers meet the above 3 requirements. For example, DigitalOcean blocks port 25 and it would not unblock port 25. Another problem is that big well-known hosting providers like DigitalOcean are abused by spammers. Often the server IP address is on several blacklists.
I run my mail servers on ScalaHosting and Kamatera VPS. I always recommend them when setting up a mail server. For a mail proxy that doesn’t require much CPU and RAM, you can choose Kamatera VPS. The 1 CPU, 1GB RAM plan costs only $4/month, and you will get one month for free. You can follow the tutorial below to create a Kamatera VPS.
You can choose any Linux distro for your VPS, but I recommend you to use Debian, Ubuntu, or CentOS/Rocky Linux.
To log into your server, you use an SSH client. If you are using Linux or macOS on your computer, then simply open up a terminal window and run the following command to log into your server. Replace 12.34.56.78 with the IP address of your VPS.
ssh root@12.34.56.78
You will be asked to enter the password. If you are using Windows, please read the following article on how to use SSH client.
Step 2: Set Up VPN Server on Your VPS
If you have a dynamic IP address at your home, then you need to set up a VPN server on your VPS, so your VPS will be able to communicate with your mail server without being interrupted due to the change of IP address. The VPN server can also help you bypass port 25 blocking.
You can set up WireGuard VPN on your VPS by following one of the tutorials below. Why do I choose WireGuard instead of other VPN protocols like OpenVPN? Because WireGuard allows you to assign static private IP addresses to VPN clients.
- Set Up Your Own WireGuard VPN Server on Ubuntu
- Set Up Your Own WireGuard VPN Server on Debian
- Set Up Your Own WireGuard VPN Server on CentOS/Rocky Linux
When following the instructions in the above articles, your VPS is the VPN server and your mail server is the VPN client. The VPS will become the default gateway for your mail server and all outbound traffic on your mail server will be tunneled through VPN, so receiving SMTP servers (Gmail, Hotmail, Yahoo Mail, etc) will think your emails come from the VPS. If you want to send outgoing emails via the VPS, but make other types of traffic use the original gateway, WireGuard also allows you to do so by enabling policy routing.
You should set a PTR record, aka reverse DNS record, for your VPS. 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. Tell the support team to update the PTR record of your server IP address to mail.your-domain.com
.
Step 3: Open Ports in Firewall and Set Up Permissions
VPS
The VPS needs to open port 25, 587, 465, 143 and 993 in the firewall. Run the following commands to open these ports.
Debian/Ubuntu:
sudo ufw allow 25,587,465,143,993/tcp
CentOS/Rocky Linux:
sudo firewall-cmd --permanent --add-service={smtp,smtp-submission,smtps,imap,imaps} sudo systemctl reload firewalld
Later in this tutorial, HAProxy on the VPS needs to bind to various email ports like 25, 587, 465, 143, and 993, but is prevented from doing so by SELinux. If you use CentOS/Rocky Linux on the VPS, you need to run the following command to allow HAProxy to bind to these ports.
sudo setsebool -P haproxy_connect_any 1
Mail Server
The mail server needs to open various ports to the VPS. Run the following command.
Debian/Ubuntu:
sudo ufw insert 1 allow in from 10.10.10.0/24
CentOS/Rocky Linux:
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="10.10.10.0/24" accept'
sudo systemctl reload firewalld
10.10.10.0/24
is the private IP range created by the VPN server, so the VPS can access all ports on the mail server.
Hint: The latest version of iRedMail starts using the nftable
firewall. Check if your mail server has the /etc/nftables.conf
file. If you can find this file, then open it and locate the following lines.
# smtp, submission, smtps tcp dport 25 accept tcp dport 587 accept tcp dport 465 accept # pop3, pop3s tcp dport 110 accept tcp dport 995 accept # imap, imaps tcp dport 143 accept tcp dport 993 accept
Add TCP ports 2525, 1043, 10465, 10587, and 10993.
# smtp, submission, smtps tcp dport 25 accept tcp dport 587 accept tcp dport 465 accept tcp dport 2525 accept tcp dport 10587 accept tcp dport 10465 accept # pop3, pop3s tcp dport 110 accept tcp dport 995 accept # imap, imaps tcp dport 143 accept tcp dport 993 accept tcp dport 10143 accept tcp dport 10993 accept
Save and close the file. Then reload the firewall rules.
sudo nft -f /etc/nftables.conf
Step 4: Set Up SMTP Proxy to Receive Email
Now you need to set up SMTP proxy so that other mail servers can send emails to your own mail server via the VPS.
VPS
SSH into your VPS and install HAProxy.
Debian/Ubuntu
sudo apt install haproxy
CentOS/Rocky Linux
sudo dnf install haproxy
Then edit the HAProxy main configuration file.
sudo nano /etc/haproxy/haproxy.cfg
Add the following lines at the end of the file. Replace 12.34.56.78
with the public IP address of your VPS. Replace 10.10.10.101
with the private IP address of your mail server, which is assigned by your VPN server.
frontend ft_smtp bind 12.34.56.78:25 mode tcp timeout client 1m log global option tcplog default_backend bk_smtp backend bk_smtp mode tcp log global option tcplog timeout server 1m timeout connect 7s server postfix 10.10.10.101:2525 send-proxy
The above configuration will make HAProxy listen on port 25 and pass SMTP connections to port 2525 of your mail server. Save and close the file. Restart HAProxy.
sudo systemctl restart haproxy
And enable auto-start at boot time.
sudo systemctl enable haproxy
Mail Server
To use HAProxy as a reverse proxy for the Postfix SMTP server, you need to enable Postscreen in Postfix. SSH into your mail server and edit the Postfix master configuration file.
sudo nano /etc/postfix/master.cf
Add the following lines at the beginning of this file. Replace 10.10.10.101
with the private IP address of your mail server assigned by VPN server. This will enable Postscreen on port 2525 and it can accept HAProxy connections from your VPS. Postfix is able to obtain the original IP address of SMTP client from HAProxy.
10.10.10.101:2525 inet n - - - 1 postscreen
-o postscreen_upstream_proxy_protocol=haproxy
-o postscreen_cache_map=btree:$data_directory/postscreen_2525_cache
-o syslog_name=postfix/2525
Then uncomment the following 3 lines. (Note: If you use iRedMail or Moboboa to run your mail server, then the following 3 lines are uncommented by default.)
smtpd pass - - y - - smtpd dnsblog unix - - y - 0 dnsblog tlsproxy unix - - y - 0 tlsproxy
Where:
- The first line will make Postscreen pass SMTP connection to
smtpd
daemon. - The dnsblog (DNS Blacklist Logger) service enables logging of DNS blacklist checks.
- The tlsproxy service enables STARTTLS support for postscreen, so remote SMTP clients can establish encrypted connection when Postscreen is enabled.
Save and close the file. Restart Postfix for the change to take effect.
sudo systemctl restart postfix
Run the following command:
sudo ss -lnpt | grep master
Make sure the Postfix master process is listening on TCP ports 25, 587, 465, 2525, 10587 and 10465.
LISTEN 0 100 10.10.10.101:10465 0.0.0.0:* users:(("master",pid=13035,fd=148)) LISTEN 0 100 127.0.0.1:10025 0.0.0.0:* users:(("master",pid=13035,fd=139)) LISTEN 0 100 0.0.0.0:587 0.0.0.0:* users:(("master",pid=13035,fd=122)) LISTEN 0 100 127.0.0.1:10028 0.0.0.0:* users:(("master",pid=13035,fd=142)) LISTEN 0 100 0.0.0.0:465 0.0.0.0:* users:(("master",pid=13035,fd=126)) LISTEN 0 100 0.0.0.0:25 0.0.0.0:* users:(("master",pid=13035,fd=17)) LISTEN 0 100 10.10.10.101:10587 0.0.0.0:* users:(("master",pid=13035,fd=145)) LISTEN 0 100 10.10.10.101:2525 0.0.0.0:* users:(("master",pid=13035,fd=13))
Now add a new MX record for your domain name like below, and your mail server is able to receive emails via the VPS.
Record Type Name Mail Server Priority
MX @ hostname-of-your-VPS 0
You can use any hostname for your VPS, as long as it can be resolved to the IP address of your VPS. For simplicity, you can use the hostname of the mail server (mail.yourdomain.com
). Don’t forget to add DNS A record for the hostname of your VPS.
Step 5: Set Up Submission Proxy
Your users can submit outgoing emails to your mail server without proxy, but what if you want your users to be able to submit outgoing emails through the VPS? You need to set up proxy for the Postfix submission service.
VPS
Edit the HAProxy main configuration file on your VPS.
sudo nano /etc/haproxy/haproxy.cfg
Add the following lines at the end of the file. Replace 12.34.56.78
with the public IP address of your VPS. Replace 10.10.10.101
with the private IP address of your mail server, which is assigned by your VPN server.
frontend ft_submission bind 12.34.56.78:587 mode tcp timeout client 1m log global option tcplog default_backend bk_submission backend bk_submission mode tcp log global option tcplog timeout server 1m timeout connect 7s server postfix 10.10.10.101:10587 send-proxy frontend ft_smtps bind 12.34.56.78:465 mode tcp timeout client 1m log global option tcplog default_backend bk_smtps backend bk_smtps mode tcp log global option tcplog timeout server 1m timeout connect 7s server postfix 10.10.10.101:10465 send-proxy
There are commonly two ports that can accept email submissions from authenticated users:
- TCP port 587 (STARTTLS)
- TCP port 465 (SMTPS)
So in the above configuration, we defined two front ends in HAProxy listening on port 587 and 465. They will pass connections to port 10587 and 10465 of your mail server, respectively.
Save and close the file. Restart HAProxy.
sudo systemctl restart haproxy
Mail Server
Then edit Postfix master configuration file on your mail server.
sudo nano /etc/postfix/master.cf
Add the following lines at the end of this file. Replace 10.10.10.101
with the private IP address of your mail server, which is assigned by your VPN server. Please allow at least one whitespace (tab or spacebar) before -o
. In postfix configurations, a preceding whitespace character means that this line is continuation of the previous line. However, you should not add space before or after the equal sign (=
).
10.10.10.101:10587 inet n - y - - smtpd -o syslog_name=postfix/10587 -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 -o smtpd_upstream_proxy_protocol=haproxy 10.10.10.101:10465 inet n - y - - smtpd -o syslog_name=postfix/10465 -o smtpd_tls_wrappermode=yes -o smtpd_sasl_auth_enable=yes -o smtpd_recipient_restrictions=permit_mynetworks,permit_sasl_authenticated,reject -o smtpd_sasl_type=dovecot -o smtpd_sasl_path=private/auth -o smtpd_upstream_proxy_protocol=haproxy
In the above configuration, we enabled two submission services listening on port 10587 and 10465, and they support the haproxy
protocol, so they will be able to accept connections from HAProxy. Save and close the file. Restart Postfix for the change to take effect.
sudo systemctl restart postfix
Step 6: Set Up IMAP Proxy
We also want users to be able to log into the IMAP server via the VPS, so we need to set up IMAP proxy.
VPS
Edit the HAProxy main configuration file on your VPS.
sudo nano /etc/haproxy/haproxy.cfg
Add the following lines at the end of the file. Replace 12.34.56.78
with the public IP address of your VPS. Replace 10.10.10.101
with the private IP address of your mail server, which is assigned by your VPN server.
frontend ft_imap bind 12.34.56.78:143 mode tcp default_backend bk_imap backend bk_imap mode tcp balance leastconn stick store-request src stick-table type ip size 200k expire 30m server imap1 10.10.10.101:10143 send-proxy-v2 frontend ft_imaps bind 12.34.56.78:993 mode tcp default_backend bk_imaps backend bk_imaps mode tcp balance leastconn stick store-request src stick-table type ip size 200k expire 30m server imaps1 10.10.10.101:10993 send-proxy-v2
There are two ports for the IMAP service:
- TCP port 143: STARTTLS
- TCP port 993: implicit TLS
So in the above configuration, we added two front ends in HAproxy listening on ports 143 and 993. They will pass connections to port 10143 and 10993 of your mail server, respectively. Save and close the file. Restart HAProxy.
sudo systemctl restart haproxy
Run the following command to check listening ports.
sudo ss -lnpt | grep haproxy
Make sure HAProxy is listening on TCP ports 25, 143, 993, 587 and 465.
LISTEN 0 4096 139.177.197.90:993 0.0.0.0:* users:(("haproxy",pid=3987970,fd=12)) LISTEN 0 4096 139.177.197.90:587 0.0.0.0:* users:(("haproxy",pid=3987970,fd=9)) LISTEN 0 4096 139.177.197.90:143 0.0.0.0:* users:(("haproxy",pid=3987970,fd=11)) LISTEN 0 4096 139.177.197.90:465 0.0.0.0:* users:(("haproxy",pid=3987970,fd=10)) LISTEN 0 4096 139.177.197.90:25 0.0.0.0:* users:(("haproxy",pid=3987970,fd=8))
Mail Server
Edit Dovecot configuration file on your mail server.
sudo nano /etc/dovecot/conf.d/10-master.conf
Hint: If you use iRedMail, then you should edit the Dovecot main configruation (/etc/dovecot/dovecot.conf
).
Find the following lines:
service imap-login { inet_listener imap { #port = 143 } inet_listener imaps { #port = 993 #ssl = yes } }
Add HAProxy support for IMAP and IMAPS like below.
service imap-login { inet_listener imap { port = 143 } inet_listener imaps { port = 993 ssl = yes } inet_listener imap_haproxy { port = 10143 haproxy = yes } inet_listener imaps_haproxy { port = 10993 ssl = yes haproxy = yes } }
In the above configuration, we enabled two additional IMAP services: imap_haproxy
and imaps_haproxy
, listening on port 10143 and 10993, respectively. They support the haproxy
protocol, so they will be able to accept connections from HAProxy. Save and close the file.
Then we need to add trusted proxy hosts in Dovecot. Edit the Dovecot main configuration file.
sudo nano /etc/dovecot/dovecot.conf
Add the following two lines at the end of this file. Replace 10.10.10.1
with the private IP address of your VPN server.
haproxy_trusted_networks = 10.10.10.1
haproxy_timeout = 3s
Save and close the file. Restart Dovecot for the change to take effect.
sudo systemctl restart dovecot
Run the following command:
sudo ss -lnpt | grep dovecot
Make sure Dovecot is listening on TCP ports 10143 and 10993.
LISTEN 0 100 127.0.0.1:4190 0.0.0.0:* users:(("dovecot",pid=14338,fd=15)) LISTEN 0 500 0.0.0.0:10143 0.0.0.0:* users:(("dovecot",pid=14338,fd=49)) LISTEN 0 500 0.0.0.0:993 0.0.0.0:* users:(("dovecot",pid=14338,fd=47)) LISTEN 0 100 0.0.0.0:995 0.0.0.0:* users:(("dovecot",pid=14338,fd=27)) LISTEN 0 100 0.0.0.0:110 0.0.0.0:* users:(("dovecot",pid=14338,fd=25)) LISTEN 0 500 0.0.0.0:143 0.0.0.0:* users:(("dovecot",pid=14338,fd=45)) LISTEN 0 500 0.0.0.0:10993 0.0.0.0:* users:(("dovecot",pid=14338,fd=51))
Now you should be able to log into the IMAP server and submit outgoing emails via the VPS.
Step 7: Set Up HTTPS Proxy on the VPS
If you would like to access webmail such as Roundcube via the VPS, then edit the HAProxy main configuration file on your VPS.
sudo nano /etc/haproxy/haproxy.cfg
Add the following lines at the end of the file. Replace 12.34.56.78
with the public IP address of your VPS. Replace 10.10.10.101
with the private IP address of your mail server, which is assigned by your VPN server. Replace mail.yourdomain.com
with the domain name used by your webmail.
frontend https bind 12.34.56.78:443 mode tcp tcp-request inspect-delay 5s tcp-request content accept if { req_ssl_hello_type 1 } use_backend webmail if { req_ssl_sni -i mail.yourdomain.com } default_backend webmail backend webmail mode tcp option ssl-hello-chk server webmail 10.10.10.101:443 check
Save and close the file. Then restart HAProxy.
sudo systemctl restart haproxy
Note that the HTTPS proxy can interfere with Let’s Encrypt TLS certificate renewal if you use the default http-01
challenge in certbot. It’s recommended to use dns-01
challenge when you renew your Let’s Encrypt TLS certificate with certbot.
Now you can test sending and receiving emails.
Troubleshooting Tips
1. If you send an email to your mail server, but received the following error,
lost connection with mail.yourdomain.com[xx.xx.xx.xx] while receiving the initial server greeting
it’s probably because your VPN connection is broken, verify if you can ping from the VPN server to the VPN client (mail server).
ping 10.10.10.101
2. Check if the VPS can access all available ports of the mail server.
It could also be that you didn’t configure the mail server firewall to allow connection from the VPN (10.10.10.0/24). Run the following command on the VPN server to see if the ports are open. Nmap can be installed on the VPN server with sudo apt install nmap
.
sudo nmap 10.10.10.101 -p 1-20000
Sample output:
Host is up (0.000021s latency). Not shown: 19985 closed ports PORT STATE SERVICE 22/tcp open ssh 25/tcp open smtp 80/tcp open http 110/tcp open pop3 143/tcp open imap 443/tcp open https 465/tcp open smtps 587/tcp open submission 993/tcp open imaps 995/tcp open pop3s 2525/tcp open ms-v-worlds 10143/tcp open unknown 10465/tcp open unknown 10587/tcp open unknown 10993/tcp open unknown
If TCP ports 2525, 1043, 10465, 10587, and 10993 aren’t on the list, then you have a problem. The VPS can’t access these ports.
Verify if you can telnet to the mail server on port 2525.
telnet 10.10.10.101 2525
3. HAProxy Error
Sometimes, you may have an error in your HAProxy configurations. For example, I once had two default_backend
directives in HAProxy as follows.
frontend ft_smtp bind 12.34.56.78:25 mode tcp timeout client 1m log global option tcplog default_backend bk_smtp default_backend ocserv
This is wrong. If you define a default_backend
in a frontend
section, then you can’t define another default_backend
in the global section. Instead, you should place each default_backend
directive in the appropriate frontend
section like we did in this article.
Another config error is that you might accidentally insert other directives in the https
frontend.
frontend https bind 12.34.56.78:443 mode tcp tcp-request inspect-delay 5s tcp-request content accept if { req_ssl_hello_type 1 } some_other_directives use_backend webmail if { req_ssl_sni -i mail.yourdomain.com } default_backend webmail
Final Thoughts
Notice that we enabled proxy support for Postfix and Dovecot by adding more listening ports (2525, 10587, 10465, 10143, 10993). We didn’t enable proxy support for existing ports (25, 587, 465, 143 and 993), because if we do, then Postfix and Dovecot will accept connections from HAProxy only and deny connection from other IP addresses, including localhost. This can prevent your webmail or web application running on the mail server to use 127.0.0.1:25
to send emails, and prevent the webmail client from fetching emails from Dovecot. You will probably see the following error when this happens.
host mail.example.com refused to talk to me: 421 4.3.2 No system resources
And your Postfix SMTP server would log the following message in the mail log.
postfix/postscreen[1479]: warning: haproxy read: time limit exceeded
Configure HAProxy Automatic Restart
I found the haproxy.service
on CentOS/Rocky Linux/RHEL can fail to start at boot time. The error is as follows.
Starting frontend ft_smtp: cannot bind socket [23.254.225.226:25]
If I manually start the service, it works, which is confusing to me. To solve this issue, we can edit the haproxy.service
to make it automatically restart on failure. To override the default systemd service configuration, we create a separate directory.
sudo mkdir -p /etc/systemd/system/haproxy.service.d/
Then create a file.
sudo nano /etc/systemd/system/haproxy.service.d/restart.conf
Add the following lines in the file.
[Service] Restart=always RestartSec=5s
Save and close the file. Then reload systemd.
sudo systemctl daemon-reload
Postfix/Dovecot Automatic Restart
It’s also recommended to configure Postfix and Dovecot on the mail server to automatically restart on failure.
Postfix
Create a separate directory.
sudo mkdir -p /etc/systemd/system/postfix.service.d/
Then create a file.
sudo nano /etc/systemd/system/postfix.service.d/restart.conf
Add the following lines in the file. Note that on Debian/Ubuntu, the postfix.service
is an oneshot
service, which doesn’t allow Restart=always
.
[Service] Restart=on-failure RestartSec=5s
Save and close the file. Then reload systemd.
sudo systemctl daemon-reload
Dovecot
Create a separate directory.
sudo mkdir -p /etc/systemd/system/dovecot.service.d/
Then create a file.
sudo nano /etc/systemd/system/dovecot.service.d/restart.conf
Add the following lines in the file.
[Service] Restart=always RestartSec=5s
Save and close the file. Then reload systemd.
sudo systemctl daemon-reload
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.
Alternative Method
If you can’t figure out what’s wrong in your server environment, you can also set up port forwarding with UFW firewall on the VPN server. Traffic will be forwarded by UFW, So HAProxy won’t be used at all. (You don’t need to remove HAProxy.)
The following ports should be forwarded from the VPN server to the mail server.
- TCP 25
- TCP 587
- TCP 465
- TCP 143
- TCP 993
- TCP 80
- TCP 443
- TCP 110
- TCP 995
Conclusion
I hope this tutorial helped you set up SMTP and IMAP proxy. As always, if you found this post useful, then subscribe to our free newsletter to get more tips and tricks. Take care 🙂
Nice tutorial.
Great content and Very nice write-up for beginners. 赞
Very helpful tutorial. This is what I have been looking to configure for a long time.
One question, I did not see any passing of port 80 / 443 through the VPS to the server so that web interface could be accessed through the VPS without opening my home firewall. Would you pass those items through HAProxy to your home server so that you can have LetsEncrypt issue certificates to use with the mail server? Based on my reading we would allow the home server to handle the SSL.
Just trying to avoid opening those ports up to my home network.
Thank you.
Hi Matt,
I added the instructions for setting up HTTPS Proxy in step 7.
A very good job
Thanks, Xiao. Very nice tutorial, as always.
I was looking for a solution to bring a currently VPS-based postfix server to my private LAN, and this article gave me an idea.
Just wonder how do you configure the private mail server to send outgoing emails to public mail servers via the HAProxy, as shown by the red path in the top image?
Hi, so I did a little research and found 2 possible solutions:
(1) I can install postfix on my public VPS, where I’ve installed HAProxy, and configure it as a relay server. Then on the private mail server, I would configure postfix “relayhost” accordingly.
(2) I can configure the private mail server to route outgoing traffic with destination port 25 to my public VPS after enabling IP forwarding there to have it act as a NAT gateway.
Solution 2 is preferred as it won’t expose email content to the VPS server along the path.
How do you think? Any other solution?
Hello Tho,
In this tutorial, the mail server establishes a VPN connection to the VPS, so all traffic (including outgoing emails) will be routed through the VPS.
Great tutorial! However I have an issue where when I send an email to an external source, such as gmail.com, outlook, etc. I get an error – “mail for [recipient domain] loops back to myself
Check the
mydestination
variable. It should only contain your own domains.I have confirmed that but I am still having issues.. I think I might restart everything, mail server, wireguard setup, etc.
If I followed all three of your guides word for word on how to create a mail server, wireguard server and of course the haproxy setup, will I have any luck? Is this how you went about it?
I really appreciate this guide and doing this has already taught me a lot about networking so I am happy even with my current failure. I just really want to make this a success.
I think you don’t need to restart everything. The problem is either in Postfix, your DNS records, or a DNS resolver issue.
I have seen this error on my own server in the past. It’s a simple fix, but I don’t remember exactly what I did.
Thank you so much!
It turns out I either had a misconfiguration in postfix, dovecot or wireguard.
I am pleased to say that everything works just perfectly by following your three guides on:
Creating an email server.
Creating a wireguard server (and client)
And of course, this guide.
Thank you for the information, you’re a great writer. Best of luck to you Xiao!
You can try the following command on your mail server to find out what’s the MX host for gmail.com
A correct output should be
Then query the A record.
Hi,
Great writeup,
I’m having a bit of trouble with roundcube not working.
After going through the logs I was able to determine that port 143 on localhost was not responding.
This return connection refused.
Any idea what should i be looking for?
Maybe you can check the Dovecot log.
And also the main mail log file. (/var/log/mail.log)
Hi,
I did everything again from scratch and now roundcube is working.
Guess I made a mistake in some file.
I have another issue now.
I can send email just fine from RoundCube but cannot receive.
I can see in iRedadmin page that email are arriving (check screenshot) but are not reaching roundcube for some reason..
Any idea?
Run the following command on your mail server to see if there are any emails held in the queue.
And check your mail log (/var/log/mail.log or /var/log/maillog) to see if there are any errors in Postfix/Dovecot.
Emails could be held in the queue if there’s not enough memory on the server.
Well hot skippy if this is not exactly what I need. I have been port-forwarding from my VPS to my home mail server for 2 years now, knowing there had to be a proper way to do this so I would see the actual outside IP of the connections from postfix’s perspective. Think I even determined HAProxy was my likely solution but never went further into figuring out how to set it up.
Question, does this cause any issues with certificates? Do I need to figure out some what to get my LetsEncrypt cert copied to the VPS every renewal?
You can do Let’s Encrypt DNS validation on the mail server, not on the VPS.
I may have badly formatted my question. Does HAProxy require any cert configuration or does it pass TLS connections through to Postfix and Dovecot transparently?
HAProxy doesn’t perform TLS termination. TLS is passed to the mail server.
Thank you for your patient answers. This sounds like it’ll be fairly painless then. I look forward to having useful logging of IPs and full DNSBL/reputation filtering functionality haha
Last question I hope:
I’ve followed your guide to the letter and the HAProxy and Postfix configs seem to be working properly, but Dovecot just refuses to listen on ports 10143 and 10993. I’ve checked my listening ports and they’re just not there, no IMAP traffic is reaching my server at all through HAProxy. I don’t really know what I did wrong, and you lifted your config straight from their own docs so I doubt you are wrong. Any idea what may be amiss? I can probably live with not having IPs for IMAP clients, I have SMTP working properly now which makes me very pleased.
Nevermind, got it going. For some reason Dovecot was not respecting my changes to 10-master.conf and I had to put those new sections into dovecot.conf instead… I’m not arguing if it works.
ho lo stesso problema ma non capisco errore di dovecot sulle porte 10143 10993
Anyway to view incoming mail to HAProxy? I am sending a email from a gmail/yahoo/outlook account and not receiving it on my mail server.
hi
this log reapeat in log file . could you help me
Feb 20 13:58:14 postfix30 postfix/2525/postscreen[40887]: CONNECT from [192.168.*.*]:34944 to [192.168.43.201]:2525
Feb 20 13:58:14 postfix30 postfix/2525/postscreen[40887]: WHITELISTED [192.168.*.*]:34944
Feb 20 13:58:14 postfix30 postfix/smtpd[41728]: connect from unknown[192.168.*.*]
Feb 20 13:58:14 postfix30 postfix/smtpd[41728]: lost connection after HELO from unknown[192.168.*.*]
Feb 20 13:58:14 postfix30 postfix/smtpd[41728]: disconnect from unknown[192.168.*.*] helo=1 commands=1
and actualy my client can connect to haproxy via outlook and test pass but i can not send or recieve any email
Hi,
how to configure HAProxy support for IMAP and IMAPS in Zimbra Mail Server?
regards,
I could be wrong because I haven’t tried and I don’t know your exact setup, but as per Zimbra’s install directions it says:
I would think if you were to change the backend ports in HAProxy in steps 4, 5, 6, and 7 to match the ones Zimbra gives, or change them in Zimbra to match the backend ports defined in HAProxy (10143, 10465, 10587, 2525, 10993, etc) it should work! 😉
Zimbra deliberately obfuscate Postfix and Dovecot configuration files to make it harder to customize.
So I don’t recommend using the HAProxy method if you use Zimbra. Instead, you can set up port forwarding with UFW firewall on the VPN server. Traffic will be forwarded by UFW, So HAProxy won’t be used at all.
How to Set Up Port Forwarding in UFW
The following ports should be forwarded from the VPN server to the mail server.
You still need to set up the WireGuard VPN.
Hey Xiao,
Thanks for the fantastic guides! Everything is working perfectly! Perhaps even too good!
I have a bit of an advanced use case that I’m hoping you can offer some advice.
ESXi host behind a pfSense firewall in a SOHO. Dynamic IP from ISP. All except the mail server I set up using this guide are behind HAProxy in pfSense. SSH access is blocked to the public on all servers. While away, I use OpenVPN in pfSense to access the servers.
Now, the mail server is on the same VLAN as the rest of the web/cloud servers, linked to a public VPS via WG, and I cannot access it via its local IP assigned by pfSense. To SSH into the mail server, I have to SSH into the public VPS, then SSH into the mail server (or any other client connected via WG).
My question to you is now, how can I add a rule that will allow me to access each client by their local IP address when on the “Road Warrior” VPN?
Many thanks for considering my request. Please keep up the great work!
Since your mail server is connected to the cloud VPS via WireGuard VPN, if your laptop or mobile phone is also connected to the VPS via WireGuard, then you can SSH into the mail server directly.
For example:
You can ping from the laptop to the mail server.
Since the mail server allows access from the 10.10.10.0/24 network (in step 3), you can SSH into it directly
Thanks for the quick reply. The VPS has SSH access open to the public, so I can SSH in now without the need for WG on a laptop. From there I can SSH into any machine behind it. What you’re suggesting is basically the same thing, just a slightly different entrance method.
My problem is that when the devices on my local 192.168.70.0/24 connect to the VPS WG server on the 10.105.150.0/24 network, I can not access the machines locally anymore. As long as WG is running, I can only access the backend machines through the VPS.
Eventually, I plan to route all backend services through the VPS and WG tunnels, but for now, several other services and websites are served via my home (dynamic) IP. When doing maintenance, it would be much easier to access all machines from one place, rather than having to switch VPNs or route through the public IP. Also, a WG client running on the laptop might assist with access to the mail and other servers while out, but machines on the local networks still lose connectivity to the machines connected to the VPS through WG. It’s not very practical to configure each local machine as another WG client, just as it’s not practical to SSH into the VPS to then SSH into machines behind it.
Sorry for the long reply, just trying to explain it better, I guess!
By default, all traffic on the VPN client will be routed through the VPN server, so you can’t use the local IP address to access the mail server.
What you need to do is enable policy routing on the mail server. Traffic on the mail server will be routed through VPN server only when TCP is used as the transport layer protocol and the destination port is 25.
How to Enable Policy Routing in WireGuard VPN
You are AMAZING! I now have an email server, a Proxmox Mail Gateway, two web servers, a Nextcloud server, a Jitsi server, and a Matrix server, all running locally, tunneled through the VPS on the dedicated IP, functioning perfectly! I can access all machines either through the VPS public IP, then SSH back using the WG IPs; I can use my “Road Warrior” OpenVPN into my LAN, then use local IPs, or I can start the WG client on my mobile device(s), go right into the WG network, and directly access any machine by its WG IP! This is AWESOME! 🙂
I need help, I installed zimbra mail and made a vps with wireguard and I can’t send a message to outlook or hotmail. Any suggestion?
Are you able to send emails to Gmail?
What’s the error message when sending to outlook or hotmail?
Yes, can send to Gmail and other senders. I receive this report from Outlook and Hotmail:
The only thing I didn’t do was configure my Zimbra’s postfix like the steps in the tutorial, when I configure it to stop sending and receiving messages, I installed Wireguard on an Ubuntu 18.04 from OVH and zimbra on a Centos 7 locally, also with Wireguard, I receive and send emails to gmail and to other servers I already have, but when I send to outlook and hotmail it automatically responds with the message I already sent. Any suggestion?
This means your IP address is blacklisted by Outlook. Follow the tutorial linked below to learn how to bypass email blacklists.
How to Bypass Email Blacklists
Personally, I don’t like Zimbra, because it obfuscates Postfix and Dovecot configurations to make it harder for admins to make custom configs. That’s why you had problems following the bypass email blacklists tutorial. I would recommend using an alternative email hosting solution like iRedMail or Modoboa, which allows admins to easily change Postfix and Dovecot configurations.
Thank’s for solution! You are the best!
Hello Xiao Guoan, I need help, follow the complete tutorial to install haproxy and ireadmail, the email is working normally on the VPN, but it cannot connect to thunderbird or outlook.
Run the following command on the VPS to see if it can access all available ports of the mail server. Nmap can be installed on the VPS with
sudo apt install nmap
.Sample output:
If TCP ports 2525, 1043, 10465, 10587, and 10993 aren’t on the list, then you have a problem. The VPS can’t access these ports.
Hint: The latest version of iRedMail starts using the
nftable
firewall. Check if your mail server has the/etc/nftables.conf
file. If you can find this file, then open it and locate the following lines.Add TCP ports 2525, 1043, 10465, 10587, and 10993.
Save and close the file. Then reload the firewall rules.
List current nftables rules.
Hello Xiao,
A nice tutorial you have shared on SMTP & IMAP Proxy
I need help with the below.
I want to check email address has been existing or not by firing RCPT TO:, however, if I fire the same command multiple times for the same domain my IP gets blocked by the recipient domain, so is there any solution for same to avoid blocking like a proxy server, or other solution
Hello Xiao,
thanks for your great tutorial.
I’m trying to implement your steps in my setup:
Internet VPS (fixed IP: pfsense + haproxy) wireguard tunnel pfsense (dynamic IP) iRedMail (private IP)
But don’t have success so fare.
One issue due to imap on 143 iRedMail log:
[code]
Dec 3 23:53:25 mx dovecot: imap-login: Error: haproxy: Client disconnected: Failed to read valid HAproxy data (rip=vps_wg_IP)
Dec 3 23:53:28 mx dovecot: message repeated 3 times: [ imap-login: Error: haproxy: Client disconnected: Failed to read valid HAproxy data (rip=vps_wg_IP)]
[/code]
That means session established (wireshark proofed) but timed out.
Doesn’t find any hints about: “valid HAproxy data”
Do you have any ideas here?
same problem here.
dovecot: imap-login: Error: haproxy: Client disconnected: Failed to read valid HAproxy data (rip=192.168.200.99)
did you find the solution?