Here’s a trick question that quietly decides whether a cluster is real or just for show. If your load balancer sends you to a different machine on every single click, what happens to your session — your login, your cart, your half-filled form? If the answer is “you get logged out,” then I’m sorry to tell you that you don’t actually have a cluster. You have three separate websites standing on each other’s shoulders wearing a long trench coat, hoping nobody notices. Making a session follow the visitor is the single thing that turns three nodes into one system.
The quiet problem with local state
By default, PHP does something that feels perfectly innocent: it stores each visitor’s session on the local disk of whichever server happened to handle the request. On a single machine, that’s flawless. It’s fast, it’s simple, it just works. But spread across many machines it becomes quietly fatal. Node A took your login and wrote it down. Nodes B and C? They’ve genuinely never heard of you. You’re a stranger to two-thirds of your own cluster.
And this is the deeper lesson, the one worth carrying to other systems entirely: as long as any part of handling a request depends on state that lives on one specific node, the load balancer’s beautiful freedom to send you anywhere stops being a feature and turns into a liability. Flexibility upstream demands statelessness downstream. You can’t have one without the other.
Get the state off the node entirely
So the fix isn’t to make the nodes share their disks or gossip about who logged in where. The fix is cleaner and a little bolder: stop storing session state on any node at all. Every replica gets pointed at one shared Redis, and PHP is told to keep its sessions there instead of on local disk. Now your session doesn’t belong to node A, or B, or C. It belongs to the cluster. Whichever replica the balancer hands your next request to, that replica looks your session up in the same shared Redis and finds precisely what the previous one wrote a moment ago.
The web tier becomes stateless — and statelessness is the magic property, the one that quietly makes horizontal scaling possible in the first place. When no replica is holding anything precious that the others lack, adding capacity stops being an anxious surgery and becomes trivial: you just add another interchangeable replica and walk away. They’re all the same. None of them is special. That’s the whole point.
Watching it actually happen
Now, I could just draw you a diagram and swear it’s true. But this isn’t a hope we sketched on a whiteboard — it’s a behavior we sat and watched with our own eyes. During testing we took a single session and incremented its counter across a run of requests, while the proxy was deliberately, mischievously bouncing that session from node to node between each one. And the counter climbed, clean as anything: 1, 2, 3, 4, 5, 6. Every step of the way. Except here’s the kicker — each of those increments was served by a different node, under the same session id. The state never skipped a beat.
The visitor, if there had been a real one, would never have felt a thing. They’d never have known they’d been quietly shuffled between three physical machines mid-visit — and that obliviousness is exactly the goal. Session migration is invisible when it works, and its invisibility is the feature. You roam freely across the cluster, and your session simply… comes along for the ride, like it was never anywhere else.