Popular solutions suggest Nginx Plus or custom Nginx module for sticky sessions.

Surprisingly, a simple approach needs just an unique per backend cookie and Nginx config setup.

The idea is to have backend routing by cookie-stored id with fallback to round robin if no cookie present.

Sample Nginx config:

upstream roundrobinbackend  {
   server 127.0.0.1:8001;
   server 127.0.0.1:8002;
}
map $cookie_backend $sticky_backend {
   default roundrobinbackend;
   backend8001 127.0.0.1:8001;
   backend8002 127.0.0.1.8002;
}
server {
    listen 80;
    location / {
       proxy_pass http://$sticky_backend$uri;
    }
}

In this scenario, each backend is responsible for setting unique cookie, like backend=backend8001, backend=backend8002, etc.

Nginx would map sessions per backend cookie and fallback to default round robin rule if no match present.