Set up Redis as both cache backend and session storage for Django applications. Improve page load times and user experience with proper Redis configuration and Django integration.
Prerequisites
- Django application running
- Python pip package manager
- Root or sudo access
What this solves
Django's default database sessions and no caching can create performance bottlenecks under load. This tutorial configures Redis as both Django's cache backend and session storage, reducing database queries and improving response times for high-traffic applications.
Step-by-step installation
Update system packages
Start by updating your package manager to ensure you get the latest versions.
sudo apt update && sudo apt upgrade -y
Install Redis server
Install Redis server and client libraries for your system.
sudo apt install -y redis-server redis-tools
Configure Redis for production
Set up Redis with optimized settings for Django caching and sessions.
# Memory configuration
maxmemory 256mb
maxmemory-policy allkeys-lru
Persistence settings for sessions
save 900 1
save 300 10
save 60 10000
Network settings
bind 127.0.0.1
port 6379
tcp-keepalive 300
Security
requirepass your_secure_redis_password
Performance tuning
tcp-backlog 511
timeout 0
keepalive 300
Enable and start Redis
Enable Redis to start on boot and start the service.
sudo systemctl enable redis-server
sudo systemctl start redis-server
sudo systemctl status redis-server
Install Python Redis clients
Install the Redis Python client and Django Redis integration library.
pip install redis django-redis hiredis
Configure Django caching backend
Add Redis cache configuration to your Django settings file.
CACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': 'redis://127.0.0.1:6379/1',
'OPTIONS': {
'CLIENT_CLASS': 'django_redis.client.DefaultClient',
'PASSWORD': 'your_secure_redis_password',
'CONNECTION_POOL_KWARGS': {
'max_connections': 50,
'retry_on_timeout': True,
}
},
'KEY_PREFIX': 'myapp',
'VERSION': 1,
'TIMEOUT': 300, # 5 minutes default timeout
}
}
Use Redis for session caching too
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
SESSION_CACHE_ALIAS = 'default'
SESSION_COOKIE_AGE = 1209600 # 2 weeks
Configure Redis session storage
Set up dedicated Redis database for session storage with different configuration.
# Alternative: Separate Redis instance for sessions
CACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': 'redis://127.0.0.1:6379/1',
'OPTIONS': {
'CLIENT_CLASS': 'django_redis.client.DefaultClient',
'PASSWORD': 'your_secure_redis_password',
},
'KEY_PREFIX': 'cache',
'TIMEOUT': 300,
},
'sessions': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': 'redis://127.0.0.1:6379/2',
'OPTIONS': {
'CLIENT_CLASS': 'django_redis.client.DefaultClient',
'PASSWORD': 'your_secure_redis_password',
},
'KEY_PREFIX': 'session',
'TIMEOUT': 1209600, # 2 weeks
}
}
Use dedicated session cache
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
SESSION_CACHE_ALIAS = 'sessions'
Add caching middleware
Enable Django's caching middleware for automatic page caching.
MIDDLEWARE = [
'django.middleware.cache.UpdateCacheMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'django.middleware.cache.FetchFromCacheMiddleware',
]
Cache settings
CACHE_MIDDLEWARE_ALIAS = 'default'
CACHE_MIDDLEWARE_SECONDS = 600
CACHE_MIDDLEWARE_KEY_PREFIX = ''
Enable template fragment caching
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
'builtins': [
'django.templatetags.cache',
],
},
},
]
Optimize Redis memory usage
Configure Redis to handle Django's specific caching patterns efficiently.
# Optimize for Django usage patterns
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
list-max-ziplist-size -2
list-compress-depth 0
set-max-intset-entries 512
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
Disable problematic commands in production
rename-command FLUSHDB ""
rename-command FLUSHALL ""
rename-command DEBUG ""
Enable keyspace notifications for cache invalidation
notify-keyspace-events Ex
Set up Redis monitoring
Configure Redis to log performance metrics and set up basic monitoring.
# Logging configuration
loglevel notice
logfile /var/log/redis/redis-server.log
syslog-enabled yes
syslog-ident redis
Slow log configuration
slowlog-log-slower-than 10000
slowlog-max-len 128
Client output buffer limits
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit slave 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
Restart Redis with new configuration
Apply the Redis configuration changes by restarting the service.
sudo systemctl restart redis-server
sudo systemctl status redis-server
Test Django Redis integration
Create a Django management command to test caching functionality.
from django.core.management.base import BaseCommand
from django.core.cache import cache
from django.contrib.sessions.models import Session
import time
class Command(BaseCommand):
help = 'Test Redis caching and session storage'
def handle(self, *args, **options):
# Test caching
cache_key = 'test_key'
cache_value = 'Hello Redis!'
# Set cache value
cache.set(cache_key, cache_value, 60)
# Get cache value
result = cache.get(cache_key)
if result == cache_value:
self.stdout.write(
self.style.SUCCESS('Cache test passed: %s' % result)
)
else:
self.stdout.write(
self.style.ERROR('Cache test failed')
)
# Test cache performance
start_time = time.time()
for i in range(1000):
cache.set(f'perf_test_{i}', f'value_{i}', 60)
set_time = time.time() - start_time
start_time = time.time()
for i in range(1000):
cache.get(f'perf_test_{i}')
get_time = time.time() - start_time
self.stdout.write(
f'Performance: 1000 SETs in {set_time:.3f}s, 1000 GETs in {get_time:.3f}s'
)
Add template fragment caching
Implement template-level caching for expensive template operations.
{% load cache %}
My Django App
{% cache 300 sidebar request.user.id %}
{% endcache %}
{% cache 600 main_content %}
{{ content }}
{% endcache %}
Configure cache invalidation
Set up Django signals to automatically invalidate cache when models change.
from django.db.models.signals import post_save, post_delete
from django.dispatch import receiver
from django.core.cache import cache
from django.core.cache.utils import make_template_fragment_key
from .models import Article
@receiver([post_save, post_delete], sender=Article)
def invalidate_article_cache(sender, instance, **kwargs):
# Invalidate specific cache keys
cache_keys = [
f'article_{instance.id}',
'article_list',
'latest_articles',
]
cache.delete_many(cache_keys)
# Invalidate template fragment cache
fragment_key = make_template_fragment_key('article_detail', [instance.id])
cache.delete(fragment_key)
# Invalidate pattern-based keys
cache.delete_pattern('article_*')
Verify your setup
Test that Redis is properly integrated with Django for both caching and sessions.
# Check Redis is running
sudo systemctl status redis-server
redis-cli ping
Test Django cache integration
python manage.py test_cache
Check Redis memory usage
redis-cli info memory
Monitor Redis operations
redis-cli monitor
Test session storage by logging into your Django application and checking Redis:
# Check session keys in Redis
redis-cli keys "session"
View Django cache statistics
python manage.py shell
>>> from django.core.cache import cache
>>> cache.get_stats()
Performance optimization
Enable Redis persistence tuning
Configure Redis persistence for session data while optimizing for performance.
# Optimize RDB saves
save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
Disable AOF for cache-only data (enable for sessions)
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
Configure connection pooling
Optimize Django Redis connections for high-traffic applications.
CACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': 'redis://127.0.0.1:6379/1',
'OPTIONS': {
'CLIENT_CLASS': 'django_redis.client.DefaultClient',
'PASSWORD': 'your_secure_redis_password',
'CONNECTION_POOL_KWARGS': {
'max_connections': 100,
'retry_on_timeout': True,
'socket_keepalive': True,
'socket_keepalive_options': {
'TCP_KEEPIDLE': 1,
'TCP_KEEPINTVL': 3,
'TCP_KEEPCNT': 5,
},
},
'COMPRESSOR': 'django_redis.compressors.zlib.ZlibCompressor',
'IGNORE_EXCEPTIONS': True,
},
'TIMEOUT': 300,
}
}
Enable connection pooling globally
DJANGO_REDIS_CONNECTION_FACTORY = 'django_redis.pool.ConnectionFactory'
Security hardening
Secure Redis access
Implement additional security measures for Redis in production.
# Network security
bind 127.0.0.1
protected-mode yes
port 6379
Authentication
requirepass your_very_secure_redis_password_here
Disable dangerous commands
rename-command FLUSHDB ""
rename-command FLUSHALL ""
rename-command EVAL ""
rename-command DEBUG ""
rename-command CONFIG "CONFIG_b835c3b4c1e7f7ad8c7b0f0e8b8e4d9b"
Resource limits
tcp-backlog 511
timeout 300
tcp-keepalive 300
maxclients 10000
Set up Redis firewall rules
Configure firewall to restrict Redis access to Django application only.
# Allow Redis only from localhost
sudo ufw deny 6379
sudo ufw allow from 127.0.0.1 to any port 6379
Common issues
| Symptom | Cause | Fix |
|---|---|---|
| Connection refused errors | Redis not running or wrong port | sudo systemctl start redis-server and check /etc/redis/redis.conf |
| Authentication errors | Password mismatch | Verify Redis password in settings matches /etc/redis/redis.conf |
| Cache misses under load | Memory eviction policy | Increase maxmemory or check maxmemory-policy setting |
| Slow cache operations | Network latency or memory swapping | Check Redis slow log: redis-cli slowlog get 10 |
| Sessions not persisting | Redis persistence disabled | Enable RDB or AOF persistence in redis.conf |
| High memory usage | No expiration on cache keys | Set TIMEOUT values in Django cache config |
chown redis:redis and use chmod 644 for files, chmod 755 for directories.Next steps
- Configure Redis cluster sharding for horizontal scaling to handle larger datasets
- Monitor Django applications with Prometheus and Grafana for performance insights
- Configure Django database connection pooling optimization for complete performance tuning
- Set up Django Celery with Redis for background tasks
- Configure NGINX with Django Redis session clustering
Running this in production?
Automated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
# Default configuration
REDIS_PASSWORD=""
REDIS_MEMORY="256mb"
DJANGO_PROJECT_PATH=""
# Usage function
usage() {
echo "Usage: $0 [OPTIONS]"
echo "Options:"
echo " -p, --password PASSWORD Set Redis password (required)"
echo " -m, --memory MEMORY Set Redis max memory (default: 256mb)"
echo " -d, --django-path PATH Django project path (optional)"
echo " -h, --help Show this help message"
exit 1
}
# Parse command line arguments
while [[ $# -gt 0 ]]; do
case $1 in
-p|--password)
REDIS_PASSWORD="$2"
shift 2
;;
-m|--memory)
REDIS_MEMORY="$2"
shift 2
;;
-d|--django-path)
DJANGO_PROJECT_PATH="$2"
shift 2
;;
-h|--help)
usage
;;
*)
echo -e "${RED}Unknown option: $1${NC}"
usage
;;
esac
done
# Validate required parameters
if [[ -z "$REDIS_PASSWORD" ]]; then
echo -e "${RED}Error: Redis password is required${NC}"
usage
fi
# Cleanup function for rollback
cleanup() {
echo -e "${YELLOW}Error occurred. Cleaning up...${NC}"
systemctl stop redis-server 2>/dev/null || systemctl stop redis 2>/dev/null || true
if [[ -f "/etc/redis/redis.conf.backup" ]]; then
mv /etc/redis/redis.conf.backup /etc/redis/redis.conf 2>/dev/null || true
fi
}
trap cleanup ERR
# Check if running as root or with sudo
if [[ $EUID -ne 0 ]]; then
echo -e "${RED}This script must be run as root or with sudo${NC}"
exit 1
fi
echo -e "${GREEN}Starting Django Redis configuration...${NC}"
# Auto-detect distribution
echo "[1/8] Detecting system distribution..."
if [[ -f /etc/os-release ]]; then
. /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_UPDATE="apt update"
PKG_INSTALL="apt install -y"
REDIS_SERVICE="redis-server"
REDIS_CONFIG="/etc/redis/redis.conf"
REDIS_PACKAGES="redis-server redis-tools"
;;
almalinux|rocky|centos|rhel|ol)
PKG_MGR="dnf"
PKG_UPDATE="dnf update -y"
PKG_INSTALL="dnf install -y"
REDIS_SERVICE="redis"
REDIS_CONFIG="/etc/redis/redis.conf"
REDIS_PACKAGES="redis redis-tools epel-release"
;;
fedora)
PKG_MGR="dnf"
PKG_UPDATE="dnf update -y"
PKG_INSTALL="dnf install -y"
REDIS_SERVICE="redis"
REDIS_CONFIG="/etc/redis/redis.conf"
REDIS_PACKAGES="redis redis-tools"
;;
amzn)
PKG_MGR="yum"
PKG_UPDATE="yum update -y"
PKG_INSTALL="yum install -y"
REDIS_SERVICE="redis"
REDIS_CONFIG="/etc/redis/redis.conf"
REDIS_PACKAGES="redis redis-tools"
;;
*)
echo -e "${RED}Unsupported distribution: $ID${NC}"
exit 1
;;
esac
echo -e "${GREEN}Detected: $PRETTY_NAME${NC}"
else
echo -e "${RED}Cannot detect distribution${NC}"
exit 1
fi
# Update system packages
echo "[2/8] Updating system packages..."
$PKG_UPDATE
# Install Redis server and tools
echo "[3/8] Installing Redis server and tools..."
$PKG_INSTALL $REDIS_PACKAGES
# Create Redis configuration directory if it doesn't exist
mkdir -p "$(dirname "$REDIS_CONFIG")"
# Backup existing Redis configuration
echo "[4/8] Configuring Redis for production..."
if [[ -f "$REDIS_CONFIG" ]]; then
cp "$REDIS_CONFIG" "${REDIS_CONFIG}.backup"
fi
# Create optimized Redis configuration
cat > "$REDIS_CONFIG" << EOF
# Memory configuration
maxmemory $REDIS_MEMORY
maxmemory-policy allkeys-lru
# Persistence settings for sessions
save 900 1
save 300 10
save 60 10000
# Network settings
bind 127.0.0.1
port 6379
tcp-keepalive 300
# Security
requirepass $REDIS_PASSWORD
# Performance tuning
tcp-backlog 511
timeout 0
tcp-keepalive 300
# Logging
loglevel notice
logfile /var/log/redis/redis-server.log
# Database settings
databases 16
# RDB configuration
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
dir /var/lib/redis
EOF
# Set proper permissions on Redis configuration
chown redis:redis "$REDIS_CONFIG" 2>/dev/null || chown root:root "$REDIS_CONFIG"
chmod 640 "$REDIS_CONFIG"
# Create log directory
mkdir -p /var/log/redis
chown redis:redis /var/log/redis 2>/dev/null || chown root:root /var/log/redis
chmod 755 /var/log/redis
# Enable and start Redis service
echo "[5/8] Starting Redis service..."
systemctl enable "$REDIS_SERVICE"
systemctl start "$REDIS_SERVICE"
# Install Python Redis clients
echo "[6/8] Installing Python Redis clients..."
if command -v pip3 &> /dev/null; then
pip3 install redis django-redis hiredis
elif command -v pip &> /dev/null; then
pip install redis django-redis hiredis
else
echo -e "${YELLOW}Warning: pip not found. Please install Redis Python packages manually:${NC}"
echo "pip install redis django-redis hiredis"
fi
# Create Django configuration template
echo "[7/8] Creating Django configuration template..."
DJANGO_CONFIG_FILE="/tmp/django_redis_settings.py"
cat > "$DJANGO_CONFIG_FILE" << EOF
# Django Redis Configuration
# Add this to your Django settings.py file
CACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': 'redis://127.0.0.1:6379/1',
'OPTIONS': {
'CLIENT_CLASS': 'django_redis.client.DefaultClient',
'PASSWORD': '$REDIS_PASSWORD',
'CONNECTION_POOL_KWARGS': {
'max_connections': 50,
'retry_on_timeout': True,
}
},
'KEY_PREFIX': 'myapp',
'VERSION': 1,
'TIMEOUT': 300, # 5 minutes default timeout
},
'sessions': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': 'redis://127.0.0.1:6379/2',
'OPTIONS': {
'CLIENT_CLASS': 'django_redis.client.DefaultClient',
'PASSWORD': '$REDIS_PASSWORD',
},
'KEY_PREFIX': 'session',
'TIMEOUT': 1209600, # 2 weeks
}
}
# Session configuration
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
SESSION_CACHE_ALIAS = 'sessions'
SESSION_COOKIE_AGE = 1209600 # 2 weeks
# Cache middleware settings
CACHE_MIDDLEWARE_ALIAS = 'default'
CACHE_MIDDLEWARE_SECONDS = 600
CACHE_MIDDLEWARE_KEY_PREFIX = ''
# Add these middleware classes to your MIDDLEWARE setting:
# 'django.middleware.cache.UpdateCacheMiddleware' (at the top)
# 'django.middleware.cache.FetchFromCacheMiddleware' (at the bottom)
EOF
chmod 644 "$DJANGO_CONFIG_FILE"
# Copy to Django project if path provided
if [[ -n "$DJANGO_PROJECT_PATH" && -d "$DJANGO_PROJECT_PATH" ]]; then
cp "$DJANGO_CONFIG_FILE" "$DJANGO_PROJECT_PATH/django_redis_settings.py"
echo -e "${GREEN}Django configuration saved to: $DJANGO_PROJECT_PATH/django_redis_settings.py${NC}"
fi
# Verification checks
echo "[8/8] Running verification checks..."
# Check Redis service status
if systemctl is-active --quiet "$REDIS_SERVICE"; then
echo -e "${GREEN}✓ Redis service is running${NC}"
else
echo -e "${RED}✗ Redis service is not running${NC}"
exit 1
fi
# Test Redis connection
if redis-cli -a "$REDIS_PASSWORD" ping | grep -q "PONG"; then
echo -e "${GREEN}✓ Redis connection test successful${NC}"
else
echo -e "${RED}✗ Redis connection test failed${NC}"
exit 1
fi
# Check Redis memory setting
REDIS_MAXMEM=$(redis-cli -a "$REDIS_PASSWORD" config get maxmemory | tail -n1)
if [[ -n "$REDIS_MAXMEM" ]]; then
echo -e "${GREEN}✓ Redis memory limit configured${NC}"
else
echo -e "${YELLOW}Warning: Redis memory limit not set${NC}"
fi
echo -e "${GREEN}Django Redis configuration completed successfully!${NC}"
echo ""
echo -e "${YELLOW}Next steps:${NC}"
echo "1. Add the configuration from $DJANGO_CONFIG_FILE to your Django settings.py"
echo "2. Update your MIDDLEWARE setting to include caching middleware"
echo "3. Restart your Django application"
echo "4. Test caching functionality in your Django application"
echo ""
echo -e "${YELLOW}Redis connection details:${NC}"
echo "Host: 127.0.0.1"
echo "Port: 6379"
echo "Password: $REDIS_PASSWORD"
echo "Cache DB: 1"
echo "Session DB: 2"
Review the script before running. Execute with: bash install.sh