F5 BIG-IP stacks per-instance licensing and throughput tiers on premium appliance hardware, with modules (LTM, ASM, APM) billed separately and costly support renewals. HAProxy is the closest open analog to a hardware ADC: a high-performance L4/L7 load balancer with rich ACLs and TLS termination, running on commodity hardware or VMs. For straightforward load balancing and TLS offload, it removes the license tax, but you’ll be translating config and re-creating any advanced modules you depend on.
Be honest about the modules
LTM (core load balancing) maps well to HAProxy. ASM (WAF) and APM (access/auth) do not, HAProxy is not a WAF or an identity proxy out of the box. If you rely on ASM, plan a dedicated WAF (e.g. ModSecurity/Coraza, or a cloud WAF); if you rely on APM, plan an auth proxy (e.g. oauth2-proxy). Inventory which F5 modules are actually in use before assuming a one-box replacement.
The translation work
Map each F5 concept to HAProxy config:
- Virtual Server (VIP) → a
frontendbound to the IP/port. - Pool + members → a
backendwithserverlines and a balancing algorithm. - Health monitors → HAProxy health checks (
option httpchk,check). - Persistence profiles → stick tables (cookie or source-based).
- iRules → ACLs and
http-request/http-responselogic. Simple iRules convert cleanly; complex TCL iRules are the biggest manual effort and sometimes need Lua-style rethinking or moving logic upstream. - SSL profiles →
bind ... ssl crt; migrate certificates and chains into HAProxy’s store.
Where the iRules go
iRules are where most of the migration effort concentrates, so treat them as their own workstream. Pull every iRule off the BIG-IP and sort it by what it actually does. The large majority inspect a header, branch on a URI, issue a redirect, or select a pool, and those translate directly into HAProxy ACLs paired with use_backend, http-request redirect, and http-request set-header. Host and path routing that lived in a when HTTP_REQUEST block becomes a few acl lines and a use_backend ... if rule.
For anything that reads from a large lookup, a customer-to-pool table or a geo decision, do not port it as a long if/else chain. Load it as a map file and resolve it with something like req.hdr(host),map(/etc/haproxy/hosts.map). That keeps the config readable and lets you update the table without reloading logic. Reserve Lua for the procedural iRules that manipulate state or call out mid-request, and expect those to be the slow part of the project. Where an iRule was really compensating for an application shortcoming, the cleanest fix is often to move that logic back into the app rather than carry it into HAProxy.
Certs, checks, and sticky sessions
Migrate certificates by exporting each cert with its key and full chain and concatenating them into one PEM per site, then point bind ... ssl crt at the file or at a crt directory for SNI. Rebuild the intent of your F5 SSL profiles with ssl-default-bind-ciphers and a minimum TLS version rather than trying to mirror profile names, and validate the served chain against an external client so a missing intermediate does not slip through.
Health checks carry real risk because a mistranslation silently marks good servers down. Convert F5 monitors to option httpchk with http-check expect status or http-check expect string for HTTP pools, and let the default connect check stand for raw TCP. Set inter, fall, and rise to match your F5 interval and retry values so failover timing is unchanged. Persistence profiles become HAProxy stick tables: source-IP persistence maps to a stick-table type ip with stick on src, and application cookie affinity maps to cookie SRV insert indirect nocache with a per-server cookie value. Match the method each application needs rather than porting every profile verbatim.
Rebuilding HA with keepalived
The F5 pair gave you packaged HA, and with HAProxy you build the equivalent yourself. Run two HAProxy nodes with keepalived managing a shared virtual IP over VRRP, and add a vrrp_script that checks the HAProxy process so the VIP moves when the daemon dies, not only when the host does. Test failover deliberately before go-live: kill the process, pull a link, reboot a node, and confirm the VIP lands cleanly and connections drain the way they did on the F5. Wire up the stats socket and Prometheus exporter at the same time so you have visibility into backend up counts and error rates once you leave the BIG-IP UI.
Size for SSL TPS, not just throughput
The classic ADC-migration mistake is sizing on raw throughput. Size on L7 requests/sec and SSL/TLS handshakes-per-second, TLS termination is CPU-intensive, and TLS inspection cuts effective throughput sharply. Deploy active/standby HA (keepalived/VRRP) to match the resilience the F5 pair gave you, and account for concurrent connections and connections/sec.
Swinging traffic across, service by service
- Inventory Virtual Servers, pools/members, health checks, persistence, iRules, certificates, and the F5 modules in use.
- Build HAProxy in HA, translating each VIP → frontend/backend, iRules → ACLs, and importing certs and health checks.
- Warm it with test traffic and validate routing, persistence, and TLS/SNI live (
curl, SNI checks). - Swing the VIP or DNS per service to HAProxy, keeping the F5 configured as immediate fallback through hypercare.
- Roll back by swinging DNS/VIP back if anything misbehaves.
Proving it against the F5 baseline
The acceptance bar is L7 routing, persistence, TLS/SNI, health-check/failover, and a load test versus the F5 baseline. Confirm certificate chains validate, sticky sessions hold, and failover is clean before retiring the appliance.
Is the trade worth it?
F5 BIG-IP → HAProxy removes per-instance ADC licensing for core load balancing and TLS offload; the work is translating Virtual Servers and iRules, sizing for SSL TPS, and replacing ASM/APM separately if you use them. Build in HA, validate with test traffic, then swing traffic per service with the F5 as fallback. Model your per-instance savings in the calculator above, and treat them as illustrative until you confirm your throughput and module requirements.