Redis Production Checklist for Django
A production checklist for Redis in Django stacks: separate roles for cache, sessions, and Celery; memory limits and eviction; persistence; network security and TLS; client timeouts; monitoring; and upgrades.
Problem statement
Redis often runs three jobs in a Django deployment at once: the cache, the session store, and the Celery broker and result backend. Each job has different requirements for memory, eviction, and durability, and a single default Redis configuration serves none of them well. Problems appear as users logged out after a restart, tasks silently lost, OOM command not allowed errors, or an unauthenticated Redis port found by an internet scanner.
This checklist reviews Redis for a Django production setup: roles and configuration, memory, persistence, security, client settings, and monitoring. It applies to self-hosted Redis and Valkey and, with minor differences, to managed services.
- Separate roles: cache on one instance (evicting), broker and sessions on another (not evicting, persistent).
- Set
maxmemorybelow available memory on every instance, with the rightmaxmemory-policyper role. - Enable AOF persistence for the broker and sessions; disable persistence for the cache.
- Keep Redis off the public internet; require authentication (ACL users or
requirepass) and TLS across untrusted networks. - Configure client timeouts and connection health checks in Django and Celery.
- Monitor memory, evictions, connected clients, latency, and queue lengths; alert on thresholds.
Checklist
1. Roles and instances
- Cache, sessions, and Celery are identified, and each uses a known instance and database number.
- The cache runs on an instance where eviction is allowed; the broker (and sessions stored only in Redis) run where it is not.
- Celery results expire (
CELERY_RESULT_EXPIRES) or are disabled for tasks whose results are never read. - Django settings use separate cache aliases if sessions are cache-backed (
SESSION_CACHE_ALIAS).
2. Memory
maxmemoryis set on every instance, below the server's or container's memory with headroom for fork-based persistence.- Cache instance:
maxmemory-policy allkeys-lru(orallkeys-lfu). - Broker and session instance:
maxmemory-policy noeviction, with alerts before memory fills. - Cache entries have timeouts; no unbounded keys from
cache.set(..., None)in cache-only instances. - Large values are avoided (store IDs or references, not whole rendered pages of megabytes).
3. Persistence and durability
- Broker and sessions: AOF enabled with
appendfsync everysec; data directory on persistent storage or a mounted volume. - Cache:
save ""andappendonly no. vm.overcommit_memory = 1on hosts running persistent Redis, so background saves do not fail.- A restart test has confirmed that queued tasks and sessions survive (see the persistence guide).
4. Network and access
- Redis listens only on private interfaces (
bindset appropriately) and is not reachable from the internet; firewall or security groups enforce it. protected-modestays enabled unless authentication and binding are configured deliberately.- Authentication is required: ACL users (Redis 6 and newer) with only the needed permissions, or at least
requirepasswith a long random password. - Dangerous commands (
FLUSHALL,CONFIG,DEBUG,KEYS) are not available to application users (ACL rules or renamed commands). - TLS is enabled when traffic crosses networks you do not fully control (managed services usually offer it; use
rediss://URLs).
5. Client configuration
- Django cache: socket timeouts are set so a slow or unreachable Redis does not hang requests:
CACHES = {
"default": {
"BACKEND": "django.core.cache.backends.redis.RedisCache",
"LOCATION": os.environ["REDIS_CACHE_URL"],
"OPTIONS": {
"socket_connect_timeout": 2,
"socket_timeout": 2,
"health_check_interval": 30,
},
}
}
- The application degrades gracefully if the cache is down (pages slower, not failing) where possible; decide per use.
- Celery broker connection settings include retries on start-up (
broker_connection_retry_on_startup) and sensiblevisibility_timeoutfor long tasks. - Connection counts are bounded: Gunicorn workers, Celery processes, and other clients stay below
maxclients.
6. Monitoring
- Memory used versus
maxmemory, and fragmentation ratio. evicted_keysrate (should be near zero for broker and sessions; expected for cache).- Cache hit ratio (
keyspace_hitsversuskeyspace_misses). - Connected clients, rejected connections, and blocked clients.
- Latency (
redis-cli --latency, orLATENCYmonitoring) and slow commands (SLOWLOG GET). - Celery queue lengths per queue, and age of the oldest message where tooling allows.
- Persistence status:
aof_last_write_status,rdb_last_bgsave_status.
7. Operations
- Redis version is supported and receives security fixes; upgrades are planned with a restart window or a replica-based switchover.
- Configuration lives in version-controlled files or infrastructure code, not only in
CONFIG SETcommands. - Backups (RDB snapshots) are copied off the server if sessions or other state in Redis matter.
- High availability needs are defined: for many Django apps, a single instance with persistence and fast restart is enough; otherwise, use replicas with Sentinel or a managed service with automatic failover, and test failover behaviour in Django and Celery.
Explanation
Redis's configuration is instance-wide: one memory limit, one eviction policy, one persistence setting. Django uses it for data with conflicting needs (disposable cache entries next to tasks that must not be lost), so separating roles is the foundation of a reliable setup. The rest of the checklist protects the instance from outside access, protects the application from a slow or failing Redis through timeouts, and makes pressure visible before it turns into errors.
Edge cases / notes
Managed Redis differences
Managed services may restrict commands (CONFIG), handle persistence through snapshots and replicas instead of AOF, and set default eviction policies such as volatile-lru. Check the defaults and adjust through the provider's parameter settings.
Valkey and Redis licensing
Valkey is an open-source fork of Redis, compatible with its protocol and the Django and Celery clients. The checklist applies to both.
When to automate this
Provision Redis instances from templates that encode role-specific settings (memory, policy, persistence, ACLs), and include Redis metrics and alerts in your standard monitoring stack. Run the restart test during disaster recovery drills.
Next steps
- Configure the cache correctly with Set Up Redis Caching for Django in Production.
- Protect queued tasks with Configure Redis Persistence for Django and Celery.
- If Redis rejects writes, see Fix Redis "OOM command not allowed" in Django.
- If Django cannot connect, see Fix Redis Connection Refused in Django.
FAQ
Should the Django cache and Celery broker share one Redis instance?
It works for small setups, but separate instances let the cache evict freely while the broker never loses tasks. Separate them as soon as either matters.
What eviction policy should Redis use for Django?
allkeys-lru or allkeys-lfu for a cache-only instance; noeviction for the Celery broker and sessions.
Does Redis need a password on a private network?
Yes. Defence in depth matters, and many breaches start from services assumed to be unreachable. Use ACL users or requirepass.
What Redis metrics should I alert on?
Memory near maxmemory, evictions on non-cache instances, persistence failures, rejected connections, high latency, and growing Celery queues.