Redis TLS Configuration: Encrypting Client Connections on Redis 6 and Later

Redis added native TLS support in version 6.0, released in April 2020. Before that, TLS for Redis required a TLS proxy (stunnel, spiped, or nginx stream proxy). If you are still running Redis without TLS because “it is on a private network”, consider that Redis commands carry your application data — including session tokens, cache entries, and queued jobs — in plaintext across any switch between your application servers and the Redis host. This article covers enabling TLS on Redis, connecting clients, and setting up TLS for Redis Sentinel and Redis Cluster.

Check your Redis version

redis-server --version
# Redis server v=7.2.0 ...

TLS requires Redis 6.0 or later. If you are on an older version, you need to either upgrade or use a TLS proxy (stunnel configuration is covered at the end of this article).

Step 1: Obtain certificates

Redis reads TLS files from disk in PEM format. You need:

  • redis.crt — the Redis server’s certificate (full chain)
  • redis.key — the private key
  • ca.crt — the CA certificate (for client verification)
# From Let's Encrypt
certbot certonly --standalone -d redis.example.com

# Or generate a self-signed certificate for internal use
openssl req -x509 -newkey rsa:4096 \
  -keyout /etc/redis/redis.key \
  -out /etc/redis/redis.crt \
  -days 365 -nodes \
  -subj "/CN=redis.example.com" \
  -addext "subjectAltName=DNS:redis.example.com,IP:192.168.1.100"

Set permissions — Redis runs as the redis user:

cp /etc/letsencrypt/live/redis.example.com/fullchain.pem /etc/redis/redis.crt
cp /etc/letsencrypt/live/redis.example.com/privkey.pem   /etc/redis/redis.key
cp /etc/letsencrypt/live/redis.example.com/chain.pem     /etc/redis/ca.crt

chown redis:redis /etc/redis/redis.crt /etc/redis/redis.key /etc/redis/ca.crt
chmod 640 /etc/redis/redis.key
chmod 644 /etc/redis/redis.crt /etc/redis/ca.crt

Step 2: Configure TLS in redis.conf

Open /etc/redis/redis.conf:

sudo nano /etc/redis/redis.conf

Add or update these settings:

# Enable TLS port (default Redis TLS port is 6380, but any port works)
port 0
tls-port 6380

# Certificate and key files
tls-cert-file /etc/redis/redis.crt
tls-key-file  /etc/redis/redis.key

# CA certificate for verifying client certificates (mutual TLS)
tls-ca-cert-file /etc/redis/ca.crt

# Minimum TLS version
tls-protocols "TLSv1.2 TLSv1.3"

# Preferred ciphers (TLS 1.2)
tls-ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-CHACHA20-POLY1305"

# Prefer server cipher order
tls-prefer-server-ciphers yes

# Client certificate verification
# "yes"      = require client cert (mutual TLS)
# "optional" = accept but do not require client cert
# "no"       = do not verify client cert (TLS encryption only)
tls-auth-clients no

To keep the plaintext port disabled:

port 0

To run both plaintext and TLS in parallel (useful for a migration period):

port 6379
tls-port 6380

Step 3: Restart Redis and verify

sudo systemctl restart redis
sudo systemctl status redis

# Check the TLS port is listening
sudo ss -tlnp | grep 6380

Test with openssl:

openssl s_client -connect redis.example.com:6380 -servername redis.example.com \
  -CAfile /etc/redis/ca.crt </dev/null 2>&1 \
  | openssl x509 -noout -subject -dates

Test with redis-cli:

redis-cli -h redis.example.com -p 6380 \
  --tls \
  --cacert /etc/redis/ca.crt \
  PING
# Expected: PONG

If using a self-signed certificate where the CA is also the server cert:

redis-cli -h redis.example.com -p 6380 \
  --tls \
  --cacert /etc/redis/redis.crt \
  PING

Step 4: Connecting application clients

Python (redis-py)

import redis
import ssl

r = redis.Redis(
    host='redis.example.com',
    port=6380,
    ssl=True,
    ssl_ca_certs='/etc/app/redis-ca.crt',
    ssl_certfile=None,   # client cert, needed for mutual TLS
    ssl_keyfile=None,    # client key, needed for mutual TLS
    ssl_check_hostname=True,
    decode_responses=True
)

print(r.ping())   # True
r.set('test-key', 'hello over TLS')
print(r.get('test-key'))  # hello over TLS

Node.js (ioredis)

const Redis = require('ioredis');
const fs = require('fs');

const redis = new Redis({
  host: 'redis.example.com',
  port: 6380,
  tls: {
    ca: fs.readFileSync('/etc/app/redis-ca.crt'),
    // cert: fs.readFileSync('/etc/app/client.crt'),  // mutual TLS
    // key: fs.readFileSync('/etc/app/client.key'),   // mutual TLS
    rejectUnauthorized: true,
    servername: 'redis.example.com'
  }
});

redis.ping().then(result => console.log(result)); // PONG

Go (go-redis)

import (
    "crypto/tls"
    "crypto/x509"
    "os"
    "github.com/redis/go-redis/v9"
)

caCert, _ := os.ReadFile("/etc/app/redis-ca.crt")
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)

rdb := redis.NewClient(&redis.Options{
    Addr: "redis.example.com:6380",
    TLSConfig: &tls.Config{
        RootCAs:    caCertPool,
        ServerName: "redis.example.com",
    },
})

PHP (Predis)

$client = new Predis\Client([
    'scheme'  => 'tls',
    'host'    => 'redis.example.com',
    'port'    => 6380,
    'ssl'     => [
        'cafile'      => '/etc/app/redis-ca.crt',
        'verify_peer' => true,
        'verify_peer_name' => true,
        'peer_name'   => 'redis.example.com',
    ],
]);

Mutual TLS — requiring client certificates

When you want only trusted applications to connect (no password authentication):

In redis.conf:

tls-auth-clients yes
tls-ca-cert-file /etc/redis/ca.crt

Generate client certificates:

# For each application
openssl genrsa -out /etc/app/client.key 4096
openssl req -new -key /etc/app/client.key -out /tmp/client.csr -subj "/CN=myapp"
openssl x509 -req -in /tmp/client.csr -CA /etc/redis/ca.crt -CAkey /etc/redis/ca.key \
  -CAcreateserial -out /etc/app/client.crt -days 365

Redis Sentinel with TLS

Redis Sentinel 6+ supports TLS. Each Sentinel instance needs its own certificate. In sentinel.conf:

tls-port 26380
port 0

tls-cert-file /etc/redis/sentinel.crt
tls-key-file  /etc/redis/sentinel.key
tls-ca-cert-file /etc/redis/ca.crt

tls-replication yes

sentinel monitor mymaster redis-primary.example.com 6380 2
sentinel auth-pass mymaster YourRedisPassword

The Redis primary and replicas must also be TLS-enabled. Configure replication TLS on the replica:

tls-replication yes

Redis Cluster with TLS

In a Redis Cluster, all nodes use TLS for both client connections and inter-node communication (gossip and replication). Set in each node’s redis.conf:

tls-port 6380
port 0
tls-replication yes
tls-cluster yes

tls-cert-file /etc/redis/node1.crt
tls-key-file  /etc/redis/node1.key
tls-ca-cert-file /etc/redis/ca.crt

Create the cluster using TLS endpoints:

redis-cli --tls --cacert /etc/redis/ca.crt \
  --cluster create \
  redis-node1.example.com:6380 \
  redis-node2.example.com:6380 \
  redis-node3.example.com:6380 \
  --cluster-replicas 1

Certificate renewal

Create a deploy hook:

sudo nano /etc/letsencrypt/renewal-hooks/deploy/redis.sh
#!/bin/bash
DOMAIN=redis.example.com
DEST=/etc/redis

cp /etc/letsencrypt/live/${DOMAIN}/fullchain.pem ${DEST}/redis.crt
cp /etc/letsencrypt/live/${DOMAIN}/privkey.pem   ${DEST}/redis.key
cp /etc/letsencrypt/live/${DOMAIN}/chain.pem     ${DEST}/ca.crt

chown redis:redis ${DEST}/redis.crt ${DEST}/redis.key ${DEST}/ca.crt
chmod 640 ${DEST}/redis.key
chmod 644 ${DEST}/redis.crt ${DEST}/ca.crt

# Redis picks up new TLS certificates via CONFIG REWRITE + restart
# Redis 7.x supports TLS certificate hot-reload:
redis-cli -p 6380 --tls --cacert ${DEST}/ca.crt CONFIG SET tls-cert-file ${DEST}/redis.crt
redis-cli -p 6380 --tls --cacert ${DEST}/ca.crt CONFIG SET tls-key-file ${DEST}/redis.key
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/redis.sh

Redis 7.x supports hot-reloading TLS certificates via CONFIG SET without restarting, which means zero-downtime certificate rotation.

Using stunnel for Redis versions before 6.0

If you cannot upgrade Redis, use stunnel as a TLS proxy:

# /etc/stunnel/redis.conf

[redis-server]

accept = 6380 connect = 127.0.0.1:6379 cert = /etc/stunnel/redis.crt key = /etc/stunnel/redis.key cafile = /etc/stunnel/ca.crt verify = 2

sudo systemctl restart stunnel

Clients connect to the stunnel port (6380) as if it were a TLS-enabled Redis instance.

Troubleshooting

ErrorCauseFix
ERR This Redis server does not support TLSRedis older than 6.0 or compiled without TLSUpgrade or use stunnel
WRONGPASS after enabling TLSrequirepass still needed even with TLSProvide the password alongside TLS config
certificate verify failedClient does not trust CAProvide correct ca_certs or cacert path
Connection reset by peer on TLS portRedis not listening or TLS config errorCheck redis.conf and restart
tls-auth-clients yes locks out all clientsClients not sending certificatesSwitch to tls-auth-clients no until clients are updated

Summary

Redis TLS is configured in redis.conf with four settings: tls-port, tls-cert-file, tls-key-file, and optionally tls-ca-cert-file. Set port 0 to disable the plaintext port once all clients are migrated. All major Redis client libraries support TLS via SSL context configuration. For Redis Cluster and Sentinel, set tls-replication yes and tls-cluster yes to encrypt inter-node traffic. Redis 7.x allows hot certificate rotation via CONFIG SET, making renewals non-disruptive.

Scroll to Top