skip to content

An HAProxy backend has `cookie SRVID insert indirect nocache` plus `server s1 10.0.0.11:8080 check cookie s1`. What does HAProxy add to the traffic, and what do the `indirect` and `nocache` keywords each change?

level: middleimportance: must knowfreq 60%

answer

  1. HAProxy writes its own Set-Cookie
  2. insert versus prefix versus rewrite
  3. the app never sees the cookie
  4. shared cache could replay Set-Cookie
  5. server line must carry a cookie value

basics

~20 s

HAProxy adds Set-Cookie: SRVID=s1 to the first response so later requests carrying that cookie go back to s1. indirect strips the cookie before forwarding to the server and skips insertion when the client already sent a valid one; nocache marks the response private so shared caches cannot store it.

solid answer

~50 s

With `insert`, HAProxy generates its own persistence cookie: when a request arrives without a valid `SRVID`, the balance algorithm picks a server, and HAProxy appends `Set-Cookie: SRVID=s1` to that server's response using the value from the server line. On later requests the client sends `Cookie: SRVID=s1`, HAProxy maps that value to the server and skips balancing. `indirect` makes the cookie invisible to the application — HAProxy removes it from the request before proxying, and does not re-insert it when the request already carried a valid one. `nocache` adds `Cache-control: private` to responses that carry the inserted cookie, so a shared cache in front of HAProxy cannot store that response and hand one server's persistence cookie to every other client. The alternatives are `prefix` and `rewrite`, which piggyback on a cookie the application already sets instead of adding a new one.

code

ini · 5 lines
ini
backend app
    balance roundrobin
    cookie SRVID insert indirect nocache
    server s1 10.0.0.11:8080 check cookie s1
    server s2 10.0.0.12:8080 check cookie s2

go deeper

for a junior

Know that HAProxy can add its own cookie naming the chosen server, and that the client sending it back is what pins the session. Be able to point at the cookie value on each server line.

for a middle

Explain both halves of indirect — stripping the cookie from the request and suppressing repeated insertion — and say precisely what nocache protects against in a shared cache.

for a senior

Argue when cookie persistence beats a stick table: it is stateless across proxy nodes, survives NAT and CDN egress, and needs no peers replication. Mention maxidle/maxlife for stale pins.

for a principal

Take a position on whether any persistence should exist at all: pinning users to servers constrains autoscaling and deploys, so decide when the proxy carries that cost and when the fix is externalised session state, and standardise the cookie's naming and lifetime across the estate.

## The three modes HAProxy's `cookie` directive has three mutually exclusive modes, and picking the right one is most of the question: - `insert` — HAProxy creates its own cookie. The application knows nothing about it. - `prefix` — the application already sets a session cookie (say `JSESSIONID`), and HAProxy prepends the server id plus a delimiter to its value, stripping the prefix back off before the request reaches the server. Useful when you cannot afford a second cookie. - `rewrite` — the application sets the cookie and HAProxy overwrites its value with the server id. This requires the application to always emit the cookie, so it is the most fragile of the three. A server participates only if its `server` line carries `cookie <value>`; a server without one can never be selected by persistence. ``` backend app balance roundrobin cookie SRVID insert indirect nocache server s1 10.0.0.11:8080 check cookie s1 server s2 10.0.0.12:8080 check cookie s2 ``` ## What happens request by request First request, no `SRVID` present: HAProxy balances normally and picks, say, `s2`. On the way back it appends `Set-Cookie: SRVID=s2; path=/` to the response. Second request: the browser sends `Cookie: SRVID=s2`, HAProxy resolves `s2` to that server and proxies straight to it, bypassing `balance roundrobin` entirely. Persistence always outranks the balancing algorithm when it has a valid answer. ## `indirect` Two effects, and candidates usually remember only one. First, HAProxy removes the persistence cookie from the request before forwarding, so the backend application never sees a cookie it did not set — no risk of it choking on an unknown name or echoing it back. Second, HAProxy does not re-insert `Set-Cookie` on responses to requests that already carried a valid cookie, which keeps the header off every single response instead of only the first. ## `nocache` This is the subtle one, and it is a genuine production incident when it is missing. If a response carrying `Set-Cookie: SRVID=s1` has no cache-control of its own and a shared cache sits in front of HAProxy, that cache may store the response including the header and replay it to everybody. Every client then arrives holding `SRVID=s1`, and one server takes the entire load while the others idle. `nocache` avoids this by adding `Cache-control: private` to responses in which a cookie was inserted and no cache directive was already set. ## Cookie persistence versus a stick table HAProxy's documentation distinguishes *persistence* — the client carries the routing decision — from *stickiness* — HAProxy remembers it in a stick table. The practical differences: - **Key.** The cookie is carried by the client, so users sharing a NAT or a CDN egress address still get individual pins. `stick on src` keys on the connection address and collapses them. - **State.** Cookie persistence is stateless in HAProxy: any node can decode `SRVID=s1`, so a fleet of proxies needs no shared table and no replication. A stick table is per-process and needs a `peers` section to be shared. - **Reach.** A cookie exists only in HTTP mode. For a TCP-mode frontend, or for non-browser clients that discard cookies, a stick table on some other key is the only option. ## Lifetime and predictability Without further options the inserted cookie is a session cookie: it disappears when the browser closes. `maxidle` and `maxlife` add a timestamp to the value so HAProxy can ignore a cookie that is too old or idle, which stops a client returning after days from being pinned to a server that no longer exists. `postonly` restricts insertion to responses to POST requests, and `dynamic` derives the value by hashing the server rather than exposing your chosen name. One last consideration: the raw value in `cookie s1` leaks a piece of your topology to anyone who looks at their cookie jar. It is not a secret, but if that bothers you, `dynamic` with a configured key produces an opaque value instead. ## When the server is gone If the cookie names a server that is now down, the persistence choice cannot be honoured and HAProxy falls back to balancing — the client keeps its stale cookie until a fresh insertion replaces it. Nothing about persistence preserves the session data that lived on the failed server, which is the standing argument for keeping session state outside the application process.

  • Why would you choose `prefix` over `insert`?
    `prefix` reuses a cookie the application already sets, such as `JSESSIONID`, by prepending the server id to its value and stripping it back off before proxying. That avoids adding a second cookie — useful where header size, a strict cookie policy, or a client that only tolerates known cookies makes an extra one unwelcome.
  • What do `maxidle` and `maxlife` add to an inserted cookie?
    They embed a timestamp in the cookie value so HAProxy can ignore it once the client has been idle too long, or once the cookie is simply too old. Without them an inserted session cookie is honoured indefinitely, so a client returning days later can be pinned to a server that has since been replaced.
  • Which is a better fit behind a CDN — cookie persistence or `stick on src`?
    Cookie persistence. Behind a CDN the source address HAProxy sees is the CDN's egress node, so `stick on src` collapses thousands of users onto a handful of entries and a handful of servers. A cookie is carried per client, so each user is pinned individually and no shared table is needed across proxy nodes.

saying these in an interview costs you the question

  • Thinking the backend application reads the SRVID cookie
  • Believing nocache stops the browser storing the cookie
  • Forgetting the server lines need their own cookie value
  • Assuming persistence keeps working when the server is down
  • Confusing insert with rewrite on an app-set cookie

context