Use Redis as a Session Store for a Web App
Store web sessions in Redis with short keys, SETEX TTLs, and cookie hygiene so logins survive app restarts without turning Redis into a public session dump.
Netbay Developer Relations
Netbay Engineering
On this page
Application memory is a bad session store. A restart logs everyone out. Two app processes do not share the session map. A deploy becomes a forced logout. Redis fixes that if you treat sessions as short-lived keys with a TTL, a random id in an HttpOnly cookie, and an instance that cannot evict those keys at random. The cookie is the pointer. Redis is the record. SQL remains the user table.
This is not a cache. A missed session key is a logged-out user. Persistence, maxmemory, and bind settings should match that fact.
Cookie in the browser, blob in Redis
Issue a cryptographically random session id, put it in a Secure HttpOnly cookie, and SETEX a JSON blob under sess: plus that id. The blob holds user id, role, and a small bag of display data. It should not hold passwords, reset tokens, or full profile rows.
const crypto = require('crypto');
function createSession(user, res, cb) {
const sid = crypto.randomBytes(24).toString('hex');
const payload = JSON.stringify({ uid: user.id, role: user.role });
redis.setex('sess:' + sid, 86400, payload, function (err) {
if (err) return cb(err);
res.setHeader('Set-Cookie', 'sid=' + sid + '; Path=/; HttpOnly; Secure; SameSite=Lax; Max-Age=86400');
cb(null, sid);
});
}
function loadSession(sid, cb) {
redis.get('sess:' + sid, function (err, raw) {
if (err) return cb(err);
if (!raw) return cb(null, null);
cb(null, JSON.parse(raw));
});
}86400 seconds is one day. Sliding expiry is a GET plus EXPIRE on each authenticated request, or a SETEX of the same payload. Sliding expiry is nicer for humans and easier to leak forever if a stolen cookie is replayed. Absolute expiry plus a separate refresh path is stricter. Pick one and document it.
Logout is DEL of the key plus a Set-Cookie that expires the cookie. Password change should DEL every sess:* for that user. Scanning by payload is slow; keep a secondary set user:42:sessions of session ids if you need mass revoke.
Redis settings that do not drop logins
allkeys-lru will evict a quiet session to make room for a cache key. That looks like random logouts at peak traffic. Use a dedicated Redis database or, better, a dedicated process. If you must share, give every session a TTL and use volatile-ttl, and never insert cache keys without EXPIRE.
bind 127.0.0.1
requirepass a-long-random-secret
maxmemory 256mb
maxmemory-policy volatile-ttl
appendonly yes
appendfsync everysec
save 300 10AOF everysec is the right durability for sessions on a small VPS. You lose about a second of logins on a crash, not the whole day. RDB alone can lose minutes. Cache-only save empty is wrong here.
The cookie must not be readable from JavaScript. HttpOnly does that. Secure requires HTTPS. SameSite=Lax stops most cross-site POST replay. Bind Redis to localhost so the session dump is not on the public IP. ACL the app user to ~sess:* if other keys share the instance.
What goes wrong in production
The classic failure is storing the entire user row and never expiring it. used_memory grows until evictions start, and LRU logs people out. The second failure is putting the session id in a query string, where it lands in access logs. The third is running Redis without a password on 0.0.0.0, which turns every session into public JSON. A fourth is sharing one maxmemory pool with a cache that uses allkeys-lru: the cache wins, the sessions lose, and the bug report is "users keep getting logged out after deploys." Split the processes or split the policies before you scale traffic.
Check the store the way you would check a database.
redis-cli INFO keyspace
redis-cli RANDOMKEY
redis-cli TTL sess:demo
redis-cli SLOWLOG GET 10TTL should be positive. RANDOMKEY should not surprise you with keys that have no prefix. SLOWLOG should not show KEYS sess:*. Use SCAN with a pattern, never KEYS, when you debug.
On a Netbay VPS the application and Redis share Intel Xeon Platinum cores and High-Speed SSD. Sessions still live in RAM. Size maxmemory for peak concurrent logins times blob size, then add headroom for AOF rewrite. A 2 KB blob times 50,000 sessions is about 100 MB plus overhead, not 2 GB.
Takeaway
Random session id in an HttpOnly cookie, SETEX blob in Redis, AOF on, LRU off those keys. You can run the app and Redis on one Lucknow VPS from Netbay and keep logins across deploys — netbayhosts.in.
Keep reading
Follow along on a real VPS
Deploy Linux in under 60 seconds
These guides are written against Ubuntu, Debian, and RHEL-family images — the same ones on NetBay.
Deploy an instance