keepcalculator

06 Numbers and Powers

HAProxy Session Persistence Across Servers

Card No. 06·51067 · Updated · Standard formula, shown below

This guide explains how to configure HAProxy to maintain session persistence (also called sticky sessions) across multiple backend servers. With persistence, a client’s requests are always routed to the same server for the duration of a session, which is essential for applications that store session state locally (e.g., shopping carts, login tokens, or in-memory caches). You’ll learn the three main methods—source IP affinity, cookie-based stickiness, and session ID tracking—and how to implement them in your HAProxy configuration.

What You’ll Need

  • A working HAProxy installation (version 1.5 or newer recommended).
  • Access to the HAProxy configuration file (usually /etc/haproxy/haproxy.cfg).
  • Basic familiarity with HAProxy frontend and backend sections.
  • Knowledge of your application’s session mechanism (e.g., whether it uses cookies or URL parameters).

Step-by-Step

  1. Identify your session requirement. Determine whether your app needs sticky sessions at all. If your backend servers share session state (e.g., via a database or Redis), you may not need persistence. If not, choose one of the methods below.
  2. Method 1: Source IP affinity (simplest, but less reliable with NAT or proxies). In your backend section, add the balance source directive. This hashes the client’s IP address and consistently maps it to a server. Example:
    backend web_servers
        balance source
        server web1 192.168.1.10:80 check
        server web2 192.168.1.11:80 check

    This works well for internal networks but can break if clients come from a shared IP (e.g., corporate NAT).

  3. Method 2: Cookie-based stickiness (recommended for most web apps). Use HAProxy to insert a cookie that identifies the chosen server. Add the cookie directive in the backend and cookie parameter on each server line. Example:
    backend web_servers
        balance roundrobin
        cookie SERVERID insert indirect nocache
        server web1 192.168.1.10:80 cookie web1 check
        server web2 192.168.1.11:80 cookie web2 check

    The insert option makes HAProxy add a Set-Cookie header if none exists. indirect removes the cookie from the request before forwarding it to the server (so the server doesn’t see it). nocache prevents caching proxies from storing the response.

  4. Method 3: Session ID tracking (for apps that manage their own session ID). If your application already sets a session cookie (e.g., JSESSIONID for Java, PHPSESSID for PHP), you can tell HAProxy to stick on that cookie’s value. Use the stick-table and stick directives:
    backend web_servers
        balance roundrobin
        stick-table type string len 32 size 100k expire 30m
        stick on req.cook(JSESSIONID)
        server web1 192.168.1.10:80 check
        server web2 192.168.1.11:80 check

    This stores the session ID in a table and maps it to the server that first served it. The expire parameter controls how long the mapping is kept (adjust to match your session timeout).

  5. Apply and test the configuration. After editing the config, run haproxy -c -f /etc/haproxy/haproxy.cfg to validate syntax. Then reload HAProxy gracefully with systemctl reload haproxy (or service haproxy reload). Test by accessing your app from the same client and verifying that requests hit the same backend server (check server logs or use a test page that shows the server hostname).
  6. Monitor and tune. Use haproxy stats (enable the stats socket) to see stick-table usage and server hit counts. Adjust the expire time for stick-tables based on your session duration. For cookie methods, consider the maxidle and maxlife options to control cookie lifetime.

Common Mistakes

  • Using source IP behind a proxy or load balancer. If clients go through a reverse proxy (like Cloudflare) or a NAT, all requests may appear to come from the same IP, causing all traffic to stick to one server. Use cookie-based stickiness instead.
  • Forgetting indirect option. Without it, the server receives the cookie and may try to use it, potentially overriding its own session cookie. This can cause session conflicts.
  • Not setting nocache. If a caching proxy stores the response with the Set-Cookie header, it may serve the same cookie to different clients, breaking persistence.
  • Stick-table size too small. For high traffic, a small table can evict entries prematurely, causing a client to be redirected to a different server. Set a size that can hold the number of concurrent sessions.
  • Mixing persistence methods. Using both source IP and cookie simultaneously can lead to unpredictable behavior. Stick to one method unless you have a specific reason.

Tips

  • For cookie-based stickiness, use the insert option only when the client doesn’t already have the cookie. If the server sets its own cookie, use prefix or rewrite to avoid conflicts.
  • Set the expire time on stick-tables slightly longer than your session timeout to avoid premature loss of stickiness.
  • Use option httpclose or option http-server-close to ensure connections are handled correctly with cookies, especially in HTTP/1.0 scenarios.
  • Monitor the stick-table usage via the stats socket: echo "show table" | socat stdio /var/run/haproxy.sock. This helps you adjust the size.
  • If you have a maintenance window, you can drain a server by setting its weight to 0, but sticky sessions will still route to it until the stick-table expires. Use disable on the server line to stop new sessions.

Troubleshooting

  • Sessions are not sticking. Check that the cookie is actually being set by HAProxy. Use curl -I to see the response headers. If no Set-Cookie appears, verify the backend configuration and that the server is up.
  • All traffic goes to one server. This often happens with source IP stickiness behind a NAT. Switch to cookie-based stickiness. Also check if the stick-table is full—if so, increase its size.
  • Clients get a new server after a reload. HAProxy reloads clear stick-tables by default. Use the stick-table with a persistent store (e.g., peers section) to share state across reloads and multiple HAProxy instances.
  • Server receives the cookie and complains. If your app sees the HAProxy cookie and tries to use it, add indirect to the cookie directive. If the app sets its own cookie, use prefix to prepend the server name to the app’s cookie value.
  • Persistence works but only for a short time. The stick-table expire is too short. Increase it to match your session length.
  • HAProxy fails to start with an error about stick-table. Ensure the stick-table type matches the data you’re storing. For a cookie value, use type string len with a length that covers your session ID length.

Frequently Asked Questions

Can I use both source IP and cookie stickiness?

Yes, but it’s not recommended. You can use balance source as a fallback if no cookie is present, but this requires a more complex configuration. In practice, choose one method that fits your environment.

How do I know which server a client is stuck to?

Check the server logs or enable a test page that outputs the server hostname. You can also use the stats socket to see the current stick-table entries.

What happens if a server goes down?

HAProxy will route new requests to other servers. For existing sessions, the stick-table entry will eventually expire, and the client will be reassigned. If you want immediate failover, you can configure option redispatch to allow rebalancing, but this may break the session.

Does session persistence work with HTTPS?

Yes, HAProxy can insert cookies over HTTPS. Ensure you have SSL termination configured on HAProxy (or pass-through) and the cookie is set securely (use the secure option in the cookie directive).

Can I share stick-tables between multiple HAProxy instances?

Yes, using the peers section. Define a peers section and reference it in the stick-table declaration. This synchronizes stick-table entries across HAProxy nodes, enabling persistence in a multi-node HAProxy setup.

How long should the stick-table expire be?

Set it to the maximum session duration you expect. For example, if sessions last 30 minutes, set expire 30m. If you’re unsure, start with 1 hour and adjust based on usage.

Related

Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.

More cards in this drawer

The whole Numbers and Powers drawer →