# Session affinity ("sticky sessions")?

**URL:** <https://community.fly.io/t/session-affinity-sticky-sessions/638>\
**Category:** General\
**Created:** [January 26, 2021, 8:00pm UTC](https://community.fly.io/t/session-affinity-sticky-sessions/638 "2021-01-26T20:00:30Z")\
**Posts on this page:** 20\
**Page:** 2

<div class="post-metadata">

**Author:** ![luke](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/luke/32/304_2.png) [@luke](https://community.fly.io/u/luke)\
**Post date:** [January 27, 2021, 10:55pm UTC](https://community.fly.io/t/session-affinity-sticky-sessions/638/21 "2021-01-27T22:55:46Z")

</div>

> [@kurt](#):
>
> Run a single app instance per region

How can I do this? How do I prevent instances of the same app from being started in the same region? I am less concerned about tying each instance to a particular region and more with ensuring two instances of a given app don’t share a region…

---

<div class="post-metadata">

**Author:** ![kurt](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/kurt/32/43757_2.png) [@kurt](https://community.fly.io/u/kurt)\
**Post date:** [January 28, 2021, 1:54am UTC](https://community.fly.io/t/session-affinity-sticky-sessions/638/22 "2021-01-28T01:54:49Z")

</div>

When you add multiple regions, we spread instances out as much as possible. If you add, say, 5 regions and then run 4 instances, you should always get one per region on a deploy.

You can get really tight control over regions by adding volumes, if you need to. That would prevent a second instance from _ever_ running in the same region.

---

<div class="post-metadata">

**Author:** ![luke](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/luke/32/304_2.png) [@luke](https://community.fly.io/u/luke)\
**Post date:** [January 28, 2021, 3:37am UTC](https://community.fly.io/t/session-affinity-sticky-sessions/638/23 "2021-01-28T03:37:00Z")

</div>

Excellent! I’ll make sure I have more regions added than running instances.

I’m so pleased that everything is working out and I found my new app hosting platform! 😁

---

<div class="post-metadata">

**Author:** ![OldhamMade](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/oldhammade/32/40954_2.png) [@OldhamMade](https://community.fly.io/u/OldhamMade)\
**Post date:** [October 20, 2021, 12:20pm UTC](https://community.fly.io/t/session-affinity-sticky-sessions/638/24 "2021-10-20T12:20:36Z")

</div>

Hey, has there been any movement on either session or IP affinity since this post? I’m considering some changes to one of my apps and some kind of request affinity would really help. I often run more app instances than there are regions (often 25 or 30 containers) so regional affinity wouldn’t work for me.

No worries if no work has been done here yet! It’s useful to know either way so I can change my approach as necessary.

Thanks!

---

<div class="post-metadata">

**Author:** ![kurt](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/kurt/32/43757_2.png) [@kurt](https://community.fly.io/u/kurt)\
**Post date:** [October 20, 2021, 9:09pm UTC](https://community.fly.io/t/session-affinity-sticky-sessions/638/25 "2021-10-20T21:09:02Z")

</div>

We haven’t done anything here yet! You can likely do this yourself with two apps:

1. Haproxy or nginx with session affinity configured
2. App instances listening on 6pn

Haproxy makes it very easy to configure load balancing across `<region>.<appname>.internal`, we use this for our postgres clusters: [postgres-ha/haproxy.cfg at main · fly-apps/postgres-ha · GitHub](https://github.com/fly-apps/postgres-ha/blob/main/config/haproxy.cfg#L32-L37)

---

<div class="post-metadata">

**Author:** ![austincollinpena](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/austincollinpena/32/1560_2.png) [@austincollinpena](https://community.fly.io/u/austincollinpena)\
**Post date:** [November 5, 2021, 5:24pm UTC](https://community.fly.io/t/session-affinity-sticky-sessions/638/27 "2021-11-05T17:24:42Z")

</div>

`--max-per-region` is a neat [command shared with me](https://community.fly.io/t/how-to-specify-regions-to-run-in/3048/2) for future readers.

Full command looks like `fly scale count 6 --max-per-region 1`

---

<div class="post-metadata">

**Author:** ![OldhamMade](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/oldhammade/32/40954_2.png) [@OldhamMade](https://community.fly.io/u/OldhamMade)\
**Post date:** [September 21, 2022, 5:58am UTC](https://community.fly.io/t/session-affinity-sticky-sessions/638/28 "2022-09-21T05:58:34Z")

</div>

Sorry to bring up an old thread, but I was wondering whether any further work had been done to enable Session Affinity within Fly? I’m sure a number of your customers (including me!) would find this particularly useful. Even a “soft” implementation would be of great help (not guaranteed, but highly likely). Thanks!

(cc @kurt)

---

<div class="post-metadata">

**Author:** ![ignoramous](https://avatars.discourse-cdn.com/v4/letter/i/a9adbd/32.png) [@ignoramous](https://community.fly.io/u/ignoramous)\
**Post date:** [September 21, 2022, 9:13pm UTC](https://community.fly.io/t/session-affinity-sticky-sessions/638/29 "2022-09-21T21:13:55Z")

</div>

> [@OldhamMade](#):
>
> Even a “soft” implementation would be of great help (not guaranteed, but highly likely)

Kurt has previously written about achieving “sticky sessions” with Nginx’s hash-based load balancing here: [The 5-hour CDN · The Fly Blog](https://fly.io/blog/the-5-hour-content-delivery-network/#the-golden-cache-hit-ratio)

---

<div class="post-metadata">

**Author:** ![apitman](https://avatars.discourse-cdn.com/v4/letter/a/c5a1d2/32.png) [@apitman](https://community.fly.io/u/apitman)\
**Post date:** [October 17, 2023, 2:49pm UTC](https://community.fly.io/t/session-affinity-sticky-sessions/638/30 "2023-10-17T14:49:22Z")

</div>

I’m running into the same need. I tried the 1 machine per region approach, but requests are being load balanced across different regions, even when I use a VPN to put myself very close to a specific region. Any ideas?

---

<div class="post-metadata">

**Author:** ![andig](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/andig/32/1029_2.png) [@andig](https://community.fly.io/u/andig)\
**Post date:** [November 7, 2023, 10:27pm UTC](https://community.fly.io/t/session-affinity-sticky-sessions/638/31 "2023-11-07T22:27:00Z")

</div>

Sorry for the lame reply, but same here. It would be super handy to add a

```
handlers = http, sticky

```

to do this without private network nginx setup.

---

<div class="post-metadata">

**Author:** ![aychtang](https://avatars.discourse-cdn.com/v4/letter/a/c5a1d2/32.png) [@aychtang](https://community.fly.io/u/aychtang)\
**Post date:** [December 9, 2023, 7:43pm UTC](https://community.fly.io/t/session-affinity-sticky-sessions/638/32 "2023-12-09T19:43:10Z")

</div>

would also love this feature for session affinity, we would be able to launch some features much sooner if it were available (and speed of building is why we love using fly!)

---

<div class="post-metadata">

**Author:** ![echoi](https://avatars.discourse-cdn.com/v4/letter/e/77aa72/32.png) [@echoi](https://community.fly.io/u/echoi)\
**Post date:** [January 4, 2024, 8:57am UTC](https://community.fly.io/t/session-affinity-sticky-sessions/638/33 "2024-01-04T08:57:54Z")

</div>

Any useful materials around this need? I’m also considering setting up private load balancer between my machines but I have no idea where to start.

---

<div class="post-metadata">

**Author:** ![mpnsk](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/mpnsk/32/17372_2.png) [@mpnsk](https://community.fly.io/u/mpnsk)\
**Post date:** [January 6, 2024, 1:19pm UTC](https://community.fly.io/t/session-affinity-sticky-sessions/638/34 "2024-01-06T13:19:17Z")

</div>

Something that is not in the docs but what I could figure out searching this forum:  
You can use the request header `fly-force-instance-id` to make the router pick a specific instance (even though load balancing would suggest another?).

This has the caveat that if the instance doesn’t respond the router doesn’t bother further and the request will just be dropped. And it needs to be a http-based / websocket protocol for the router to look at the headers in the first place.

But with this it should be easy to let a web-frontend hold a session with a process running on a specific machine.

---

<div class="post-metadata">

**Author:** ![andig](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/andig/32/1029_2.png) [@andig](https://community.fly.io/u/andig)\
**Post date:** [July 18, 2024, 7:45pm UTC](https://community.fly.io/t/session-affinity-sticky-sessions/638/35 "2024-07-18T19:45:59Z")

</div>

Seems this wasn’t mentioned before (and I surely didn’t find it) but it’s in the docs: [Session Affinity (a.k.a. Sticky Sessions) · Fly Docs](https://fly.io/docs/blueprints/sticky-sessions/)

---

<div class="post-metadata">

**Author:** ![andig](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/andig/32/1029_2.png) [@andig](https://community.fly.io/u/andig)\
**Post date:** [July 18, 2024, 8:36pm UTC](https://community.fly.io/t/session-affinity-sticky-sessions/638/36 "2024-07-18T20:36:10Z")

</div>

Fwiw, here’s a simple sticky handler in Golang: [Go fly.io sticky session handler · GitHub](https://gist.github.com/andig/8a0a3e1142e98eae8e456b8c03f96d1c)

---

<div class="post-metadata">

**Author:** ![rubys](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/rubys/32/16907_2.png) [@rubys](https://community.fly.io/u/rubys)\
**Post date:** [July 18, 2024, 10:19pm UTC](https://community.fly.io/t/session-affinity-sticky-sessions/638/37 "2024-07-18T22:19:04Z")

</div>

@andig Can I have your permission to add that example to the blueprint?

---

<div class="post-metadata">

**Author:** ![andig](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/andig/32/1029_2.png) [@andig](https://community.fly.io/u/andig)\
**Post date:** [July 19, 2024, 5:26am UTC](https://community.fly.io/t/session-affinity-sticky-sessions/638/38 "2024-07-19T05:26:19Z")

</div>

Yes, sure 👍🏻

---

<div class="post-metadata">

**Author:** ![andig](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/andig/32/1029_2.png) [@andig](https://community.fly.io/u/andig)\
**Post date:** [July 20, 2024, 10:08am UTC](https://community.fly.io/t/session-affinity-sticky-sessions/638/39 "2024-07-20T10:08:41Z")

</div>

One thing I’m not sure about and that isn’t mentioned in the docs is how a non-existing machine is handled:

> If the cookie does not match the environment variable, then a response containing a Fly-Replay header is created. This will cause the [Fly.io](http://Fly.io) proxy to replay the request to the desired machine.

What happens if I `fly-replay` to redirect to the sticky machine but that machine does no longer exist? It would be helpful if the Fly proxy was able to add a cookie that shows that to allow client application to start a new session. Maybe something like `fly-replay: invalid` or similar?

@rubys would you know what happens/ how to handle this situation?

---

<div class="post-metadata">

**Author:** ![rubys](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/rubys/32/16907_2.png) [@rubys](https://community.fly.io/u/rubys)\
**Post date:** [July 20, 2024, 12:47pm UTC](https://community.fly.io/t/session-affinity-sticky-sessions/638/40 "2024-07-20T12:47:26Z")

</div>

There are people looking into making the proxy more useful - I’m focused on frameworks and deployments; but I also happen to be a user of [fly.io](http://fly.io).

If the machine is merely stopped, the proxy will restart the machine and then route the request to it.

If the machine no longer exists, the request will fail after about a minute. If your application knows that the machine is no longer there, it can delete or reset the cookie rather than replying with a Fly-Replay response header.

---

<div class="post-metadata">

**Author:** ![andig](https://sea1.discourse-cdn.com/fly1/user_avatar/community.fly.io/andig/32/1029_2.png) [@andig](https://community.fly.io/u/andig)\
**Post date:** [July 27, 2024, 11:29am UTC](https://community.fly.io/t/session-affinity-sticky-sessions/638/41 "2024-07-27T11:29:44Z")

</div>

> There are people looking into making the proxy more useful

@rubys that’s great to know! It would be nice if it were possible to join the discussion if there’s a public thread?

> If the machine no longer exists, the request will fail after about a minute.

Thought so. At this time unfortunately, a (web) client would continue sending the outdated header.

> If your application knows that the machine is no longer there, it can delete or reset the cookie rather than replying with a Fly-Replay response header.

Thats an option but it does imho limit the purpose of `fly-replay`. If I need to track internal services (Consul…) I can just as well talk to the required backend service directly. The nice part of `fly-replay` is that the proxy already knows which machines are available (assumption). It would be nice- using the current approach- if we could instruct it which header to clean if the target machine is gone. Something like:

```
fly-replay: <past-machine-id>
fly-replay-clear: fly-machine-id # your header name here

```

[Previous page](https://community.fly.io/t/session-affinity-sticky-sessions/638.md?page=1)

[Next page](https://community.fly.io/t/session-affinity-sticky-sessions/638.md?page=3)
