Skip to content
A retired steel equipment rail sits unlit beside a compact modern module glowing indigo, a single pink cable running unbroken between them
Infrastructure

Migrating from F5 BIG-IP: A Concept-by-Concept Guide

Migrations away from BIG-IP rarely stall on the load balancing. Virtual servers, pools and monitors map across cleanly enough that an experienced engineer can rebuild a straightforward estate in an afternoon.

What stalls them is a folder of iRules written over eleven years by four people, three of whom have left, doing things nobody has fully catalogued — plus the quiet realisation, two weeks in, that several backends have been authenticating clients by source IP address and are about to stop working for reasons that have nothing to do with the load balancer.

This is a concept-by-concept map from BIG-IP to Tula, an honest account of what does not map, and a staged path that keeps a rollback available until the last possible moment.

The object model, side by side

The vocabulary differs more than the concepts do.

BIG-IP Tula Notes
Virtual server VIP (Virtual IP) Under Load Balancing > Virtual IPs; Layer 4 and Layer 7 variants
Pool Backend group (backend pool) The set of servers behind a VIP
Pool member / node Backend server An individual destination
Monitor Health check TCP connect, or HTTP verifying a URL and expected response code
Load balancing method Algorithm Six available — see below
Persistence profile Session persistence Source IP Hash, cookie insert, cookie prefix
Client SSL profile TLS termination on the VIP Certificate presented to clients
Server SSL profile Backend re-encryption Whether traffic to backends is HTTP or HTTPS
Local Traffic Policy Host- and path-based routing rules Evaluated in order
iRule No direct equivalent See the section on iRules — this is the real work
SNAT / AutoMap X-Forwarded-For insertion Different mechanism, important consequences
Traffic group / floating IP VRRP floating IP The HA pair’s shared address
BIG-IP DNS (GTM) GSLB Site-level failover by DNS
Certificate management ACME / Let’s Encrypt automation Renewal stops being a diary entry

Most of a migration is reading down that table. The interesting rows are the three with caveats.

Algorithms: fewer, and that is usually fine

BIG-IP offers a long list of load balancing methods, several of which are rarely used deliberately. Tula offers six: Round Robin, Weighted Round Robin, Least Connections, Weighted Least Connections, Source IP Hash and URI Hash.

BIG-IP method Tula equivalent
Round Robin Round Robin
Ratio (member/node) Weighted Round Robin
Least Connections Least Connections
Ratio Least Connections Weighted Least Connections
Source Address Affinity persistence Source IP Hash
Observed, Predictive, Dynamic Ratio No direct equivalent — see below

The adaptive methods — Observed, Predictive, Dynamic Ratio — adjust weights from live performance. They have no direct counterpart, and in practice this matters far less than it sounds. Estates using them usually adopted them speculatively rather than in response to a measured problem, and Least Connections captures most of the same benefit with behaviour you can reason about at three in the morning. If you genuinely relied on adaptive weighting, that is worth establishing early rather than discovering at cutover.

Health monitors: the same idea, and a chance to fix them

Monitors map to health checks directly. A TCP monitor becomes a TCP connect check; an HTTP monitor with a send string and receive rule becomes an HTTP check verifying a URL and expected response code.

Migration is a good moment to audit them, because inherited monitor configurations are reliably worse than people expect. Two things worth checking as you port each one:

  • Is it testing anything? A TCP monitor on a web server proves the port answers. It will report a backend as healthy while it returns 500 to every request. If the service is HTTP, check HTTP.
  • Is it testing too much? A monitor that reaches through to a shared database will mark every backend down when that database has a bad minute — converting a degraded service into a total outage, on the authority of your own health checking. Check what is genuinely local to that backend, and no deeper.

You are rebuilding these anyway. Rebuilding them correctly costs nothing extra.

Persistence: mind the mode, not just the setting

Persistence profiles map onto session persistence, with one substitution worth making deliberately rather than automatically.

BIG-IP persistence Tula
Cookie (insert) Cookie insert
Cookie (rewrite/passive) Cookie prefix
Source address affinity Source IP Hash
Universal / hash (iRule-driven) Usually cookie insert; see the iRules section

If the BIG-IP configuration used source address affinity for HTTP traffic, treat the migration as an opportunity to move to cookie insert instead. Source-IP persistence concentrates every user behind a corporate gateway or mobile carrier onto a single backend, and because the backend is chosen by hashing across available members, losing one backend reshuffles bindings for a large share of everyone — not just the users on the failed one. Cookie persistence has neither property. A great many source-address-affinity configurations exist because someone enabled the simplest option in 2014, not because the application required it.

TLS: two profiles become two decisions

BIG-IP separates the client-side and server-side TLS configuration into two profiles. Tula frames the same thing as termination on the VIP plus a choice about the backend leg: HAProxy terminates TLS and either forwards to backends over plain HTTP, or re-encrypts for end-to-end TLS.

The mapping is simple. The opportunity is the certificate lifecycle: if the estate you are leaving had certificates renewed by hand, by a calendar reminder, or by a script somebody wrote and left, this is the moment that stops being true. Enabling ACME automation during the rebuild costs minutes and retires an entire category of outage.

iRules: the part that actually takes the time

Here is the honest bit. iRules are TCL running in the data path, and there is no equivalent. Nor should you want one — but you cannot migrate an estate without knowing what yours do.

The productive approach is to categorise rather than to translate. Export every iRule and sort it into five buckets:

1. Redirects. HTTP to HTTPS, old domain to new, a path that moved. Overwhelmingly the largest bucket in most estates, and entirely declarative on the other side.

2. Host and path routing. “If the Host header is api., use the API pool; if the path starts with /static, use the static pool.” This is exactly host- and path-based routing rules, evaluated in order. Direct translation, usually clearer afterwards than it was before.

3. Header manipulation. Inserting, removing or rewriting request and response headers — security headers, internal routing hints, stripping something a backend should not see. Native, via header manipulation on the VIP.

4. Operational logic that is really configuration. Maintenance-page switching, IP-based access control, blocking a user agent. These map to rules or belong somewhere else entirely — a WAF, the application, a firewall.

5. Genuinely programmatic logic. Parsing a payload to make a routing decision, mutating a cookie’s contents, calling out to a sideband service mid-request, implementing a bespoke authentication scheme. This bucket does not map, and it is the only one that requires real decisions.

The reason this categorisation is worth doing before anything else is that bucket five is almost always much smaller than the folder’s size suggests — and it is the only part whose answer is “this logic moves into the application, or into a service in front of it, and that is a piece of work with its own timeline.”

Do the audit first. A migration plan written before anyone has read the iRules is a guess, and the number that matters is not how many iRules there are but how many are in bucket five.

What the audit tends to look like

The categorisation is worth doing on paper before anyone touches a configuration, because the shape of the answer determines the shape of the project. To illustrate the method rather than to predict your numbers — suppose an export yields 47 iRules across 60 virtual servers:

Bucket Count What happens to them
Redirects 19 Declarative rules; an afternoon
Host / path routing 11 Routing rules, evaluated in order
Header manipulation 8 Native on the VIP
Operational logic 6 Rules, or moved to a firewall or the application
Genuinely programmatic 3 Real design work

Forty-four of forty-seven are configuration. Three are a project. The plan you write for “47 iRules” and the plan you write for “3 pieces of logic to relocate, and a lot of typing” are very different documents, and only one of them survives contact with a steering group.

Two further things usually fall out of the audit, and both are welcome:

  • Duplicates. The same redirect rule, copy-pasted across eleven virtual servers with minor variations, three of which are almost certainly bugs.
  • Dead rules. iRules attached to virtual servers that no longer receive traffic, or guarding hostnames that were retired years ago. Migration is the only moment anyone will ever have a reason to check.

High availability and multi-site

Two more rows from the table deserve a sentence each, because their concepts survive the move intact even though their names do not.

Traffic groups and floating addresses become a VRRP floating IP. The pattern is the one you already run: a pair of nodes, a shared address that lives on the active member, and automatic movement on failure. What changes is the vocabulary and the configuration surface, not the design — and as with the certificates, it is worth proving by actually failing the pair over rather than trusting that it is configured.

BIG-IP DNS (GTM) becomes GSLB. Site-level failover is done the same way it always was, by handing out different DNS answers according to which sites are healthy. If you are moving a GTM configuration across, the thing worth recalculating rather than assuming is the failover timing: detection is health check interval multiplied by threshold, plus the check timeout, and propagation is bounded by the record’s TTL. That arithmetic is a different number from whatever your GTM was configured with, and it is better to know it than to discover it.

The failure nobody rehearses: your backends can see a different client

This one is not in the object model, does not appear in any configuration diff, and reliably surprises people about a fortnight in.

On BIG-IP, SNAT (often AutoMap) is commonly enabled, which replaces the client’s source address with the load balancer’s own. Backends therefore see the load balancer’s IP, and anything on the backend that cares about client identity has been reading X-Forwarded-For for years, because it had to.

Or — depending on the design — SNAT was not used, backends saw genuine client addresses, and over the years things quietly grew to depend on that: an IP allowlist on an admin path, a rate limiter keyed on remote address, a geolocation lookup, an audit log that records who did what from where, a licence check pinned to an address range.

Whichever of those two worlds you are in, changing load balancer changes what the backend sees. And the failure mode is nasty because it is silent and selective. The site works. Pages load. But the admin allowlist now admits everyone or no one, the rate limiter counts every user as one visitor, and the audit log has recorded the load balancer’s address for every action since Tuesday.

Establish this before you cut over, not after:

  1. On a representative backend, look at what is actually in the access log’s remote-address field today.
  2. Grep the application configuration for anything keyed on client IP — allowlists, rate limits, geo rules, audit fields.
  3. Confirm the new VIP inserts X-Forwarded-For (and X-Forwarded-Proto, which catches the other classic: an application generating http:// links because it can no longer tell the original connection was TLS).
  4. Confirm the application is actually configured to trust and read those headers — many frameworks require the proxy to be declared explicitly before they will honour them.

This single check is worth more than any amount of careful VIP-by-VIP diffing.

A staged migration path

The aim throughout is that rollback stays cheap until the last step, and that the last step is the smallest one.

Stage 1 — Audit. Export the BIG-IP configuration. Inventory virtual servers, pools, monitors, persistence profiles and certificates. Categorise every iRule into the five buckets. The output is a list, and a count of bucket five.

Stage 2 — Build in parallel. Construct the equivalent VIPs, backend groups, health checks and rules on Tula, pointing at the same live backends. Nothing is serving production traffic yet, and nothing about the existing estate has changed. Backends happily accept traffic from two load balancers at once.

Stage 3 — Validate out of band. Test the new VIPs directly by address, with a Host header override, before any DNS points at them. Every route, every health check, every certificate, and the client-IP checks above.

curl -sk https://<new-vip-address>/ -H 'Host: app.example.com' -o /dev/null -w '%{http_code}\n'
curl -sk https://<new-vip-address>/api/health -H 'Host: app.example.com' -i | head -20

Stage 4 — Lower the TTL, and wait. Drop the DNS TTL for the names you are moving to 60 seconds, and then wait longer than the old TTL before doing anything else. This is the step people skip, and it is the one that makes rollback fast. Cutting over on a 3,600-second TTL means an hour to undo a mistake; cutting over on 60 means a minute.

Stage 5 — Cut over, one name at a time. Repoint DNS. Start with the least critical service, and leave a gap between names — you are looking for the class of problem that only appears under real traffic, and moving everything at once removes your ability to tell which change caused it.

Stage 6 — Watch, then decommission. Leave the BIG-IP configuration in place and functional for at least one full business cycle, including a month-end if your traffic has one. Only when nothing has pointed at it for a fortnight should you start dismantling. The cost of leaving it running is small; the cost of not having it is an unbounded incident.

What you gain, and what you give up

Worth stating plainly rather than discovering.

Gained: certificate renewal that runs itself; a configuration model with fewer moving parts; a REST API and configuration you can hold in version control; no per-throughput licensing tier to plan capacity around.

Given up: in-path programmability. If your traffic genuinely requires arbitrary logic at the edge, that logic has to live somewhere, and the honest options are the application or a purpose-built service in front of it — not the load balancer. For most estates that is a simplification. For a few it is a project.

The decision is not really “is Tula as programmable as BIG-IP” — it is not, deliberately. It is “how much of our estate depends on that programmability”, and bucket five of your iRule audit is the answer.

Symptoms and causes

Symptom Likely cause
Admin path suddenly open to everyone, or to nobody Backend keying on remote address; needs to read X-Forwarded-For
Application generating http:// links behind TLS X-Forwarded-Proto missing or not trusted by the framework
Rate limiting counting all users as one Same root cause — client IP now the load balancer’s
Audit logs recording one address for every action Same again; check before cutover, not after
One hostname works, another 404s Routing rules evaluated in order — a broad rule shadowing a narrower one
Backend healthy on the old estate, down on the new Health check ported as HTTP where the old monitor was TCP, and the backend genuinely errors
All backends down at once Health check reaching a shared dependency
Users logged out after cutover Persistence not carried across, or source-IP affinity replaced by nothing
Rollback taking far longer than expected TTL not lowered before the cutover

Before you call it done

  1. Every route tested by address with a Host override, before DNS moves.
  2. Client IP visible to backends, confirmed in a real backend access log rather than assumed.
  3. Certificates valid, and one automatic renewal observed before the old estate is dismantled.
  4. Health checks proven by stopping a backend and watching it leave the pool — then return.
  5. Persistence proven by killing the backend a session is pinned to, and seeing what the application does.
  6. HA proven by failing over the pair and confirming the floating address and certificates follow.
  7. The old estate still standing, untouched, for a fortnight after the last name moved.

In short

The load balancing maps across almost mechanically. Budget your time for the two things that do not appear in the object model: categorising the iRules — where the number that matters is how many are genuinely programmatic, not how many exist — and establishing what your backends currently see as the client address, because that is the change that breaks things quietly.

Do those two first, keep the TTL low and the old estate alive, and the cutover itself is the least eventful part of the project.

Further reading: Layer 7 load balancing, load balancing algorithms, session persistence and the Let’s Encrypt guide.

CategoriesInfrastructure
Avatar photo

Alison Ivers

Leave a comment