Transparent Load Balancing in Azure

When deploying a BIG-IP load balancer in Azure you often need to apply both source and destination address translation to work with the Azure load balancers. The following is how to reduce the amount of address translation to make it possible for a backend application to see the original client IP address and make it easier to correlate logs to public IP addresses.

Deployment Scenario

The following example makes use of several Azure and BIG-IP features to reduce the amount of address translation that is required.  

  1. Use Azure “Floating IP” to preserve the destination IP address to the BIG-IP
  2. Set SNAT (source network address translation) to None on the BIG-IP to preserve the source IP address
  3. Make use of Azure “HA Ports” to send the return traffic from the backend application to the correct BIG-IP device

How the pieces fit together

Preserving Destination IP Address

When you use the Azure Load Balancer there is an option to configure a “Floating IP”. Enabling this option causes ALB to no longer rewrite the destination IP address to the private address of the BIG-IP.

Preserving the Client IP Address

ALB will forward the connection with the original client IP address. The BIG-IP can be configured to also forward the client IP address by selecting the option of setting SNAT to None. This will cause the BIG-IP to still rewrite the destination IP to the pool member (otherwise how would the packet get there?), but preserve the source IP.

Getting the return traffic via ALB

Earlier we did not rewrite the client IP address, that creates a new problem of how do we respond to the original client with the correct source IP address (previously rewritten by the BIG-IP). In Azure you can configure a route table (or UDR) to point to a private address on an internal Azure Load Balancer (no public IP address). The ALB can then be configured to forward the connection back to the BIG-IP. This is the Azure equivalent of pointing the default gateway of a backend server to the BIG-IP (common “two-arm” deployment of BIG-IP on-prem).

Staying Active

A potential issue is that Azure load balancer will send to all the backends. To keep traffic symmetric (only flow through a single device) we configure Azure health monitors to monitor a health probe on the BIG-IP that will only respond on the "active" device.

Unusual Traffic Flow

Taking a look at the final picture of traffic flow we can see that we have created a meandering path of traffic. First stop, external ALB, next stop BIG-IP, on to the backend app, back to an internal ALB, return to the BIG-IP, and all the way back to the client. This “works” because the traffic always knows where to go next.

Should I be doing this?

This solution works well in situations where the backend application MUST see the original client IP address. Otherwise, it’s a bit complicated and reduces you to an Active/Standby architecture instead of a more scalable Active/Active deployment. Alternate approaches would be to use an X-Forwarded-For header and/or Proxy Protocol. You can also do this architecture without using an Azure load balancer and using the Cloud Failover Extension to move Azure Public IPs and Route Tables via API calls. Using the Azure load balancer makes it simpler to do this type of topology.

I hope this cleared things up for you.

Published Nov 09, 2020
Version 1.0

Was this article helpful?


  • Hi Eric, great article! I'll ask here so others might benefit: how would you configure the health probes on the Azure load balancer in this case? We only want the Active device to respond, but I believe the Backend Pool in the Azure Load Balancer should contain only the primary IP addresses of the Azure NIC's (ie, F5's self IP addresses). So what does the health monitor look like in Azure LB, and on the BIG-IP ?

  • There is another similar article that describes the monitor in more detail:

    It works out to be a VIP target from a traffic-group-local VIP to a traffic-group-1 VIP to check for which device is "active". The Azure health probe will typically go to the first private IP (hence the need for a VIP target unless you are using a secondary address, but that is not possible with the configuration above).


  • Thank you as always. For the sake of others reading the article, I'll share what I did in Azure to get this to work: I set up Azure LB health probe. In my case, I used an HTTP probe on port 80 requesting "/". Then I made sure that port 80 was allowed in the setting of the SelfIP, and I created 2 VIPs listening on port 80, one for each self IP. Importantly, these VIPs were in traffic-group-local-only, so there is 1 VIP on 1 device, and another on the other. This is explained in K13896. Then I applied a traffic policy to forward all incoming traffic on these VIPs to another VIP, which I configured as and, importantly, this last VIP lives in traffic-group-1. This VIP has an iRule attached that responds with 200 OK to every http request. The result: Azure sends health checks to both F5 VM's, both receive the health check but only the Active device can forward it to, since traffic-group-1 only exists on Active device. Now Azure believes Standby device is down and Active is up, and a LB Rule with "floatingIP" enabled in Azure works well and my application VIP has the same IP as the load-balancer front end. IF you're a customer that needs help here, leave a message or reach out, thanks!