Redis is one of those services that starts as a simple cache and ends up being a critical piece of infrastructure. I’ve used it for session storage, rate limiting, job queues, pub/sub, and as a general-purpose key-value store. Getting the configuration right from the start saves headaches later.
Installation
# Ubuntu/Debian
apt install redis-server
# CentOS/RHEL
dnf install redis
For the latest stable version from the Redis project’s own repository:
curl -fsSL https://packages.redis.io/gpg | gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main" | tee /etc/apt/sources.list.d/redis.list
apt update
apt install redis
Start and verify:
systemctl enable redis-server
systemctl start redis-server
redis-cli ping # Should return PONG
Basic Configuration
The config file is at /etc/redis/redis.conf (Debian/Ubuntu) or /etc/redis.conf (CentOS/RHEL).
Key settings to review on a fresh install:
Network Binding
bind 127.0.0.1 ::1
By default, Redis only binds to localhost. For most use cases, this is correct — your app and Redis are on the same server. If you need Redis accessible from other servers, bind to the appropriate interface:
bind 0.0.0.0
But then set a password (see below), restrict with firewall, and consider using Redis over a VPN. Redis has no TLS by default (it’s opt-in), so credentials in clear text are a real concern over untrusted networks.
Authentication
requirepass your_strong_password_here
Even on localhost-only installs, setting a password is good practice. It prevents accidental redis-cli flushall from a misconfigured script.
In your application, configure the password in the Redis connection string:
******127.0.0.1:6379
Port
port 6379
Change the port if you want to reduce exposure to automated scanning. Not security through obscurity exactly, but it cuts down on noise in your logs.
Memory Configuration
maxmemory 2gb
maxmemory-policy allkeys-lru
maxmemory — set a limit on how much memory Redis can use. Without this, Redis uses all available memory and can trigger the OOM killer. I always set this.
maxmemory-policy — what to do when the limit is reached:
noeviction— return errors when memory is full (safe for databases, bad for caches)allkeys-lru— evict least recently used keys (good for cache use cases)volatile-lru— evict LRU keys only from those with an expire setallkeys-random— evict random keysvolatile-ttl— evict keys with the shortest TTL
For a pure cache, allkeys-lru is typical. For a database or session store where losing keys is bad, noeviction or volatile-lru.
Persistence
Redis supports two persistence mechanisms:
RDB (snapshots) — saves a point-in-time snapshot of data to disk at intervals:
save 900 1 # Save if at least 1 key changed in 900 seconds
save 300 10 # Save if at least 10 keys changed in 300 seconds
save 60 10000 # Save if at least 10000 keys changed in 60 seconds
AOF (Append-Only File) — logs every write operation:
appendonly yes
appendfsync everysec # Sync to disk every second
For a pure cache where data loss is acceptable: disable both (save "", appendonly no). Redis restarts empty and warms up from application traffic.
For session storage or anything you don’t want to lose: enable AOF with appendfsync everysec. You might lose up to 1 second of writes on a crash, but that’s usually acceptable.
For maximum durability: appendfsync always — sync every write. Significantly slower but no data loss.
I usually enable AOF for anything beyond pure caching.
Tuning for Performance
Disable Transparent Huge Pages
This is the most impactful OS-level change. Redis performs better without transparent huge pages:
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag
Make it permanent in /etc/rc.local or a systemd service:
# /etc/systemd/system/disable-thp.service
[Unit]
Description=Disable THP
After=sysinit.target local-fs.target
[Service]
Type=oneshot
ExecStart=/bin/sh -c "echo never > /sys/kernel/mm/transparent_hugepage/enabled && echo never > /sys/kernel/mm/transparent_hugepage/defrag"
[Install]
WantedBy=multi-user.target
systemctl enable disable-thp
systemctl start disable-thp
Redis logs a warning on startup if THP is enabled — this is what that warning refers to.
TCP Backlog
tcp-backlog 511
Increase the connection backlog for high-connection-rate scenarios. Also increase the OS-level:
echo "net.core.somaxconn=1024" >> /etc/sysctl.d/99-redis.conf
sysctl -p /etc/sysctl.d/99-redis.conf
Max Clients
maxclients 1000
Default is 10,000. Set to something reasonable for your use case. Each client uses a file descriptor — make sure the OS ulimit is configured appropriately.
Connection Pooling from Applications
Don’t open a new Redis connection for every operation. Use connection pooling in your application.
Python (redis-py):
import redis
pool = redis.ConnectionPool(
host='127.0.0.1',
port=6379,
password='your_password',
db=0,
max_connections=50
)
r = redis.Redis(connection_pool=pool)
Node.js (ioredis):
const redis = new Redis({
host: '127.0.0.1',
port: 6379,
password: 'your_password',
lazyConnect: true,
maxRetriesPerRequest: 3
});
Connection pool size should match your application’s concurrency level. More pools = more Redis connections = more overhead.
Monitoring
Check real-time stats:
redis-cli info
redis-cli info stats
redis-cli info memory
redis-cli monitor # Logs all commands (careful — very verbose, use briefly)
Key metrics to watch:
redis-cli info | grep -E "used_memory_human|connected_clients|rejected_connections|keyspace_hits|keyspace_misses|evicted_keys"
keyspace_hits / (keyspace_hits + keyspace_misses) = hit rate. For a cache, you want this above 90%+.
evicted_keys — keys evicted due to maxmemory. Some eviction is normal for a cache; high rates suggest maxmemory is too low.
rejected_connections — connections rejected because maxclients was hit. If this is non-zero, increase maxclients or reduce connection pool sizes.
Backup
# Save a snapshot manually
redis-cli bgsave
# The RDB file location
redis-cli config get dir
redis-cli config get dbfilename
Copy the RDB file for backups. For AOF, back up the AOF file. Either way, include Redis data in your backup rotation. For the backup strategy, the same principles from PostgreSQL backups apply — regular backups plus testing that they’re actually restorable.
Securing Redis
Beyond the password:
- Disable dangerous commands via renaming:
rename-command FLUSHALL ""
rename-command FLUSHDB ""
rename-command CONFIG ""
rename-command DEBUG ""
- Use Unix socket instead of TCP for local-only access:
unixsocket /var/run/redis/redis.sock
unixsocketperm 770
Then connect with redis-cli -s /var/run/redis/redis.sock.
- Use TLS for remote connections (Redis 6+):
tls-port 6380
tls-cert-file /etc/redis/tls/redis.crt
tls-key-file /etc/redis/tls/redis.key
tls-ca-cert-file /etc/redis/tls/ca.crt
Redis 6.0+ includes native TLS support. For older versions, use stunnel or a VPN.