Redis on Linux: Installation, Configuration, and Production Tuning

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 set
  • allkeys-random — evict random keys
  • volatile-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:

  1. Disable dangerous commands via renaming:
rename-command FLUSHALL ""
rename-command FLUSHDB ""
rename-command CONFIG ""
rename-command DEBUG ""
  1. 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.

  1. 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.

Scroll to Top