Laravel session affinity

Hi there,

Is there a relatively simple way to set up session affinity for a Laravel app hosted on Fly?

At the moment each deploy kicks me out of my session. The application is in development but obviously could not launch with this behaviour as it would provide a lot of friction to users.

Thanks!

1 Like

Hey there!

There’s a few things to talk about, but the tl;dr is: I suggest spinning up a redis instance and use that for session storage.

I’m going to assume you’re using the default file-based session storage for now.

What you should do

So the issue with using file-based sessions is that files and disks are ephemeral in Fly VM’s. The file-based sessions are blown away between deployments.

Options:

:one: Use cookie-based sessions:

  • Pro: No added cost to you
  • Pro: You can spin up/load balance amongst multiple VM’s and not worry about session storage
  • Con: Cookie-based sessions have a limit in how much data they store, so use of sessions for things like flash messages or custom data may not work

This is a good option if you’re running in multiple regions, until you want to get more complicated with a central session store.

:two: Create a volume

Assuming you have one VM (volumes can only be associated with a single VM), you may want to create a small-ish volume and mount it to the session storage location (IIRC in Laravel that’s in its storage dir)

  • Pro: Retains your data, like session data
  • Con: Only in the VM you assign the volume to
  • Con: Volumes aren’t free (but are pretty cheap)

Docs on that: Persisting the Storage Folder · Fly Docs

This pins your session storage to a particular VM but will persist through deployments.

:three: My personal favorite: Use Redis

You can spin up your own Redis instance, or create a managed Redis instance.

Your own redis docs: https://fly.io/docs/laravel/the-basics/databases/#laravel-with-redis-in-fly-io

Managed redis docs: Upstash for Redis®* · Fly Docs

Redis can then be your persistent session storage. It’s simple, but some thought is needed if you’re running in multiple regions.

  • Pro: Redis is great for many things
  • Con: Gets a bit hairier in multi-region deployments
  • Con: Redis also costs money, but is pretty cheap still - session storage doesn’t need a lot of resources

Session Affinity

This is a bit of a “Well, Actually™” type statement:

I’ve seen the term “session affinity” used the most when in a load-balanced environment. In that scenario, you can’t really use file-based sessions because the session data only lives on the server where the session was created.

However, you can configure your load balancer for “sticky sessions”, so all subsequent requests from a client keep going to the same web server.

so session affinity isn’t really “save sessions on my server” so much as “keep a user going to one single VM for all their requests”.

Fly’s proxy is essentially a load balancer, but it doesn’t have that feature. You’d have to spin up your own haproxy’s, or make your own proxy and make clever use of the fly replay header.

My suggestion: Don’t worry about this particular point, although it may be important if you spin up multiple web servers in Fly.

If you have one VM per region, it’s likely (but not guaranteed) a user will always get sent to that one server. But this doesn’t solve your immediate issue for deployments.

1 Like

Cheers Chris!

Setting SESSION_DRIVER = "cookie" in the project fly.toml was enough to get this working.

Just in case it helps anyone else, flashing lang keys (rather than translated strings) can help keep the cookie nice and manageable.

For example, rather than doing:

return redirect()->back()->with('flash_message', trans('user.updated'));

I personally do:

return redirect()->back()->with('flash_message', 'user.updated');

And then do to i18n in a view. Can save those precious bytes!

1 Like

Great idea!