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.

Set Up SMTP and IMAP Proxy with HAProxy

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.

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.

postfix haproxy smtp proxy

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 🙂

Rate this tutorial
[Total: 8 Average: 5]

49 Responses to “Set Up SMTP & IMAP Proxy with HAProxy (Debian, Ubuntu, CentOS)

  • Michael
    4 years ago

    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.

    • Xiao Guoan (Admin)
      3 years ago

      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?

    • Xiao Guoan (Admin)
      3 years ago

      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

    • Xiao Guoan (Admin)
      3 years ago

      Check the mydestination variable. It should only contain your own domains.

      postconf mydestination
      • 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.

    • Xiao Guoan (Admin)
      3 years ago

      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!

    • Xiao Guoan (Admin)
      3 years ago

      You can try the following command on your mail server to find out what’s the MX host for gmail.com

      dig MX gmail.com +short

      A correct output should be

      10 alt1.gmail-smtp-in.l.google.com.
      5 gmail-smtp-in.l.google.com.
      30 alt3.gmail-smtp-in.l.google.com.
      40 alt4.gmail-smtp-in.l.google.com.
      20 alt2.gmail-smtp-in.l.google.com.
      

      Then query the A record.

      dig A gmail-smtp-in.l.google.com +short
  • 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.

     telnet localhost 143 

    This return connection refused.

    Any idea what should i be looking for?

    • Xiao Guoan (Admin)
      3 years ago

      Maybe you can check the Dovecot log.

      sudo journalctl -eu dovecot

      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?

    • Xiao Guoan (Admin)
      3 years ago

      Run the following command on your mail server to see if there are any emails held in the queue.

      sudo postqueue -p

      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.

  • Wild Tangent
    2 years ago

    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?

    • Xiao Guoan (Admin)
      2 years ago

      You can do Let’s Encrypt DNS validation on the mail server, not on the VPS.

      • Wild Tangent
        2 years ago

        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?

    • Xiao Guoan (Admin)
      2 years ago

      HAProxy doesn’t perform TLS termination. TLS is passed to the mail server.

      • Wild Tangent
        2 years ago

        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

    • Wild Tangent
      2 years ago

      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.

      • Wild Tangent
        2 years ago

        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.

      • fabriziolinux
        2 years ago

        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

  • Febby Aji Pangestu
    2 years ago

    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:

      Main menu
      
         1) Common Configuration:
         2) zimbra-ldap:                             Enabled
         3) zimbra-logger:                           Enabled
         4) zimbra-mta:                              Enabled
         5) zimbra-snmp:                             Enabled
         6) zimbra-store:                            Enabled
              +Create Admin User:                    yes
              +Admin user to create:                 [email protected]
      ******* +Admin Password                        UNSET
              +Anti-virus quarantine user:           [email protected]
              +Enable automated spam training:       yes
              +Spam training user:                   [email protected]
              +Non-spam(Ham) training user:          [email protected]
              +SMTP host:                            webmail.example.com
              +Web server HTTP port:                 8080
              +Web server HTTPS port:                8443
              +Web server mode:                      https
              +IMAP server port:                     7143
              +IMAP server SSL port:                 7993
              +POP server port:                      7110
              +POP server SSL port:                  7995
              +Use spell check server:               yes
              +Spell server URL:                     http://webmail.example.com:7780/aspell.php
              +Enable version update checks:         TRUE
              +Enable version update notifications:  TRUE
              +Version update notification email:    [email protected]
              +Version update source email:          [email protected]
              +Install mailstore (service webapp):   yes
              +Install UI (zimbra,zimbraAdmin webapps): yes
      

      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! 😉

    • Xiao Guoan (Admin)
      2 years ago

      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.

      
          TCP 25
          TCP 587
          TCP 465
          TCP 143
          TCP 993
          TCP 80
          TCP 443
          TCP 110
          TCP 995
      

      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!

    • Xiao Guoan (Admin)
      2 years ago

      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:

      Cloud VPS:    10.10.10.1
      mail server:  10.10.10.2
      laptop:       10.10.10.3
      

      You can ping from the laptop to the mail server.

      ping 10.10.10.2

      Since the mail server allows access from the 10.10.10.0/24 network (in step 3), you can SSH into it directly

      ssh [email protected]
      • 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!

    • Xiao Guoan (Admin)
      2 years ago

      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! 🙂

  • Jhonatas Garagnani
    2 years ago

    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?

    • Xiao Guoan (Admin)
      2 years ago

      Are you able to send emails to Gmail?

      What’s the error message when sending to outlook or hotmail?

      • Jhonatas Garagnani
        2 years ago

        Yes, can send to Gmail and other senders. I receive this report from Outlook and Hotmail:

        This is the mail system at host xfindzimbra8mail.com.br.
        
        I'm sorry to have to inform you that your message could not
        be delivered to one or more recipients. It's attached below.
        
        For further assistance, please send mail to postmaster.
        
        If you do so, please include this problem report. You can
        delete your own text from the attached returned message.
        
                           The mail system
        
        : host hotmail-com.olc.protection.outlook.com[104.47.18.161] said: 550 5.7.1
            Unfortunately, messages from [51.81.87.165] weren't sent. Please contact
            your Internet service provider since part of their network is on our block
            list (S3140). You can also refer your provider to
            http://mail.live.com/mail/troubleshooting.aspx#errors.
            [AM7EUR06FT010.eop-eur06.prod.protection.outlook.com] (in reply to MAIL
            FROM command)
        • Jhonatas Garagnani
          2 years ago

          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?

    • Xiao Guoan (Admin)
      2 years ago

      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

    • Xiao Guoan (Admin)
      2 years ago

      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.

  • Jhonatas Garagnani
    2 years ago

    Thank’s for solution! You are the best!

  • Jhonatas Garagnani
    2 years ago

    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.

    • Xiao Guoan (Admin)
      2 years ago

      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.

      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.

      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

      List current nftables rules.

      sudo nft list chain inet filter input
  • Swapnil
    1 year ago

    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?

Leave a Comment

  • Comments with links are moderated by admin before published.
  • Your email address will not be published.
  • Use <pre> ... </pre> HTML tag to quote the output from your terminal/console.
  • Please use the community (https://community.linuxbabe.com) for questions unrelated to this article.
  • I don't have time to answer every question. Making a donation would incentivize me to spend more time answering questions.

The maximum upload file size: 2 MB. You can upload: image. Links to YouTube, Facebook, Twitter and other services inserted in the comment text will be automatically embedded. Drop file here