Introduction
HAProxy's Access Control List (ACL) engine is one of its most powerful features, allowing you to inspect every facet of an incoming request — the path, hostname, HTTP headers, query strings, source IP, SSL attributes, and more — and then route, reject, or modify traffic accordingly. This article is a comprehensive, production-ready guide to building ACL rules that cover virtual hosting, microservice path routing, header-based canary deployments, geographic steering, and request sanitisation. Every example uses real HAProxy 2.8+ syntax and has been tested for correctness.
1. ACL Fundamentals
1.1 What Is an ACL?
An ACL is a named boolean test applied to request or response data. HAProxy evaluates ACLs in order and uses them inside
use_backend,
http-request, and
http-responsedirectives to make routing and policy decisions.
1.2 ACL Syntax
acl <name> <criterion> [flags] [operator] <value> ...
Key components:
- name — a descriptive identifier (e.g.,
is_api
,host_blog
). - criterion — the fetch method (e.g.,
path_beg
,hdr(host)
,src
). - flags — modifiers like
-i
(case-insensitive),-f
(read from file),-m
(match method). - value — one or more values to match against.
1.3 Common Fetch Methods
# Layer 4
src # Client source IP
dst_port # Destination port
ssl_fc # 1 if connection is SSL
# Layer 7 — Host and Path
path # Exact path
path_beg # Path begins with
path_end # Path ends with
path_reg # Path matches regex
path_sub # Path contains substring
hdr(host) # Host header value
hdr_beg(host) # Host header begins with
# Layer 7 — Headers and Method
method # HTTP method (GET, POST, etc.)
hdr(X-Forwarded-For) # Any header by name
hdr_cnt(header) # Number of occurrences of a header
req.hdr(User-Agent) # User-Agent value
# Layer 7 — Query string
url_param(name) # Value of a URL parameter
query # Full query string
1.4 Match Flags
-i # Case-insensitive comparison
-f # Load values from a file (one per line)
-m str # Exact string match (default for most)
-m beg # Begins with
-m end # Ends with
-m sub # Contains substring
-m reg # POSIX regex
-m found # True if the fetch returns any value
-m len # Match on length
2. Path-Based Routing
Path-based routing sends requests to different backend pools based on the URL path. This is the foundation of microservice routing.
2.1 Basic Path Prefix Routing
frontend http_front
bind *:80
mode http
# Define ACLs
acl is_api path_beg /api
acl is_static path_beg /static /assets /images
acl is_websocket path_beg /ws
acl is_health path /health
# Route to backends
use_backend api_servers if is_api
use_backend static_servers if is_static
use_backend websocket_servers if is_websocket
use_backend health_check if is_health
default_backend web_servers
backend api_servers
mode http
balance leastconn
option httpchk GET /api/ping
http-check expect status 200
server api1 10.0.1.10:8080 check inter 3s fall 3 rise 2
server api2 10.0.1.11:8080 check inter 3s fall 3 rise 2
backend static_servers
mode http
balance roundrobin
server static1 10.0.2.10:80 check
server static2 10.0.2.11:80 check
backend websocket_servers
mode http
balance source
timeout tunnel 3600s
server ws1 10.0.3.10:8081 check
server ws2 10.0.3.11:8081 check
backend web_servers
mode http
balance roundrobin
server web1 10.0.4.10:80 check
server web2 10.0.4.11:80 check
backend health_check
mode http
http-request return status 200 content-type text/plain string "OK"
2.2 Path Stripping (Rewriting) for Backends
Often, your API backend doesn't expect the
/apiprefix. Strip it before forwarding:
backend api_servers
mode http
balance leastconn
# Strip /api prefix: /api/v1/users -> /v1/users
http-request set-path %[path,regsub(^/api,,)]
server api1 10.0.1.10:8080 check
server api2 10.0.1.11:8080 check
2.3 Versioned API Routing
frontend http_front
bind *:80
mode http
acl is_api_v1 path_beg /api/v1
acl is_api_v2 path_beg /api/v2
acl is_api_v3 path_beg /api/v3
use_backend api_v1_servers if is_api_v1
use_backend api_v2_servers if is_api_v2
use_backend api_v3_servers if is_api_v3
default_backend web_servers
backend api_v1_servers
mode http
server apiv1a 10.0.10.10:8080 check
backend api_v2_servers
mode http
server apiv2a 10.0.11.10:8080 check
server apiv2b 10.0.11.11:8080 check
backend api_v3_servers
mode http
server apiv3a 10.0.12.10:8080 check
server apiv3b 10.0.12.11:8080 check
server apiv3c 10.0.12.12:8080 check
2.4 Regex-Based Path Routing
frontend http_front
bind *:80
mode http
# Match /user/123/profile, /user/456/settings, etc.
acl is_user_profile path_reg ^/user/[0-9]+/profile$
acl is_user_settings path_reg ^/user/[0-9]+/settings$
# Match file extensions
acl is_image path_end .jpg .jpeg .png .gif .webp .svg
acl is_document path_end .pdf .docx .xlsx
use_backend profile_service if is_user_profile
use_backend settings_service if is_user_settings
use_backend cdn_servers if is_image
use_backend document_servers if is_document
default_backend web_servers
3. Host-Based Routing (Virtual Hosting)
Host-based routing multiplexes multiple domains or subdomains through a single HAProxy frontend.
3.1 Simple Multi-Domain Setup
frontend https_front
bind *:443 ssl crt /etc/haproxy/certs/ alpn h2,http/1.1
mode http
# Host-based ACLs (case-insensitive)
acl host_www hdr(host) -i www.example.com example.com
acl host_api hdr(host) -i api.example.com
acl host_blog hdr(host) -i blog.example.com
acl host_admin hdr(host) -i admin.example.com
acl host_grafana hdr(host) -i grafana.example.com
use_backend web_servers if host_www
use_backend api_servers if host_api
use_backend blog_servers if host_blog
use_backend admin_servers if host_admin
use_backend grafana_servers if host_grafana
default_backend web_servers
3.2 Wildcard Subdomain Routing
frontend https_front
bind *:443 ssl crt /etc/haproxy/certs/ alpn h2,http/1.1
mode http
# Match any subdomain of example.com
acl host_example hdr_end(host) -i .example.com
# Match specific subdomains first (more specific rules first)
acl host_api hdr(host) -i api.example.com
acl host_staging hdr_beg(host) -i staging.
use_backend api_servers if host_api
use_backend staging_servers if host_staging host_example
use_backend web_servers if host_example
default_backend fallback_servers
3.3 Host-Based Routing from a Map File
For environments with many domains, use a map file for cleaner configuration:
# /etc/haproxy/maps/domain-to-backend.map
www.example.com web_servers
example.com web_servers
api.example.com api_servers
blog.example.com blog_servers
admin.example.com admin_servers
grafana.example.com grafana_servers
app.clienta.com clienta_servers
app.clientb.com clientb_servers
frontend https_front
bind *:443 ssl crt /etc/haproxy/certs/ alpn h2,http/1.1
mode http
# Use map file for dynamic backend selection
use_backend %[req.hdr(host),lower,map(/etc/haproxy/maps/domain-to-backend.map,fallback_servers)]
This approach scales to hundreds of domains and can be updated at runtime via the HAProxy Runtime API:
# Add or update a map entry at runtime
echo "set map /etc/haproxy/maps/domain-to-backend.map app.clientc.com clientc_servers" | socat stdio /var/run/haproxy/admin.sock
# List all entries
echo "show map /etc/haproxy/maps/domain-to-backend.map" | socat stdio /var/run/haproxy/admin.sock
# Delete an entry
echo "del map /etc/haproxy/maps/domain-to-backend.map app.clientb.com" | socat stdio /var/run/haproxy/admin.sock
4. Header Inspection and Manipulation
4.1 Routing by Custom Header
frontend http_front
bind *:80
mode http
# Canary deployment: route if X-Canary: true header is present
acl is_canary hdr(X-Canary) -i true
# Internal traffic detection
acl is_internal hdr(X-Internal-Token) -i s3cretT0ken2026
# Mobile app detection
acl is_mobile_app hdr_sub(User-Agent) -i MobileApp/
use_backend canary_servers if is_canary
use_backend internal_servers if is_internal
use_backend mobile_backend if is_mobile_app
default_backend web_servers
4.2 Routing by HTTP Method
frontend http_front
bind *:80
mode http
acl is_api path_beg /api
acl is_read_method method GET HEAD OPTIONS
acl is_write_method method POST PUT PATCH DELETE
# Split read/write traffic to different backend pools
use_backend api_read_replicas if is_api is_read_method
use_backend api_write_primary if is_api is_write_method
default_backend web_servers
backend api_read_replicas
mode http
balance roundrobin
server read1 10.0.1.10:8080 check
server read2 10.0.1.11:8080 check
server read3 10.0.1.12:8080 check
backend api_write_primary
mode http
balance leastconn
server write1 10.0.2.10:8080 check
server write2 10.0.2.11:8080 check
4.3 Adding, Modifying, and Deleting Headers
frontend http_front
bind *:80
mode http
# Add headers before forwarding
http-request set-header X-Forwarded-Proto http
http-request set-header X-Real-IP %[src]
http-request set-header X-Request-ID %[uuid()]
# Delete dangerous headers from client
http-request del-header X-Forwarded-For
http-request del-header X-Original-URL
http-request del-header Proxy
# Add security headers to response
http-response set-header X-Content-Type-Options nosniff
http-response set-header X-Frame-Options DENY
http-response set-header Referrer-Policy strict-origin-when-cross-origin
http-response del-header Server
http-response del-header X-Powered-By
default_backend web_servers
4.4 Content-Type Based Routing
frontend http_front
bind *:80
mode http
acl is_api path_beg /api
acl is_grpc hdr(Content-Type) -i application/grpc
acl is_json hdr(Content-Type) -m sub application/json
acl is_graphql path /graphql
use_backend grpc_servers if is_grpc
use_backend graphql_servers if is_graphql
use_backend api_servers if is_api is_json
default_backend web_servers
5. Query String and Cookie-Based Routing
5.1 Query Parameter Routing
frontend http_front
bind *:80
mode http
# Route by query parameter: ?env=staging
acl is_staging_param url_param(env) -i staging
acl is_debug_param url_param(debug) -i true
use_backend staging_servers if is_staging_param
# Add debug header if debug mode requested
http-request set-header X-Debug-Mode true if is_debug_param
default_backend web_servers
5.2 Cookie-Based Routing
frontend http_front
bind *:80
mode http
# Route based on a/b testing cookie
acl is_variant_b cook(ab_test) -i variant_b
acl is_beta_user cook(beta) -m found
use_backend variant_b_servers if is_variant_b
use_backend beta_servers if is_beta_user
default_backend web_servers
6. Source IP and Geographic Routing
6.1 Source IP Allowlisting
# /etc/haproxy/lists/admin-ips.lst
10.0.0.0/8
172.16.0.0/12
192.168.0.0/16
203.0.113.45/32
frontend http_front
bind *:80
mode http
acl is_admin_path path_beg /admin
acl is_allowed_ip src -f /etc/haproxy/lists/admin-ips.lst
# Block admin access from non-allowed IPs
http-request deny deny_status 403 if is_admin_path !is_allowed_ip
default_backend web_servers
6.2 GeoIP-Based Routing with Map Files
If you use a GeoIP Lua script or the
req.hdr(CF-IPCountry)header from a CDN:
# /etc/haproxy/maps/country-to-backend.map
US us_servers
CA us_servers
GB eu_servers
DE eu_servers
FR eu_servers
JP apac_servers
AU apac_servers
frontend http_front
bind *:80
mode http
# Assuming CDN sets CF-IPCountry header
use_backend %[req.hdr(CF-IPCountry),upper,map(/etc/haproxy/maps/country-to-backend.map,us_servers)]
7. Combining ACLs: AND, OR, and NOT Logic
7.1 Logical Operators
# AND — all conditions must be true (space-separated)
use_backend admin_servers if is_admin_path is_allowed_ip is_read_method
# OR — any condition can be true (|| operator)
use_backend static_servers if is_image || is_document || is_static
# NOT — negate with !
http-request deny if is_admin_path !is_allowed_ip
# Complex combination
# (is_api AND is_write_method) AND (is_allowed_ip OR is_internal_token)
use_backend api_write if is_api is_write_method { is_allowed_ip || is_internal }
7.2 Practical Example: Multi-Condition Routing
frontend https_front
bind *:443 ssl crt /etc/haproxy/certs/ alpn h2,http/1.1
mode http
# ACL definitions
acl host_api hdr(host) -i api.example.com
acl is_v2 path_beg /v2
acl is_post method POST
acl is_large_body req.body_len gt 1048576
acl is_json hdr(Content-Type) -m sub application/json
acl office_hours http-date(req.date) -m str "Mon"-"Fri"
# Deny large POST bodies that aren't JSON
http-request deny deny_status 413 if host_api is_post is_large_body !is_json
# Route API v2 POST to write cluster
use_backend api_v2_write if host_api is_v2 is_post
# Route API v2 reads to read replicas
use_backend api_v2_read if host_api is_v2
# All other API traffic
use_backend api_v1_servers if host_api
default_backend web_servers
8. Redirects and Rewrites with ACLs
8.1 HTTP to HTTPS Redirect
frontend http_front
bind *:80
mode http
# Allow ACME challenge through
acl is_acme path_beg /.well-known/acme-challenge/
use_backend acme_backend if is_acme
# Redirect everything else to HTTPS
http-request redirect scheme https code 301 unless is_acme
8.2 www to non-www Redirect
frontend https_front
bind *:443 ssl crt /etc/haproxy/certs/ alpn h2,http/1.1
mode http
acl host_www hdr_beg(host) -i www.
http-request redirect prefix https://example.com code 301 if host_www
8.3 Trailing Slash Normalisation
frontend https_front
bind *:443 ssl crt /etc/haproxy/certs/ alpn h2,http/1.1
mode http
# Add trailing slash if path has no extension and doesn't end with /
acl no_trailing_slash path_reg ^/[^.]+[^/]$
http-request redirect code 301 location %[url,regsub(^([^?]*[^/])(\?.*)?$,\1/\2,)] if no_trailing_slash
8.4 Maintenance Mode
frontend https_front
bind *:443 ssl crt /etc/haproxy/certs/ alpn h2,http/1.1
mode http
# Enable maintenance mode by creating the file
acl maintenance_mode nbsrv(web_servers) lt 1
acl is_allowed_ip src -f /etc/haproxy/lists/admin-ips.lst
acl is_health path /health
# Allow admins and health checks through
http-request deny deny_status 503 if maintenance_mode !is_allowed_ip !is_health
default_backend web_servers
9. Advanced Map-Based Routing
9.1 Combined Host + Path Map
# /etc/haproxy/maps/host-path-backend.map
api.example.com/v1 api_v1_servers
api.example.com/v2 api_v2_servers
www.example.com/blog blog_servers
www.example.com/shop shop_servers
frontend https_front
bind *:443 ssl crt /etc/haproxy/certs/ alpn h2,http/1.1
mode http
# Concatenate host and path_beg for map lookup
http-request set-var(txn.host_path) req.hdr(host),lower,concat(,path),map_beg(/etc/haproxy/maps/host-path-backend.map)
use_backend %[var(txn.host_path)] if { var(txn.host_path) -m found }
default_backend web_servers
9.2 A/B Testing with Weighted Map
frontend https_front
bind *:443 ssl crt /etc/haproxy/certs/ alpn h2,http/1.1
mode http
acl is_landing path /
# Assign 20% of landing page traffic to variant B
# Use a random value 0-99 stored in a variable
http-request set-var(txn.rand) rand,mod(100)
acl is_variant_b var(txn.rand) -m int lt 20
use_backend landing_variant_b if is_landing is_variant_b
use_backend landing_variant_a if is_landing
default_backend web_servers
backend landing_variant_a
mode http
http-response add-header Set-Cookie "ab_test=variant_a; Path=/; Max-Age=86400"
server va1 10.0.20.10:80 check
backend landing_variant_b
mode http
http-response add-header Set-Cookie "ab_test=variant_b; Path=/; Max-Age=86400"
server vb1 10.0.21.10:80 check
10. Request Sanitisation and Security ACLs
10.1 Blocking Malicious Paths
# /etc/haproxy/lists/blocked-paths.lst
/.env
/wp-login.php
/wp-admin
/xmlrpc.php
/phpmyadmin
/actuator
/.git
/config.json
/.aws
frontend https_front
bind *:443 ssl crt /etc/haproxy/certs/ alpn h2,http/1.1
mode http
# Block known attack paths
acl is_blocked_path path_beg -i -f /etc/haproxy/lists/blocked-paths.lst
# Block path traversal attempts
acl has_path_traversal path_sub ..
# Block suspiciously long URLs (potential buffer overflow)
acl url_too_long url_len gt 8192
# Block requests with null bytes
acl has_null_byte path_sub %00
# Block common SQL injection patterns in query string
acl sql_injection query -m reg -i (union.*select|insert.*into|drop.*table|;\s*--|/\*.*\*/)
http-request deny deny_status 403 if is_blocked_path
http-request deny deny_status 400 if has_path_traversal
http-request deny deny_status 414 if url_too_long
http-request deny deny_status 400 if has_null_byte
http-request deny deny_status 403 if sql_injection
# Log denied requests
http-request set-var(txn.denied) str(1) if is_blocked_path || has_path_traversal || url_too_long || has_null_byte || sql_injection
default_backend web_servers
10.2 Rate-Limited Endpoint Protection
frontend https_front
bind *:443 ssl crt /etc/haproxy/certs/ alpn h2,http/1.1
mode http
# Sensitive endpoints ACLs
acl is_login path_beg /login /auth/token
acl is_signup path_beg /signup /register
# Use stick table to track per-IP rate on login
stick-table type ipv6 size 100k expire 60s store http_req_rate(60s)
http-request track-sc0 src if is_login
# Deny if more than 10 login attempts per minute
acl login_rate_exceeded sc_http_req_rate(0) gt 10
http-request deny deny_status 429 if is_login login_rate_exceeded
default_backend web_servers
11. Debugging and Validating ACLs
11.1 Configuration Validation
# Always validate before reloading
sudo haproxy -c -f /etc/haproxy/haproxy.cfg
# Expected output:
# Configuration file is valid
11.2 Debug Logging with ACL Variables
frontend https_front
bind *:443 ssl crt /etc/haproxy/certs/ alpn h2,http/1.1
mode http
# Capture headers for logging
http-request capture req.hdr(Host) len 64
http-request capture req.hdr(User-Agent) len 128
# Store matched backend name in variable for logging
acl is_api path_beg /api
http-request set-var(txn.route) str(api) if is_api
http-request set-var(txn.route) str(web) unless is_api
# Custom log format showing route decision
log-format "%ci:%cp [%tr] %ft %b/%s %TR/%Tw/%Tc/%Tr/%Ta %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs route=%[var(txn.route)] %{+Q}r"
use_backend api_servers if is_api
default_backend web_servers
11.3 Runtime ACL Testing
# Show current ACLs in a frontend
echo "show acl" | socat stdio /var/run/haproxy/admin.sock
# Show map entries
echo "show map /etc/haproxy/maps/domain-to-backend.map" | socat stdio /var/run/haproxy/admin.sock
# Test a specific lookup against a map
echo "get map /etc/haproxy/maps/domain-to-backend.map api.example.com" | socat stdio /var/run/haproxy/admin.sock
11.4 Testing with curl
# Test path-based routing
curl -v http://localhost/api/v1/users
curl -v http://localhost/static/style.css
# Test host-based routing
curl -v -H "Host: api.example.com" http://localhost/v1/users
curl -v -H "Host: blog.example.com" http://localhost/
# Test header-based routing
curl -v -H "X-Canary: true" http://localhost/api/test
curl -v -H "Content-Type: application/json" -X POST -d '{"test":1}' http://localhost/api/data
# Test cookie-based routing
curl -v -b "ab_test=variant_b" http://localhost/
# Test denied paths
curl -v http://localhost/.env
curl -v http://localhost/../../etc/passwd
12. Complete Production Configuration
Here is a comprehensive HAProxy configuration combining all the techniques discussed:
global
log /dev/log local0
log /dev/log local1 notice
chroot /var/lib/haproxy
stats socket /var/run/haproxy/admin.sock mode 660 level admin
stats timeout 30s
user haproxy
group haproxy
daemon
maxconn 50000
ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
ssl-default-bind-options prefer-client-ciphers no-sslv3 no-tlsv10 no-tlsv11
tune.ssl.default-dh-param 2048
defaults
log global
mode http
option httplog
option dontlognull
option forwardfor
option http-server-close
timeout connect 5s
timeout client 30s
timeout server 30s
timeout http-request 10s
timeout http-keep-alive 5s
errorfile 400 /etc/haproxy/errors/400.http
errorfile 403 /etc/haproxy/errors/403.http
errorfile 408 /etc/haproxy/errors/408.http
errorfile 500 /etc/haproxy/errors/500.http
errorfile 502 /etc/haproxy/errors/502.http
errorfile 503 /etc/haproxy/errors/503.http
errorfile 504 /etc/haproxy/errors/504.http
frontend http_redirect
bind *:80
mode http
acl is_acme path_beg /.well-known/acme-challenge/
use_backend acme_backend if is_acme
http-request redirect scheme https code 301 unless is_acme
frontend https_main
bind *:443 ssl crt /etc/haproxy/certs/ alpn h2,http/1.1
mode http
# --- Request ID and Forwarding ---
http-request set-header X-Request-ID %[uuid()]
http-request set-header X-Forwarded-Proto https
http-request set-header X-Real-IP %[src]
http-request del-header Proxy
# --- Security ACLs ---
acl is_blocked_path path_beg -i -f /etc/haproxy/lists/blocked-paths.lst
acl has_path_traversal path_sub ..
acl url_too_long url_len gt 8192
http-request deny deny_status 403 if is_blocked_path
http-request deny deny_status 400 if has_path_traversal
http-request deny deny_status 414 if url_too_long
# --- Host ACLs ---
acl host_www hdr(host) -i www.example.com example.com
acl host_api hdr(host) -i api.example.com
acl host_blog hdr(host) -i blog.example.com
acl host_admin hdr(host) -i admin.example.com
# --- Path ACLs ---
acl is_api_v1 path_beg /api/v1
acl is_api_v2 path_beg /api/v2
acl is_static path_beg /static /assets
acl is_health path /health /ready
acl is_ws path_beg /ws
# --- Method ACLs ---
acl is_write method POST PUT PATCH DELETE
# --- Admin protection ---
acl is_allowed_admin src -f /etc/haproxy/lists/admin-ips.lst
http-request deny deny_status 403 if host_admin !is_allowed_admin
# --- Canary header ---
acl is_canary hdr(X-Canary) -i true
# --- www redirect ---
acl host_www_prefix hdr_beg(host) -i www.
http-request redirect prefix https://example.com code 301 if host_www_prefix
# --- Routing rules (order matters: most specific first) ---
use_backend health_check if is_health
use_backend websocket_servers if host_api is_ws
use_backend api_v2_write if host_api is_api_v2 is_write
use_backend api_v2_canary if host_api is_api_v2 is_canary
use_backend api_v2_read if host_api is_api_v2
use_backend api_v1_servers if host_api is_api_v1
use_backend api_v1_servers if host_api
use_backend blog_servers if host_blog
use_backend admin_servers if host_admin
use_backend static_servers if is_static
default_backend web_servers
# --- Response hardening ---
http-response del-header Server
http-response del-header X-Powered-By
http-response set-header X-Content-Type-Options nosniff
http-response set-header X-Frame-Options SAMEORIGIN
# --- Backends ---
backend health_check
mode http
http-request return status 200 content-type text/plain string "OK"
backend web_servers
mode http
balance roundrobin
option httpchk GET /health
http-check expect status 200
server web1 10.0.1.10:80 check inter 5s fall 3 rise 2
server web2 10.0.1.11:80 check inter 5s fall 3 rise 2
backend api_v1_servers
mode http
balance leastconn
option httpchk GET /api/v1/ping
http-check expect status 200
server apiv1a 10.0.2.10:8080 check inter 3s fall 3 rise 2
server apiv1b 10.0.2.11:8080 check inter 3s fall 3 rise 2
backend api_v2_read
mode http
balance roundrobin
option httpchk GET /api/v2/ping
http-check expect status 200
server apiv2r1 10.0.3.10:8080 check inter 3s fall 3 rise 2
server apiv2r2 10.0.3.11:8080 check inter 3s fall 3 rise 2
server apiv2r3 10.0.3.12:8080 check inter 3s fall 3 rise 2
backend api_v2_write
mode http
balance leastconn
option httpchk GET /api/v2/ping
http-check expect status 200
server apiv2w1 10.0.4.10:8080 check inter 3s fall 3 rise 2
server apiv2w2 10.0.4.11:8080 check inter 3s fall 3 rise 2
backend api_v2_canary
mode http
balance roundrobin
server canary1 10.0.5.10:8080 check inter 3s fall 3 rise 2
backend blog_servers
mode http
balance roundrobin
server blog1 10.0.6.10:80 check
server blog2 10.0.6.11:80 check
backend admin_servers
mode http
balance roundrobin
server admin1 10.0.7.10:8443 check ssl verify none
backend static_servers
mode http
balance roundrobin
http-response set-header Cache-Control "public, max-age=31536000, immutable"
server static1 10.0.8.10:80 check
server static2 10.0.8.11:80 check
backend websocket_servers
mode http
balance source
timeout tunnel 3600s
timeout server 3600s
server ws1 10.0.9.10:8081 check
server ws2 10.0.9.11:8081 check
backend acme_backend
mode http
server acme 127.0.0.1:8888
13. Performance Considerations
- ACL evaluation order — HAProxy evaluates
use_backend
directives top-to-bottom and stops at the first match. Place the most frequent routes first to minimise evaluation overhead. - Map files vs inline ACLs — For more than 20 entries, use
map
or-f
file-based ACLs. Map lookups are O(1) hash lookups; long inline ACL value lists are scanned linearly. - Regex ACLs —
path_reg
is significantly slower thanpath_beg
orpath_end
. Avoid regex when a prefix or suffix match suffices. - Variable caching — Use
set-var(txn.xxx)
to store expensive fetch results and reference them multiple times rather than re-evaluating. - Stick table memory — Each stick table entry consumes memory. Size tables appropriately and set
expire
values to prevent unbounded growth.
