Redirects & Rewrites
Overview
Redirects and rewrites are ordered (drag-and-drop priority) request-mutation rules scoped per listener. They run after WAF and before backend routing in the request pipeline.
Redirects
Redirects send the client to a different URL. Each redirect has:
| Property | Description |
|---|---|
| Name | Display name |
| Listener scoping | listener_ids, listener_id, frontend_match, or global |
| Priority | Drag-and-drop ordering |
| Source | Path prefix or regex to match |
| Target | Destination URL |
| Type | permanent (301), temporary (307), or regex |
| Code | HTTP status code |
Redirect Types
| Type | Status | Description |
|---|---|---|
| permanent | 301 | Permanent redirect (cached by browsers) |
| temporary | 307 | Temporary redirect (preserves method) |
| regex | 301/307 | Regex-based redirect with capture groups |
Listener Scoping
| Scope | Description |
|---|---|
| All listeners | Apply to every listener |
| Specific listeners | Apply to selected listener IDs |
| Frontend match | Apply to listeners matching a frontend name pattern |
Rewrites
Rewrites modify the request URI without sending a redirect. Each rewrite has:
| Property | Description |
|---|---|
| Name | Display name |
| Listener scoping | Same options as redirects |
| Priority | Drag-and-drop ordering |
| Source pattern | Pattern to match in the URI |
| Target | Replacement string |
| Type | Path rewrite, query rewrite, or full URI |
A redirect tells the browser to go to a new URL (the URL changes in the address bar). A rewrite changes the URI internally — the browser URL stays the same, but the backend receives a different path.
Custom Response Pages
Custom response pages replace HAProxy’s default error pages with your own HTML for any HTTP status code. Pages are scoped per listener (one or many, or all listeners when none are selected) and have a configurable content type (default text/html).
| Property | Description |
|---|---|
| Status code | The HTTP status code this page applies to (e.g. 403, 429, 500, 502, 503) |
| Listeners | Selected listeners, or all when none selected |
| Content type | MIME type (default text/html; use application/json for API error bodies) |
| Content | The page body — HTML/JSON with {{ variable }} template substitutions |
Template Variables
All variables are substituted at request time using the live request’s attributes.
| Variable | Description |
|---|---|
{{ request_id }} | HAProxy unique request ID (for support correlation) |
{{ waf_unique_id }} | Coraza transaction ID (for 403 WAF blocks) |
{{ client_ip }} | Client IP address |
{{ client_port }} | Client TCP port |
{{ method }} | HTTP method (GET, POST, …) |
{{ uri }} | Full request URI |
{{ path }} | Request path (without query string) |
{{ query }} | Query string (without ?) |
{{ host }} | Host header value |
{{ user_agent }} | User-Agent header value |
{{ referer }} | Referer header value |
{{ timeout }} | Configured timeout (for timeout-generated errors) |
{{ timestamp }} | Request timestamp |
{{ frontend_name }} | HAProxy frontend (listener) name |
{{ backend_name }} | HAProxy backend name |
{{ rate_limit_window }} | Rate limit window in seconds (for 429 rate limit pages) |
{{ rate_limit_duration }} | Block duration in seconds (for 429 tarpit pages; 0 when no block duration) |
Listener rate limits return 429 Too Many Requests by default (configurable via the rate limit’s response_code). If you previously created a custom 503 page for rate limiting, create a 429 page instead — the 503 page will no longer be served for rate-limited requests.
Preview
Each page row has a Preview action (eye icon) that opens the rendered template in a new browser tab so you can verify the layout and variable substitution before applying.
Step-by-Step: Redirect HTTP to HTTPS
- Navigate to Traffic > Redirects & Rewrites
- Click Add Redirect
- Name:
http-to-https - Listener: select your HTTP listener (port 80)
- Source:
/(match all paths) - Target:
https://example.com(your domain) - Type: permanent (301)
- Save and Apply
Use 307 instead of 301 for temporary redirects. 301 is cached aggressively by browsers and search engines. If you’re not sure the redirect is permanent, use 307.
Step-by-Step: Rewrite an API Path
- Navigate to Traffic > Redirects & Rewrites > Rewrites
- Click Add Rewrite
- Name:
api-v1-to-v2 - Listener: select your listener
- Source pattern:
/api/v1/ - Target:
/api/v2/ - Type: path rewrite
- Save and Apply
Now requests to /api/v1/users are internally rewritten to /api/v2/users without changing the browser URL.
Step-by-Step: Custom 403 Page
- Navigate to Traffic > Redirects & Rewrites > Error Pages
- Click Add Page
- Status code: 403
- Content type:
text/html(orapplication/jsonfor an API error body) - Listeners: all (or select specific listeners)
- Paste your HTML template, using
{{ request_id }}for support correlation and{{ waf_unique_id }}for WAF-block correlation - Save and Apply
- Use the Preview action (eye icon) to open the rendered page in a new tab and verify the layout
Verification
-
Test a redirect:
curl -k -v http://localhost/ 2>&1 | grep -i 'location\|301\|307' -
Test a rewrite:
curl -k -v https://localhost/api/v1/users 2>&1 | grep -i 'request'The backend should receive
/api/v2/userswhile the client URL shows/api/v1/users. -
Test custom error page:
curl -k https://localhost/forbidden-endpointExpect your custom 403 page with the request_id rendered.
Next Steps
- Headers — Response and request header rules
- Listeners & Backends — Configure listener bindings
- Security Rules — Layer access control
- Page Protect — Security headers via CSP management