Redis Configuration Guide
Complete guide for Redis setup on Heatwave servers (production and staging).
Overview
Hybrid Architecture (Production):
- Local Redis (127.0.0.1): Cache databases (1, 4, 5) - Geocoder, Rails cache, API cache
- Remote Redis (Vultr): Shared databases (0, 2, 3) - Sessions, Action Cable, Sidekiq
Single Server (Staging):
- Local Redis (127.0.0.1): All databases (0-5) - Everything runs locally
- Unix socket enabled for better performance
- Persistence enabled - Sessions/Sidekiq need to survive restarts
Database Assignments
| Database | Service | Production Location | Staging Location |
|---|---|---|---|
| 0 | Sessions | Remote (Vultr) | Local (127.0.0.1) |
| 1 | Geocoder cache | Local (127.0.0.1) | Local (127.0.0.1) |
| 2 | Action Cable | Remote (Vultr) | Local (127.0.0.1) |
| 3 | Sidekiq | Remote (Vultr) | Local (127.0.0.1) |
| 4 | Rails cache | Local (127.0.0.1) | Local (127.0.0.1) |
| 5 | API cache | Local (127.0.0.1) | Local (127.0.0.1) |
Why Hybrid in Production:
- Cache databases (1, 4, 5) are deterministic - no sharing needed, faster locally
- Shared databases (0, 2, 3) must be shared across multiple app servers
Production Setup (App Servers)
Step 1: Install Redis
sudo apt-get update
sudo apt-get install -y redis-server
redis-server --version
Step 2: Configure Redis for Cache-Only
Edit /etc/redis/redis.conf:
# Network - localhost only
bind 127.0.0.1 ::1
protected-mode yes
# Memory management
maxmemory 1gb # Adjust based on available RAM (see sizing guide below)
maxmemory-policy allkeys-lru
# Disable persistence (cache is ephemeral)
save ""
appendonly no
# Performance
tcp-keepalive 300
timeout 300
maxclients 10000
# Logging
loglevel notice
logfile /var/log/redis/redis-server.log
Memory Sizing Guide:
- Check available RAM:
free -h - Use 10-20% of available RAM, max 2GB for cache-only
- Example: 7GB available → use 1GB for Redis
Step 3: Create Log Directory
sudo mkdir -p /var/log/redis
sudo chown redis:redis /var/log/redis
sudo chmod 755 /var/log/redis
Step 4: Start Redis
sudo systemctl enable redis-server
sudo systemctl start redis-server
sudo systemctl status redis-server
# Test connection
redis-cli ping
# Should return: PONG
Step 5: Verify Cache Databases
redis-cli -n 1 ping # Geocoder cache
redis-cli -n 4 ping # Rails cache
redis-cli -n 5 ping # API cache
All should return PONG.
Staging Setup (Single Server)
Step 1: Install Redis
sudo apt-get update
sudo apt-get install -y redis-server
Step 2: Configure Redis
Edit /etc/redis/redis.conf:
# Network - localhost only
bind 127.0.0.1 ::1
protected-mode yes
# Unix socket (better performance for local connections)
unixsocket /var/run/redis/redis-server.sock
unixsocketperm 770
# Memory management
maxmemory 512mb
maxmemory-policy allkeys-lru
# Persistence enabled (sessions/Sidekiq need it)
# Keep default save points or explicitly set:
save 3600 1 300 100 60 10000
appendonly no # RDB persistence is sufficient
# Password authentication (OPTIONAL for localhost-only)
# Since Redis is bound to 127.0.0.1 only, password is optional
# Only add if you want defense-in-depth or consistency with production patterns
# requirepass entreat8GRANDAM-ply
# Logging
loglevel notice
logfile /var/log/redis/redis-server.log
Step 3: Create Socket Directory
sudo mkdir -p /var/run/redis
sudo chown redis:redis /var/run/redis
sudo chmod 755 /var/run/redis
Step 3.5: Add Deploy User to Redis Group (REQUIRED)
Critical: The deploy user must be in the redis group to access the Unix socket during Capistrano deployments.
# Add deploy user to redis group
sudo usermod -a -G redis deploy
# Verify the user is in the group
groups deploy
# Should show: deploy redis ... (redis should be listed)
# Note: User must log out and back in (or restart session) for group changes to take effect
# For systemd services, restart the service after adding the user to the group
Why this is needed:
- Unix socket permissions are
770(owner and group can read/write) - Socket is owned by
redis:redis deployuser needs group membership to connect duringrake db:migrateand other deployment tasks
Step 4: Start Redis
sudo systemctl enable redis-server
sudo systemctl restart redis-server
# Test Unix socket (with password if configured)
redis-cli -s /var/run/redis/redis-server.sock -a entreat8GRANDAM-ply ping
# Or without password: redis-cli -s /var/run/redis/redis-server.sock ping
# Test TCP (with password if configured)
redis-cli -a entreat8GRANDAM-ply ping
# Or without password: redis-cli ping
Both should return PONG.
Configuration Files
config/redis_consolidated.yml
This file defines Redis connection settings per environment:
default: &default
host: 127.0.0.1
port: 6379
ssl: false
staging:
<<: *default
username: entreat8GRANDAM-ply
password: # Password from redis.conf requirepass
production:
host: vultr-prod-17a82860-f346-40c1-967a-e683814f57ea-vultr-prod-a2b0.vultrdb.com
port: 16752
username: default
password: AVNS_SpT2e_ummAiKRKiPjuT@vultr-prod-17a82860-f346-40c1-967a-e683814f57ea-vultr-prod-a2b0
ssl: true
Code Configuration
The RedisConfig class (config/initializers/100_redis_config.rb) automatically:
- Routes cache databases (1, 4, 5) to local Redis in production
- Routes shared databases (0, 2, 3) to remote Redis in production
- Detects and uses Unix socket if available (staging)
- Falls back to TCP if socket not found
- Handles password authentication for both TCP and Unix socket
No manual configuration needed - the code handles routing automatically.
Verification
Production (App Servers)
# Check local Redis status
sudo systemctl status redis-server
redis-cli info memory
# Test cache databases
redis-cli -n 1 dbsize # Geocoder cache
redis-cli -n 4 dbsize # Rails cache
redis-cli -n 5 dbsize # API cache
# In Rails console
rails console
Rails.cache.write('test', 'value', expires_in: 1.minute)
Rails.cache.read('test') # Should return "value"
Staging
# Check Redis status
sudo systemctl status redis-server
# Test Unix socket (with password if configured)
redis-cli -s /var/run/redis/redis-server.sock -a entreat8GRANDAM-ply ping
# Or without password: redis-cli -s /var/run/redis/redis-server.sock ping
# Verify socket exists
ls -la /var/run/redis/redis-server.sock
# Should show: srwxrwx--- redis redis
# Check persistence (with password if configured)
redis-cli -a entreat8GRANDAM-ply CONFIG GET save
# Or without password: redis-cli CONFIG GET save
Testing Unix Socket Access (Deploy User)
After adding deploy user to redis group, test access:
# Switch to deploy user
sudo su - deploy
# Quick test: Direct socket access
redis-cli -s /var/run/redis/redis-server.sock ping
# Should return: PONG
# Comprehensive test: Run the test script
cd /var/www/heatwave/current
RAILS_ENV=staging bundle exec rails runner script/test_redis_socket_access.rb
# This will test:
# - User group membership
# - Socket file permissions
# - Direct Unix socket connection
# - Sidekiq connection (critical for deployments)
# - Rails cache connection
# - Sessions connection
# - Action Cable connection
# - Geocoder connection
Expected output:
- ✅ All connections should succeed
- ✅ User should be in
redisgroup - ✅ Socket should be readable/writable
- ✅ Sidekiq job enqueue should work (this is what failed during migration)
Troubleshooting
Redis Won't Start
# Check logs
sudo journalctl -u redis-server -n 50
# Check if port is in use
sudo lsof -i :6379
# Test config syntax
redis-server /etc/redis/redis.conf --test-memory 1
Connection Refused
# Verify Redis is running
sudo systemctl status redis-server
# Test connection
redis-cli ping
# Check Rails logs for connection errors
tail -f log/production.log | grep -i redis
Memory Issues
# Check current usage
redis-cli info memory
# If hitting maxmemory, increase in redis.conf:
# maxmemory 1gb
# Then restart: sudo systemctl restart redis-server
Unix Socket Permission Denied (Staging)
This error occurs when the deploy user cannot access the Unix socket during deployments.
# Check socket permissions
ls -la /var/run/redis/redis-server.sock
# Should show: srwxrwx--- redis redis
# Check if deploy user is in redis group
groups deploy
# Should include 'redis' in the output
# Fix: Add deploy user to redis group (REQUIRED)
sudo usermod -a -G redis deploy
# Verify group membership
groups deploy
# Should show: deploy : deploy sudo redis docker
# After adding to group:
# - For interactive testing: Use `newgrp redis` to activate the group in current session
# - For Capistrano deployments: Group membership is automatically active (each command runs in new shell)
# - For systemd services: Restart the service after adding user to group
# Quick test (after adding to group):
newgrp redis
redis-cli -s /var/run/redis/redis-server.sock ping
# Should return: PONG
# If socket permissions are wrong, fix them:
sudo chown redis:redis /var/run/redis/redis-server.sock
sudo chmod 770 /var/run/redis/redis-server.sock
sudo systemctl restart redis-server
Password Authentication Issues
Note: Password is optional for localhost-only Redis. If you don't use a password, remove requirepass from redis.conf and remove password from config/redis_consolidated.yml.
If you do use a password:
- Password works the same for TCP and Unix socket - the Redis client handles AUTH automatically
- If you see authentication errors:
- Verify password in
/etc/redis/redis.confmatchesconfig/redis_consolidated.yml - Check Rails logs for connection URL (should include password if configured)
- Test manually:
redis-cli -a <password> ping
- Verify password in
Security Checklist
Production (Cache-Only)
- ✅ Redis bound to
127.0.0.1only (not accessible externally) - ✅ No password needed (localhost-only)
- ✅ Protected mode enabled
- ✅ Firewall doesn't expose port 6379
- ✅ Runs as
redisuser (not root) - ✅ Persistence disabled (cache is ephemeral)
Staging (Full Redis)
- ✅ Redis bound to
127.0.0.1only - ⚠️ Password authentication (optional - not needed for localhost-only, adds unnecessary complexity)
- ✅ Protected mode enabled
- ✅ Unix socket with proper permissions (770)
- ✅ Persistence enabled (sessions/Sidekiq need it)
Monitoring
Check Redis Status
# Service status
sudo systemctl status redis-server
# Memory usage
redis-cli info memory
# Database sizes
redis-cli -n 0 dbsize # Sessions
redis-cli -n 1 dbsize # Geocoder cache
redis-cli -n 4 dbsize # Rails cache
redis-cli -n 5 dbsize # API cache
# View logs
sudo tail -f /var/log/redis/redis-server.log
Rails Logs
Look for these messages on startup:
Redis cache store initialized successfully: redis://127.0.0.1:6379/4
Redis API cache store initialized successfully: redis://127.0.0.1:6379/5
For staging with Unix socket:
Redis cache store initialized successfully: unix:///var/run/redis/redis-server.sock?db=4
Benefits
Production Hybrid Setup
-
Cache databases (1, 4, 5) local:
- ✅ No network dependency = no connection failures
- ✅ Sub-millisecond latency
- ✅ Eliminates cache-related incidents
-
Shared databases (0, 2, 3) remote:
- ✅ Sessions work across all app servers
- ✅ Sidekiq jobs can be processed by any worker
- ✅ Action Cable pub/sub works across servers
Staging Single Server
- All databases local:
- ✅ Simple setup (one server handles everything)
- ✅ Unix socket for optimal performance
- ✅ Persistence for sessions/Sidekiq
Rollback Plan
If issues arise:
- Revert
config/initializers/100_redis_config.rbto previous version - Restart Rails application
- All databases will use remote Redis again (production) or continue using local (staging)
No need to uninstall local Redis - it just won't be used.
Quick Reference
Production App Server Commands
# Install
sudo apt-get install -y redis-server
# Configure (edit /etc/redis/redis.conf)
# - Set maxmemory 1gb
# - Set maxmemory-policy allkeys-lru
# - Disable persistence (save "", appendonly no)
# Start
sudo systemctl enable redis-server
sudo systemctl start redis-server
# Test
redis-cli ping
Staging Server Commands
# Install
sudo apt-get install -y redis-server
# Configure (edit /etc/redis/redis.conf)
# - Enable Unix socket (unixsocket /var/run/redis/redis-server.sock)
# - Set unixsocketperm 770
# - Set maxmemory 512mb
# - Keep persistence enabled
# - Password is optional (not needed for localhost-only)
# Create socket directory
sudo mkdir -p /var/run/redis
sudo chown redis:redis /var/run/redis
# Start
sudo systemctl enable redis-server
sudo systemctl restart redis-server
# Test (with password if configured)
redis-cli -s /var/run/redis/redis-server.sock -a <password> ping
# Or without password: redis-cli -s /var/run/redis/redis-server.sock ping