In order to make your architecture scalable, you may often need to use a load balancer, reverse proxy, or an application delivery controller. When using one of them, the client information is almost always hidden. Or, if you want to get the information, it requires huge modifications in the architecture.

Unfortunately, for troubleshooting and security purposes, it's often useful to know the client information (mainly the source IP address). That’s where the proxy protocol comes in.

What is the Proxy Protocol?

The proxy protocol was developed to maintain client information when chaining proxies and reverse proxies.

There are two main advantages to using it:

  1. you can provide a downstream proxy or server (aka next hop) with the client information (mainly the IP address and port source)

  2. you can use servers in multiple data centers without a complex network architecture (you just need to provide routing for a TCP connection)

Why Simply Not Use TPROXY (Transparent Proxy) Mode?

Transparent proxy mode allows a load balancer or a reverse proxy to open the TCP connection to the server using the client's IP address. One of the drawbacks of TPROXY is that the default gateway for the application servers must be the load balancer. Or you must do policy-based routing on your network, which could be painful.

Why Postfix & HAProxy?

HAProxy was the first software to implement the proxy protocol. Note that you’ll have to use HAProxy 1.5 branch or patched HAProxy 1.4.

Another solution is to use the Aloha load balancer, which does everything for you in a box (from the OS to HAProxy) with all the nice features you could expect.

Lately, Postfix has implemented it. It is available in Postfix 2.10. It is the first application server to ship with it.
Hopefully, other MTAs will implement it soon. It is simple and brings so many improvements to the architecture.

SMTP, Spam & Security

In SMTP, it is really important to know the client's IP since we use it most of the time through RBL to fight spam. For security purposes as well: we may want to allow only some hosts to use our SMTP relays and block any other clients. Without the proxy protocol, the load balancer will hide the client's IP with its own IP. You would have to maintain whitelists in the load balancer (which is doable). Thanks to proxy protocol, Postscreen is aware of the client IP, which means you could maintain lists directly into the MTA.

HAProxy & Postfix Connection Flow

The diagram below shows the protocols and the process in place in this kind of architecture:

      smtp              proxy-protocol
                             + smtp
(INTERNET) ---> 25 (HAPROXY)      --->      srv1:10024 (Postscreen
                                                       / smtpd)
                                  --->      srv2:10024 (Postscreen
                                                       / smtpd)

Note that the default gateway of the MTA servers is not the load balancer anymore. Both servers might be in the same LAN or data center. Any type of architecture is now doable.

Configuration

#1 HAProxy

frontend ft_smtp
  bind 0.0.0.0:25
  mode tcp
  timeout client 1m
  log global
  option tcplog
  default_backend bk_postfix
backend bk_postfix
  mode tcp
  log global
  option tcplog
  timeout server 1m
  timeout connect 5s
  server postfix 127.0.0.1:10024 send-proxy

#2 Postfix

Note: I installed postfix in /opt/postfix directory.

main.cf

queue_directory = /opt/postfix/var/spool/postfix
command_directory = /opt/postfix/usr/sbin
daemon_directory = /opt/postfix/usr/libexec/postfix
data_directory = /opt/postfix/var/lib/postfix
mail_owner = postfix
unknown_local_recipient_reject_code = 550
inet_interfaces = localhost
sendmail_path = /opt/postfix/usr/sbin/sendmail
newaliases_path = /opt/postfix/usr/bin/newaliases
mailq_path = /opt/postfix/usr/bin/mailq
setgid_group = postdrop
html_directory = no
manpage_directory = /opt/postfix/usr/local/man
sample_directory = /opt/postfix/etc/postfix
readme_directory = no
inet_protocols = ipv4
postscreen_upstream_proxy_protocol = haproxy

master.cf

10024     inet  n       -       n       -       1       postscreen
smtpd     pass  -       -       n       -       -       smtpd

See the Results in Postfix Logs

#1 No proxy protocol

Jun 30 01:18:14 sd-33932 postfix/postscreen[2375]: 
       CONNECT from [127.0.0.1]:52841 to [127.0.0.1]:10024
Jun 30 01:18:22 sd-33932 postfix/smtpd[2376]: 
       disconnect from localhost[127.0.0.1]

#2 With proxy protocol

Jun 29 09:13:41 sd-33932 postfix/postscreen[30505]: 
       CONNECT from [<client public IP>]:59338 to [<server IP>]:25
Jun 29 09:13:52 sd-33932 postfix/postscreen[30505]: 
       DISCONNECT [<client public IP>]:59338
Subscribe to our blog. Get the latest release updates, tutorials, and deep-dives from HAProxy experts.