Chapter 40
Production Configuration and Security Hardening
Chapter 40: Production Configuration and Security Hardening
Redis ships with defaults optimized for developer convenience, not production security. A default installation is bound to 0.0.0.0, has no password, exposes all commands, and applies no memory limits. This chapter closes every gap: network isolation, authentication and fine-grained authorization via ACL, dangerous command protection, TLS mutual authentication, kernel tuning, and a complete 25-point production security checklist.
1. Network Binding
1.1 The bind Directive
# redis.conf
# Bind only to the loopback and private network interface.
# Never bind to 0.0.0.0 or a public IP address.
bind 127.0.0.1 192.168.1.100
# protected-mode: when no password is configured and bind covers more than
# loopback, Redis refuses all non-loopback connections.
# Keep this on even with a password as a second line of defense.
protected-mode yes
# Standard port — consider changing to reduce automated scanner exposure
port 6379
# Unix socket: highest performance for same-host communication
unixsocket /var/run/redis/redis.sock
unixsocketperm 770
# Verify only internal addresses are listening
ss -tlnp | grep 6379
# Safe: 127.0.0.1:6379 192.168.1.100:6379
# Danger: 0.0.0.0:6379 :::6379
2. Authentication: requirepass and ACL
2.1 requirepass (pre-Redis 6.0)
# redis.conf
requirepass "YourStr0ng!Password#2024"
# Client authentication
AUTH YourStr0ng!Password#2024
# Password requirements:
# - Minimum 32 characters
# - Mix of uppercase, lowercase, digits, symbols
# - Not in any dictionary; not based on company name or dates
2.2 ACL (Redis 6.0+ — Strongly Recommended)
ACL replaces the single shared password with a full user management system: named users, hashed passwords, allowed key patterns, and command-level permissions.
# Syntax: ACL SETUSER <name> [on|off] [>password] [~key-pattern] [+command]
# Read-only application user — can only access keys matching cache:*
ACL SETUSER readonly_user on >ReadPass#123 ~cache:* +@read
# Read-write application user with restricted key namespaces
ACL SETUSER app_user on >AppPass#456 \
~cache:* ~session:* \
+get +set +del +expire +hset +hget +hgetall +ttl +exists
# Administrator (full access)
ACL SETUSER admin_user on >AdminPass#789 ~* &* +@all
# Pub/Sub-only user
ACL SETUSER pubsub_user on >PubSubPass ~* &events:* +subscribe +publish +unsubscribe
# Inspect the current ACL list
ACL LIST
# user default off nopass ~* &* +@all
# user app_user on #<sha256_hash> ~cache:* ~session:* +get +set ...
# Check the current session's identity
ACL WHOAMI
# Dry-run: can user X execute command Y on key Z?
ACL DRYRUN app_user get cache:user:1001 # → OK or error
# Load ACL file (after editing it on disk)
ACL LOAD
# Persist current in-memory ACL state to file
ACL SAVE
# redis.conf — point to an external ACL file
aclfile /etc/redis/users.acl
# /etc/redis/users.acl
user default off
user app_user on #5e884898da28047151d0e56f8dc629277b7b1ad36601f39a6e4c6a40f5e0a16 \
~cache:* ~session:* +get +set +del +expire +hset +hget +hgetall +ttl +exists
user admin_user on #<admin_sha256> ~* &* +@all
2.3 Built-In Command Categories
+@all # every command
+@read # GET, HGET, LRANGE, SMEMBERS, ZRANGE, etc.
+@write # SET, HSET, LPUSH, SADD, ZADD, etc.
+@string # string-type commands only
+@hash # hash-type commands only
+@list # list-type commands only
+@set # set-type commands only
+@sortedset # sorted set commands only
+@geo # GEO commands
+@stream # Stream commands
+@pubsub # SUBSCRIBE, PUBLISH, etc.
+@admin # CONFIG, INFO, DEBUG, etc.
+@dangerous # FLUSHALL, KEYS, DEBUG, SHUTDOWN, etc.
-@dangerous # remove dangerous commands from an otherwise full grant
3. Renaming Dangerous Commands
# redis.conf
# Disable entirely (empty string)
rename-command FLUSHDB ""
rename-command FLUSHALL ""
rename-command DEBUG ""
rename-command KEYS ""
rename-command SHUTDOWN ""
# Rename to a secret string (internal tooling can still use it)
rename-command CONFIG "CONFIG_a8f3d2c1b4e5"
rename-command DEBUG "DEBUG_x9y8z7w6v5u4"
# IMPORTANT: rename-command is NOT supported in Cluster mode.
# In Cluster, rely on ACL -@dangerous instead.
# Adapting client code when CONFIG is renamed
CONFIG_CMD = "CONFIG_a8f3d2c1b4e5"
def redis_config_get(param: str):
return r.execute_command(CONFIG_CMD, "GET", param)
4. TLS Mutual Authentication (mTLS)
4.1 Generating Certificates
# Step 1: Create a Certificate Authority (CA)
openssl genrsa -out ca.key 4096
openssl req -new -x509 -days 3650 -key ca.key -out ca.crt \
-subj "/C=US/O=YourCompany/CN=Redis Internal CA"
# Step 2: Server certificate
openssl genrsa -out redis.key 2048
openssl req -new -key redis.key -out redis.csr \
-subj "/C=US/O=YourCompany/CN=redis.internal"
openssl x509 -req -days 365 \
-in redis.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
-out redis.crt
# Step 3: Client certificate (required for mTLS)
openssl genrsa -out client.key 2048
openssl req -new -key client.key -out client.csr \
-subj "/C=US/O=YourCompany/CN=redis-client"
openssl x509 -req -days 365 \
-in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
-out client.crt
4.2 Redis TLS Configuration
# redis.conf
# Disable plaintext port
port 0
# Enable TLS port
tls-port 6380
# Certificate files
tls-cert-file /etc/redis/certs/redis.crt
tls-key-file /etc/redis/certs/redis.key
tls-ca-cert-file /etc/redis/certs/ca.crt
# Require client certificates (mutual TLS)
tls-auth-clients yes
# Minimum protocol version
tls-protocols "TLSv1.2 TLSv1.3"
# Strong cipher suites
tls-ciphers "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384"
tls-ciphersuites "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256"
tls-prefer-server-ciphers yes
# Replicate and cluster traffic also encrypted
tls-replication yes
tls-cluster yes
4.3 Client Connections with TLS
import redis
r = redis.Redis(
host="redis.internal",
port=6380,
ssl=True,
ssl_certfile="/path/to/client.crt",
ssl_keyfile="/path/to/client.key",
ssl_ca_certs="/path/to/ca.crt",
ssl_check_hostname=True,
)
print(r.ping()) # True
# redis-cli with TLS
redis-cli -h redis.internal -p 6380 \
--tls \
--cert /path/to/client.crt \
--key /path/to/client.key \
--cacert /path/to/ca.crt \
ping
# PONG
5. maxmemory Sizing and Configuration
5.1 Sizing Formula
maxmemory = (physical RAM - OS reserve - other processes) × 0.75–0.85
Example — 32 GB server, Redis only:
OS + monitoring agents: 2.5 GB
Available for Redis: 29.5 GB
maxmemory = 29.5 × 0.80 ≈ 23 GB
Why not 100%?
Redis forks on BGSAVE. Fork uses Copy-on-Write (COW):
the child shares pages with the parent until they diverge.
On a write-heavy workload, RSS can nearly double during the fork window.
Always reserve 15–25% of maxmemory for COW overhead.
5.2 Configuration
# redis.conf
maxmemory 23gb
maxmemory-policy allkeys-lru # evict least-recently-used keys across all keys
maxmemory-samples 10 # sample 10 candidates per eviction (default 5; higher = more accurate)
# Eviction policy selection guide:
# noeviction — write errors when full (use for primary data store)
# allkeys-lru — evict LRU key from the whole keyspace (general cache)
# allkeys-lfu — evict least-frequently-used key (hot-spot preservation)
# allkeys-random — random eviction (rarely optimal)
# volatile-lru — evict LRU among keys with a TTL set
# volatile-lfu — evict LFU among keys with a TTL set
# volatile-random — random eviction among keys with a TTL set
# volatile-ttl — evict the key with the shortest remaining TTL
6. Kernel Parameter Tuning
# /etc/sysctl.conf
# Allow overcommit so BGSAVE fork never fails due to memory accounting
# 0 = heuristic (default) 1 = always allow 2 = strict
vm.overcommit_memory = 1
# Expand TCP connection queues for high-concurrency environments
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
# TCP keepalive — detect dead connections faster
net.ipv4.tcp_keepalive_time = 300
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 3
# Increase global file descriptor limit
fs.file-max = 1000000
# Apply immediately
sysctl -p
# Transparent Huge Pages (THP) — MUST be disabled
# THP causes COW latency spikes during fork and increased fragmentation
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag
# Persist across reboots (systemd approach)
cat > /etc/systemd/system/disable-thp.service << 'EOF'
[Unit]
Description=Disable Transparent Huge Pages
DefaultDependencies=no
After=sysinit.target local-fs.target
Before=redis.service
[Service]
Type=oneshot
ExecStart=/bin/sh -c 'echo never > /sys/kernel/mm/transparent_hugepage/enabled'
ExecStart=/bin/sh -c 'echo never > /sys/kernel/mm/transparent_hugepage/defrag'
[Install]
WantedBy=multi-user.target
EOF
systemctl enable disable-thp
# Verify
cat /sys/kernel/mm/transparent_hugepage/enabled
# Expected: always madvise [never]
# Per-process file descriptor limits for the redis user
# /etc/security/limits.conf
redis soft nofile 65535
redis hard nofile 65535
# Or via systemd unit
# /etc/systemd/system/redis.service (override)
[Service]
LimitNOFILE=65535
# redis.conf (matching kernel tuning)
tcp-backlog 511 # must be <= net.core.somaxconn
tcp-keepalive 300 # Redis-level keepalive (seconds)
timeout 300 # close idle client connections after 5 minutes
7. Persistence Security
# redis.conf
# RDB snapshots
save 3600 1 # save if 1 write occurred in the last hour
save 300 100 # save if 100 writes in 5 minutes
save 60 10000 # save if 10,000 writes in 1 minute
stop-writes-on-bgsave-error yes # fail writes if RDB save fails (safety net)
rdbcompression yes
rdbchecksum yes # CRC64 checksum validation on load
dbfilename dump.rdb
dir /var/lib/redis
# AOF (write-ahead log — recommended for production)
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec # fsync every second: good balance of safety and performance
# appendfsync always # fsync on every write: maximum durability, lowest throughput
# appendfsync no # OS decides: highest throughput, possible data loss
no-appendfsync-on-rewrite no # keep fsyncing during AOF rewrite
auto-aof-rewrite-percentage 100 # trigger rewrite when AOF doubles in size
auto-aof-rewrite-min-size 64mb # but only if AOF is at least 64 MB
aof-use-rdb-preamble yes # hybrid RDB+AOF format for fast loads
# Directory permissions
# chown redis:redis /var/lib/redis
# chmod 750 /var/lib/redis
8. Audit Logging Options
# Redis has no built-in audit log. Choose the approach that fits your environment.
# Option 1: Short-term MONITOR capture (impacts performance significantly)
redis-cli monitor >> /var/log/redis/audit.log &
# Option 2: Proxy-layer auditing (recommended for production)
# Deploy Envoy sidecar or Twemproxy to intercept and log all commands.
# Supports filtering by user, IP address, or command type.
# Option 3: Keyspace notifications with an external subscriber
CONFIG SET notify-keyspace-events "KEA" # all key events
redis-cli subscribe '__keyevent@0__:set' '__keyevent@0__:del'
9. Production Security Checklist (25 Items)
Network Isolation (5 items)
✅ 1. bind is set to loopback + private network interfaces only; 0.0.0.0 is never used.
✅ 2. Firewall rules: port 6379/6380 is open only to application server IPs; closed to the public internet.
✅ 3. Redis and application servers share the same VPC / security group; no public network routing.
✅ 4. Sentinel port 26379 and Cluster bus ports 17000+ have their own restrictive firewall rules.
✅ 5. Same-host applications use Unix Socket instead of TCP (performance + security).
Authentication and Authorization (5 items)
✅ 6. Authentication is mandatory — requirepass or ACL with a strong password; no anonymous access.
✅ 7. ACL enforces least privilege: each application user is restricted to its own key namespace.
✅ 8. The default user is disabled: ACL SETUSER default off.
✅ 9. Different services use different Redis users; sensitive services use separate logical databases.
✅ 10. Passwords and credentials are stored in a secrets manager (HashiCorp Vault, AWS Secrets Manager); never hard-coded.
Dangerous Command Protection (4 items)
✅ 11. rename-command disables FLUSHDB, FLUSHALL, DEBUG, and SHUTDOWN.
✅ 12. rename-command disables KEYS; all code uses SCAN.
✅ 13. ACL includes -@dangerous for all application users.
✅ 14. Destructive operations (FLUSHALL, DROP DATABASE equivalent) require dual approval in production.
Transport Security (2 items)
✅ 15. TLS is enabled in production; minimum TLS 1.2, TLS 1.3 preferred; mTLS for sensitive environments.
✅ 16. Replica and Cluster inter-node communication also uses TLS (tls-replication yes, tls-cluster yes).
Memory and Configuration (4 items)
✅ 17. maxmemory is set with a 15–25% buffer for BGSAVE COW overhead; eviction policy is configured.
✅ 18. timeout is set (e.g., 300 seconds) to auto-close idle connections and prevent connection leaks.
✅ 19. Transparent Huge Pages are disabled: echo never > .../transparent_hugepage/enabled (system-wide).
✅ 20. vm.overcommit_memory = 1 prevents BGSAVE fork failure under high memory pressure.
Persistence and Backup (3 items)
✅ 21. AOF is enabled (appendonly yes) with appendfsync everysec for production data safety.
✅ 22. RDB snapshots are shipped to remote object storage (S3 / OSS) daily; 7-day retention minimum.
✅ 23. Backup restoration drill is performed quarterly; RTO and RPO targets are documented and validated.
Monitoring and Alerting (2 items)
✅ 24. redis_exporter + Prometheus + Grafana are deployed; all critical alerts from Chapter 39 are active.
✅ 25. slowlog-log-slower-than is set to 5000 μs (5 ms); slow query alerts and weekly reviews are in place.
10. Complete Production redis.conf Template
# ===== NETWORK =====
bind 127.0.0.1 192.168.1.100
port 6379
protected-mode yes
tcp-backlog 511
timeout 300
tcp-keepalive 300
# ===== TLS (uncomment to enable) =====
# port 0
# tls-port 6380
# tls-cert-file /etc/redis/certs/redis.crt
# tls-key-file /etc/redis/certs/redis.key
# tls-ca-cert-file /etc/redis/certs/ca.crt
# tls-auth-clients yes
# tls-protocols "TLSv1.2 TLSv1.3"
# tls-replication yes
# tls-cluster yes
# ===== AUTHENTICATION =====
# requirepass "YourStr0ng!Password#2024" # replaced by ACL below
aclfile /etc/redis/users.acl
# ===== DANGEROUS COMMAND PROTECTION =====
rename-command FLUSHDB ""
rename-command FLUSHALL ""
rename-command DEBUG ""
rename-command KEYS ""
rename-command SHUTDOWN "SHUTDOWN_9x8y7z"
rename-command CONFIG "CONFIG_a1b2c3d4"
# ===== MEMORY =====
maxmemory 23gb
maxmemory-policy allkeys-lru
maxmemory-samples 10
# ===== PERSISTENCE =====
save 3600 1
save 300 100
save 60 10000
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
dir /var/lib/redis
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-use-rdb-preamble yes
# ===== PERFORMANCE =====
hz 10
dynamic-hz yes
aof-rewrite-incremental-fsync yes
rdb-save-incremental-fsync yes
# ===== SLOW LOG =====
slowlog-log-slower-than 5000
slowlog-max-len 256
# ===== LOGGING =====
loglevel notice
logfile /var/log/redis/redis.log
# ===== PROCESS =====
daemonize yes
pidfile /var/run/redis/redis.pid
# ===== CLIENT LIMITS =====
maxclients 10000
Chapter Summary
- Three-layer network isolation: bind + protected-mode + firewall rules.
- ACL (Redis 6.0+) supersedes the shared
requirepassmodel; implement least-privilege per service. rename-command+ACL -@dangerousform a dual barrier against destructive commands.- mTLS with client certificate validation ensures both server and client identities are verified.
- Size
maxmemoryconservatively (75–85% of available RAM) to accommodate BGSAVE COW spikes; always set an eviction policy. - Kernel requirements: THP off, overcommit_memory = 1, somaxconn expanded — all three are mandatory.
- The 25-item checklist spans network, authentication, command protection, TLS, memory, persistence, and monitoring — work through it before every production deployment.