Route misconfiguration is one of the most common configuration mistakes we see that can cause incidents on F5 Distributed Cloud (F5 XC). The four route types look deceptively simple in the console, but they have distinct behaviors, ordering rules, and gotchas. This article covers all four types with real field names, decision guidance, and the mistakes that actually happen in production.
What Routes Do in F5 XC HTTP Load Balancer
An HTTP Load Balancer in F5 XC is a full L7 proxy running at the Regional Edge (RE) and depending on the deployment model, Customer Edge (CE). We will use the Regional Edge as a deployment model for this article.
When a request arrives, the RE evaluates the route list in order and applies the first matching route. That route determines what happens to the request: forward it to an origin, redirect the client, return a synthetic response, or apply advanced routing logic.
Routes can be configured inside the HTTP Load Balancer configuration which opens a new Route Options window:
Multi-Cloud App Connect > Load Balancers > HTTP Load Balancers > [your LB] > Routes > Route Options
The four route types map to three underlying route actions:
| XC Route Type | Route Action | Traffic Goes To |
|---|---|---|
| Simple Route | route | Origin Pool |
| Redirect Route | redirect | Client (3xx response) |
| Direct Response Route | direct_response | Client (fixed response body) |
| Custom Route | route / redirect / direct_response | Depends on configuration |
Route Matching: How XC Evaluates Routes
Route evaluation is sequential, stops on first match, and has no automatic specificity ranking. The order you set is the order XC uses.
Evaluation Order
The HTTP Load Balancer evaluates routes sequentially, top to bottom. The first route that matches the incoming request wins. No further routes are evaluated.
This means:
- More specific routes must appear before broader ones.
- A catch-all route (prefix /) at the top will swallow everything. Nothing below it will ever match.
Path Match Types
Three path match types are available across all route types:
| Match Type | Field | Behavior |
|---|---|---|
| Prefix | path_prefix | Path must begin with the specified string |
| Exact | exact | Path must equal the value exactly (query string excluded) |
| Regex | regex | Entire path (minus query string) must match the regex pattern |
Prefix matching pitfall: The prefix /api matches /api/v1/users but also /apikeys and /api-internal. If you want to match a path segment boundary, use /api/ (trailing slash) or switch to regex.
Additional Matching Criteria
Beyond path, routes can match on:
- HTTP methods: GET, POST, PUT, DELETE, etc.
- Request headers: presence, exact value, regex
- Query parameters: Retain, Remove, or Replace
Combining criteria (e.g., path prefix + method + header) creates an AND condition: all specified criteria must match.
Route Type 1: Simple Routes
Simple routes are the workhorse of most HTTP Load Balancer configurations. They match a path (and optionally method/headers) and forward traffic to an Origin Pool.
When to Use
- Standard application traffic forwarding
- Path-based routing to different backend services
- API versioning (/v1/ → pool A, /v2/ → pool B)
- Microservice fanout from a single domain
Key Configuration Fields
| Field | Description |
|---|---|
| Path match type | Prefix / Exact / Regex |
| HTTP Method | Any, GET, POST, PUT, etc… |
| Origin Pool | The backend pool receiving the request |
| Host Rewrite Method | Disable/ Hostname / Header value: rewrites the Host header sent to origin |
| Query Parameters | Retain, Remove, Replace |
Advanced Options Worth Knowing
Path rewriting (under Advanced Options):
- Disabled: path sent to origin unchanged
- Prefix Replacement: replaces the matched prefix with a new string (e.g., strip /api/v1 prefix before sending to origin)
- Regex-based: full regex substitution on the path
Retry policy: The default retry policy is 1 retry on 5xx responses. Set this explicitly for your application in every route:
- Disabled: no retries; required for write operations
- Default: 1 retry on 5xx
- Custom: specify retry conditions, count, and interval
Per-route WAF override: Each simple route can attach its own WAF App Firewall policy. This completely replaces the load balancer-level WAF for matching requests; it is not additive. Use this to enforce stricter rules on sensitive paths (e.g., /admin/) or to relax inspection on certain paths.
Example: API Path Routing
Route 1: Prefix /api/v2/ → origin-pool-v2 (exact origin for v2) Route 2: Prefix /api/v1/ → origin-pool-v1 (legacy backend) Route 3: Prefix /api/ → origin-pool-api (catch-all for API paths) Route 4: Prefix / → origin-pool-web (catch-all for everything else)
Order matters here. If route 3 or 4 appeared first, routes 1 and 2 would never fire.
Route Type 2: Redirect Routes
Redirect routes return an HTTP 3xx response directly to the client. No origin pool is involved: the RE handles the response entirely.
When to Use
- HTTP → HTTPS redirect (though XC has a dedicated LB-level toggle for this)
- Domain canonicalization (www.example.com → example.com)
- Legacy URL migrations (/old-path/ → /new-path/)
- Temporary redirects during maintenance or A/B migrations
Key Configuration Fields
| Field | Description |
|---|---|
| Protocol | HTTP or HTTPS |
| Host | Target FQDN; supports non-standard ports |
| Redirect Path / URI | Target path; if left unset, original URI is preserved (including query string) |
| Response Code | 301 (Permanent), 302 (Temporary), 307, 308 |
Redirect Behavior: URI Preservation
When you leave the redirect path unset, XC preserves the original URI path and query string in the Location header. This is useful for protocol/host-only redirects where you just want to change the scheme or domain without touching the path.
Example: Redirect all HTTP traffic to HTTPS on the same host:
Protocol: HTTPS Host: same-as-request (leave blank or match domain) Path: (unset — preserve original URI) Code: 301
Redirect Route Limitations
Simple redirect routes (defined directly on the LB) do not support custom header manipulation on the redirect response. If you need to inject headers (e.g., Cache-Control: no-store on the redirect response), use a Custom Route object instead.
Route Type 3: Direct Response Routes
Direct response routes return a fully synthetic HTTP response to the client. The request never reaches an origin pool: the RE generates the response itself.
When to Use
- Health check endpoints that should always return 200 (e.g., /healthz) without touching the app
- Maintenance mode pages: serve a 503 with a message body while origin is down
- Blocking specific paths with a meaningful error body (vs. a generic deny)
- Canary or feature-flag placeholders that return 404 before the feature ships
- Robots.txt or security.txt served from the edge without an origin
Key Configuration Fields
| Field | Description |
|---|---|
| HTTP Status Code | Any valid HTTP status code (200, 403, 503, etc.) |
| Response Body | Static text or HTML body returned to client |
| Path match | Same prefix/exact/regex options as other route types |
Example: Edge-Served Health Check
Path: Exact /healthz Method: GET Action: Direct Response Status: 200 Body: OK
This responds to health probes from AWS ALB, Kubernetes ingress controllers, or uptime monitors without any load on the backend. Particularly useful during blue/green deployments when the app might not yet be healthy.
Route Type 4: Custom Routes
Custom routes reference standalone Route objects created separately in XC and attached to one or more HTTP Load Balancers. Unlike the other three types, they follow a service-mesh model rather than a traditional LB model.
When to Use Custom Routes
- Weighted traffic splitting between origin pools (canary releases, blue/green)
- Request/response header manipulation not available on simple routes
- Advanced retry policies with specific conditions and intervals
- Traffic mirroring (shadow traffic to a secondary backend for testing)
- Reusable route logic shared across multiple load balancers
Architecture: Route Objects vs. Inline Routes
Inline routes (simple, redirect, direct response) are defined directly on the HTTP Load Balancer. Custom route objects are:
- Created as standalone objects under Multi-Cloud App Connect
- Referenced by the HTTP Load Balancer
- Reusable: multiple LBs can reference the same route object
Weighted Clusters
Custom routes enable weighted traffic splitting across multiple upstream clusters, equivalent to BIG-IP pool ratio weights or AWS ALB weighted target groups.
Route: Prefix /api/ Cluster A (origin-pool-v2): weight 90 Cluster B (origin-pool-v1): weight 10
This is the correct mechanism for canary deployments and gradual traffic shifts on F5 XC. The weights are percentage-based and must sum to 100.
Header Manipulation
Custom routes support header operations at the route level, applied before forwarding to origin:
| Operation | Direction | Example |
|---|---|---|
| Add header | Request | X-Forwarded-For: {client-ip} |
| Remove header | Request | Strip Authorization before certain paths |
| Add header | Response | Strict-Transport-Security: max-age=31536000 |
| Remove header | Response | Strip Server header from responses |
Header manipulation runs in order: route-level → virtual host-level → route configuration-level.
Retry Policies
Route retry policies take complete precedence over any virtual host-level retry policy. Configure explicitly:
| Field | Description |
|---|---|
| Retry on | Conditions: 5xx, gateway-error, reset, connect-failure, retriable-4xx |
| Number of retries | Integer |
| Per-try timeout | Timeout applied to each individual retry attempt |
| Retry interval | Base interval between retries |
Traffic Mirroring
Mirror policies shadow a copy of each request to a secondary cluster. The mirrored request is fire-and-forget. Example:
- Testing a new backend version against live traffic without affecting users
- Security analysis pipelines
Route Ordering and Priority
Route order is the most common source of routing bugs in XC deployments. There is no automatic specificity ranking; you own the order.
The Rules
- Routes evaluate top to bottom.
- First match wins. Evaluation stops.
- Disabling a route (via the Route Activation Status toggle) does not remove it: traffic falls through to the next matching route.
Recommended Ordering Pattern
Order routes from most specific to least specific:
- Exact paths first Exact /api/v2/auth/token 2. Specific prefixes next Prefix /api/v2/ 3. Broader prefixes after Prefix /api/ 4. Path-specific exceptions Exact /healthz 5. Catch-all last Prefix /
Common Ordering Mistakes
| Mistake | Symptom | Fix |
|---|---|---|
| Catch-all prefix / first | All traffic hits one origin; other routes never fire | Move catch-all to last position |
| /api prefix before /api/v2/ | V2 traffic hits wrong origin | Reverse the order |
| Disabled/Unused route above active route | Traffic silently hits next route with different behavior | Remove disabled routes; don’t rely on toggle for permanent changes |
| Redirect route below a prefix match | Redirect never fires | Move redirect above the prefix that would match it first |
Common Mistakes and Gotchas
Prefix /api matches /apikeys. The prefix match does not anchor to path segment boundaries. /api matches /api/, /api/v1/, and also /apikeys, /api-docs. Use /api/ (trailing slash) or regex if segment boundary matters.
Per-route WAF is a full replacement, not additive. Attaching a WAF policy to a route does not stack with the LB-level WAF. It replaces it entirely for that route. If your LB WAF is in blocking mode and you attach a route-level WAF in monitoring mode, that route is now in monitoring mode only.
Custom routes enforce TLS: test before production. If your origin uses a self-signed certificate and you switch from a simple route to a custom route without uploading the Root CA, connections will fail. Test in a staging environment first.
Header manipulation on redirect requires a custom route object. Simple redirect routes in XC do not support response header injection. If you need Cache-Control or Vary headers on your redirects, you must use a standalone custom route object with redirect action.
Regex route performance at scale. Regex routes require full path evaluation on every request. At high request volumes, a large number of regex routes adds measurable CPU overhead compared to prefix or exact routes. Use regex only where prefix or exact matching is insufficient.
FAQ
Q: What is the difference between a Simple Route and a Custom Route?
A: Simple routes are inline on the HTTP Load Balancer and forward traffic directly to an Origin Pool. Custom routes are standalone objects that use an Endpoints → Clusters → Routes model, support weighted traffic splits, header manipulation, and mirroring, but cannot reference Origin Pools directly.
Q: Why is my catch-all route matching everything instead of the specific routes below it?
A: Route evaluation stops at the first match. If your catch-all prefix (/) is above more specific routes, it wins every time. Move the catch-all to the last position in the list.
Q: Can I use a Custom Route to send traffic directly to an F5 XC Origin Pool?
A: No. Custom routes do not support Origin Pools directly. They use an Endpoints → Clusters → Routes abstraction. If you need weighted splitting with Origin Pool support, custom routes are not the right fit; simple routes forward to Origin Pools but do not support weighted clusters.
Q: My POST requests are creating duplicate records and I traced it to XC retries. What is happening?
A: The default retry policy on simple routes is “1 retry on 5xx.” A POST that hits a 500 gets retried once, potentially double-writing. Set the retry policy to Disabled on any route handling non-idempotent operations (POST, PUT, PATCH, DELETE).
Q: Does attaching a WAF policy to a route add rules on top of my LB-level WAF?
A: No. Per-route WAF replaces the LB-level WAF entirely for requests matching that route. If your LB WAF is in blocking mode and the route WAF is in monitoring mode, those requests are evaluated in monitoring mode only.
Q: My Custom Route TLS connections to origin are failing but the same origin works fine on a Simple Route. Why?
A: Custom routes enforce strict TLS with no skip-verify option. Simple routes do not have this requirement. For custom routes, upload the Root CA certificate for your origin, or use the use_volterra_trusted_ca_url flag via the API for public CAs. Self-signed certs without the Root CA uploaded will fail silently.
Q: I disabled a route in the console but traffic behavior changed unexpectedly. What happened?
A: Disabling a route via the Route Activation toggle does not remove it from evaluation. Traffic falls through to the next matching route in the list. If that route is a broad catch-all, the behavior shift may look correct until something that depends on specific routing breaks. Remove routes you no longer need rather than toggling them off.

