Logging Client IPs behind a Proxy with Docker

One of the issues that can arise with advanced deployments of Mautic is the tracking the real IP address of the visitors. Whether one is using the Docker container or simply deploying Mautic behind a load balancer such as NGINX, without custom configuration, Mautic will detect the internal IP address (in an IP range such as 10.0.0.0/8, 172.16.0.0/12, or 192.168.0.0/16) that proxied the visitor’s HTTP request to Mautic when their browser loaded the tracking code. This prevents Mautic from detecting their actual IP address.

Since Mautic relies on a visitors’ IP address to generate an anonymous contact for that visitor before their email address (the unique identifier) is identified by a form or the API, using Mautic behind a load balancer, LXC proxy device, or a Docker Swarm network can result in an internal IP address being recorded for every visitor who reaches your website. This prevents any page hits from being tracked, so actions triggered by campaign decisions such as “Clicks email” or “Visits a page” will not fire.

A potential workaround to this is adding track_private_ip_ranges => true, to the app/config/local.php in your Mautic installation’s directory but the contacts will still be recorded with the private IP address of your load balancer, rather than the visitor’s public-facing IP address.

With the track private IPs approach, only the load balancer or edge router IP will be recorded in the Mautic contact’s audit log so identifying visitors by IP (if “on” in Configuration > Tracking Settings) and geo IP lookup will not function correctly.

Other approaches that have been suggested for tracking the real IP address of visitors for previous Mautic versions have included parsing the X-Forwarded-For HTTP header passed by some reverse proxies, but in our experience, this approach is not always reliable with every combination of reverse proxy and web server.

The recommended way to track the real IP address of a visitor behind a reverse proxy is by using the PROXY protocol. The PROXY protocol was introduced by HAProxy, which in fact, many managed load balancers made available by cloud providers such as DigitalOcean are built upon. It has become a standard that other load balancers such as Traefik and web servers including Apache and NGINX support as well.

The Traefik, Apache, and NGINX documentation explain how to configure each of them respectively to accept the PROXY Protocol and “rewrite the IP address of the load balancer or proxy to the one received in the PROXY protocol header.”

If using a Docker container to deploy Mautic, the container image must be rebuilt to support this. This is an included feature with the custom Docker image for customers of our complete Mautic reseller solution, powered by Docker.

It is imperative to enable the PROXY protocol on the proxy (or proxies) in your architecture and on the web server before enabling PROXY protocol on DigitalOcean, Elastic Load Balancer, or the equivalent with your cloud provider. Otherwise all the connections will be refused as the downstream is not set up to accept the PROXY protocol.

The PROXY protocol preserves the public-facing IP address of the website visitor and allows it to be handed off from the reverse proxy to the web server. Even if there are multiple load balancers in front of each other, information about the visitor can be handed off between multiple successive proxies using PROXY protocol.

For example, for our clients we have deployed load balanced Mautic clusters where the request hits a cloud load balancer, is forwarded to Traefik on a Docker Swarm cluster, and ultimately arrives in the Docker container where the Mautic instance is running. By leveraging the PROXY protocol, placing the Docker container into host networking mode is not necessary to capture the real IP address of the visitor. For further reading, the topic of “retrieving a user’s IP address in Docker Swarm mode” is discussed in this Github issue.

Tracking client IP addresses in Mautic with PROXY protocol
Tracking client IP addresses in Mautic with PROXY protocol

This configuration makes it possible to host multiple Mautic instances for different end users without needing to have one public IP address for every instance. With the host networking mode, each Mautic instance would require its own port 80 (HTTP) and 443 (HTTPS) on its own virtual server, negating the benefits of hosting Mautic in a multi-tenant environment using Docker.

Even if you are deploying Mautic only for your own organization, using the PROXY protocol to facilitate the tracking of visitors’ actual IP addresses behind a proxy is helpful for scaling Mautic to multiple servers for high traffic websites and large databases. Another commonly misconfigured setting is Configuration > Allowed Proxies. Normally for a single server Mautic deployment this value can be left blank, but if you are trying to scale Mautic out to multiple servers using a load balancer or proxy, it is necessary to configure this field with the correct CIDR block(s). This is another reason why Mautic can fail to connect when it is behind a load balancer setup.

If you are a marketer who finds the infrastructure & networking aspects of deploying open source Mautic daunting, please don’t hesitate to contact our team for our pre-built and pre-configured Mautic solutions which can be deployed at a range of cloud providers – including AWS, DigitalOcean, and Google Cloud.