The Problem

TLS-encrypted connections to Redis fail with various errors:

bash
Redis::ConnectionError: SSL_connect returned=1 errno=0 state=error: certificate verify failed
Error: Connection refused (TLS required)
SSL handshake failed: wrong version number

Secure Redis deployments require TLS, but configuration issues prevent successful connections.

Understanding Redis TLS

Redis 6.0+ supports native TLS encryption: - Server certificates for authentication - Client certificates for mutual TLS - CA certificates for verification - TLS protocol version control

Key configuration parameters: - tls-cert-file - Server certificate - tls-key-file - Private key - tls-ca-cert-file - CA certificate for verification - tls-auth-clients - Client certificate requirement

Diagnosis Commands

Check Redis TLS Configuration

bash
redis-cli CONFIG GET tls-*

Output:

bash
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
tls-ca-cert-dir 
tls-auth-clients optional
tls-protocols TLSv1.2 TLSv1.3
tls-ciphers DEFAULT
tls-prefer-server-ciphers yes
tls-session-caching yes
tls-session-cache-size 5000
tls-session-cache-timeout 300

Check Certificate Files

bash
ls -la /etc/redis/tls/

Verify Certificate Validity

bash
openssl x509 -in /etc/redis/tls/redis.crt -text -noout | grep -E "Issuer|Subject|Not Before|Not After"

Test TLS Connection

bash
redis-cli --tls --cert /etc/redis/tls/client.crt \
          --key /etc/redis/tls/client.key \
          --cacert /etc/redis/tls/ca.crt \
          PING

Check OpenSSL Connection

bash
openssl s_client -connect localhost:6379 -CAfile /etc/redis/tls/ca.crt \
                  -cert /etc/redis/tls/client.crt \
                  -key /etc/redis/tls/client.key

Common TLS Errors

Error 1: Certificate Verify Failed

bash
SSL_connect returned=1 errno=0 state=error: certificate verify failed

Diagnosis:

```bash # Check certificate chain openssl verify -CAfile /etc/redis/tls/ca.crt /etc/redis/tls/redis.crt

# Check certificate expiration openssl x509 -in /etc/redis/tls/redis.crt -noout -dates

# Check if CA is correct openssl x509 -in /etc/redis/tls/ca.crt -noout -subject -issuer ```

Solutions:

  1. 1.Expired certificate:

```bash # Generate new certificate openssl req -new -x509 -days 365 -key /etc/redis/tls/redis.key \ -out /etc/redis/tls/redis.crt

# Restart Redis sudo systemctl restart redis-server ```

  1. 1.Wrong CA certificate:

```bash # Ensure CA matches certificate issuer openssl x509 -in /etc/redis/tls/redis.crt -noout -issuer openssl x509 -in /etc/redis/tls/ca.crt -noout -subject

# They should match (issuer from cert = subject from CA) ```

  1. 1.Hostname mismatch:

```bash # Check certificate CN/SAN openssl x509 -in /etc/redis/tls/redis.crt -noout -text | grep -E "Subject:|DNS:"

# If connecting to "redis.example.com", certificate must include it ```

Generate certificate with correct hostname:

```bash openssl req -new -key /etc/redis/tls/redis.key \ -subj "/CN=redis.example.com" \ -out /etc/redis/tls/redis.csr

openssl x509 -req -in /etc/redis/tls/redis.csr \ -CA /etc/redis/tls/ca.crt -CAkey /etc/redis/tls/ca.key \ -CAcreateserial -out /etc/redis/tls/redis.crt -days 365 ```

Error 2: TLS Not Enabled on Server

bash
Connection refused (TLS required)

or client connects but commands fail.

Diagnosis:

```bash # Check if TLS is configured redis-cli CONFIG GET tls-port redis-cli CONFIG GET tls-cert-file

# Try non-TLS connection redis-cli -p 6379 PING ```

Solution:

Enable TLS on Redis:

```bash # Configure TLS port redis-cli CONFIG SET tls-port 6380

# Set certificate files redis-cli CONFIG SET tls-cert-file /etc/redis/tls/redis.crt redis-cli CONFIG SET tls-key-file /etc/redis/tls/redis.key redis-cli CONFIG SET tls-ca-cert-file /etc/redis/tls/ca.crt

# Or in redis.conf 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 ```

Error 3: TLS Protocol Mismatch

bash
SSL handshake failed: wrong version number

Diagnosis:

```bash # Check supported protocols redis-cli CONFIG GET tls-protocols

# Client might be using incompatible version openssl s_client -connect localhost:6380 -tls1_2 openssl s_client -connect localhost:6380 -tls1_3 ```

Solution:

Match client and server protocols:

```bash # Allow specific protocols redis-cli CONFIG SET tls-protocols "TLSv1.2 TLSv1.3"

# Or allow all redis-cli CONFIG SET tls-protocols "" ```

Error 4: Client Certificate Required

bash
No client certificate provided

Diagnosis:

bash
redis-cli CONFIG GET tls-auth-clients

Values: - no - No client cert required - optional - Client cert optional - yes - Client cert required (default for mutual TLS)

Solution:

Provide client certificate or change server config:

```bash # Connect with client certificate redis-cli --tls --cacert /etc/redis/tls/ca.crt \ --cert /etc/redis/tls/client.crt \ --key /etc/redis/tls/client.key \ -p 6380 PING

# Or disable client cert requirement redis-cli CONFIG SET tls-auth-clients optional ```

Error 5: Permission Denied on Certificate Files

bash
Error loading certificate file

Diagnosis:

bash
ls -la /etc/redis/tls/
ps aux | grep redis  # Check Redis user

Solution:

```bash # Fix permissions sudo chown -R redis:redis /etc/redis/tls/ sudo chmod 600 /etc/redis/tls/*.key sudo chmod 644 /etc/redis/tls/*.crt

# Verify Redis can read sudo -u redis cat /etc/redis/tls/redis.crt >/dev/null && echo "OK" || echo "FAIL" ```

Error 6: Cipher Suite Mismatch

bash
SSL handshake failed: no shared ciphers

Diagnosis:

bash
redis-cli CONFIG GET tls-ciphers
redis-cli CONFIG GET tls-ciphersuites

Solution:

Set compatible cipher suites:

```bash # Allow common ciphers redis-cli CONFIG SET tls-ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256"

# For TLS 1.3 redis-cli CONFIG SET tls-ciphersuites "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256" ```

Client Configuration Examples

redis-cli

```bash # Basic TLS connection redis-cli --tls --cacert /path/to/ca.crt -h redis.example.com -p 6380

# With client certificate redis-cli --tls --cacert /path/to/ca.crt \ --cert /path/to/client.crt \ --key /path/to/client.key \ -h redis.example.com -p 6380

# Skip certificate verification (testing only) redis-cli --tls --insecure -h redis.example.com -p 6380 ```

Python redis-py

```python import redis

# Basic TLS r = redis.Redis( host='redis.example.com', port=6380, ssl=True, ssl_ca_certs='/path/to/ca.crt' )

# Mutual TLS r = redis.Redis( host='redis.example.com', port=6380, ssl=True, ssl_ca_certs='/path/to/ca.crt', ssl_certfile='/path/to/client.crt', ssl_keyfile='/path/to/client.key' )

# Skip verification (development only) r = redis.Redis( host='redis.example.com', port=6380, ssl=True, ssl_cert_reqs=None # No verification ) ```

Node.js ioredis

```javascript const Redis = require('ioredis');

// Basic TLS const redis = new Redis({ host: 'redis.example.com', port: 6380, tls: { ca: require('fs').readFileSync('/path/to/ca.crt') } });

// Mutual TLS const redis = new Redis({ host: 'redis.example.com', port: 6380, tls: { ca: require('fs').readFileSync('/path/to/ca.crt'), cert: require('fs').readFileSync('/path/to/client.crt'), key: require('fs').readFileSync('/path/to/client.key') } }); ```

Java Jedis

```java import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisShardInfo;

JedisShardInfo shardInfo = new JedisShardInfo("redis.example.com", 6380, true); shardInfo.setSslSocketFactory(createSslSocketFactory());

Jedis jedis = new Jedis(shardInfo); ```

Certificate Generation

Generate Self-Signed CA and Certificates

```bash # Generate CA key and certificate openssl genrsa -out /etc/redis/tls/ca.key 4096 openssl req -new -x509 -days 3650 -key /etc/redis/tls/ca.key \ -subj "/CN=Redis-CA" \ -out /etc/redis/tls/ca.crt

# Generate server key and certificate openssl genrsa -out /etc/redis/tls/redis.key 2048 openssl req -new -key /etc/redis/tls/redis.key \ -subj "/CN=redis.example.com" \ -out /etc/redis/tls/redis.csr

openssl x509 -req -in /etc/redis/tls/redis.csr \ -CA /etc/redis/tls/ca.crt -CAkey /etc/redis/tls/ca.key \ -CAcreateserial -out /etc/redis/tls/redis.crt -days 365

# Generate client certificate openssl genrsa -out /etc/redis/tls/client.key 2048 openssl req -new -key /etc/redis/tls/client.key \ -subj "/CN=redis-client" \ -out /etc/redis/tls/client.csr

openssl x509 -req -in /etc/redis/tls/client.csr \ -CA /etc/redis/tls/ca.crt -CAkey /etc/redis/tls/ca.key \ -CAcreateserial -out /etc/redis/tls/client.crt -days 365

# Set permissions chmod 600 /etc/redis/tls/*.key chmod 644 /etc/redis/tls/*.crt ```

Redis TLS Configuration

```conf # redis.conf

# TLS port (0 = disabled) tls-port 6380

# Standard port still available (optional) # port 6379

# Certificate files 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

# Client authentication tls-auth-clients optional # no, optional, or yes

# Protocol versions tls-protocols "TLSv1.2 TLSv1.3"

# Cipher suites tls-ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256" tls-ciphersuites "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256" tls-prefer-server-ciphers yes

# Session caching tls-session-caching yes tls-session-cache-size 5000 tls-session-cache-timeout 300 ```

Verification

After configuring TLS:

```bash # Test connection redis-cli --tls --cacert /etc/redis/tls/ca.crt -p 6380 PING

# Check certificate details openssl s_client -connect localhost:6380 -CAfile /etc/redis/tls/ca.crt | grep Verify

# Should show: Verify return code: 0 (ok)

# List TLS configuration redis-cli --tls --cacert /etc/redis/tls/ca.crt -p 6380 CONFIG GET tls-* ```

Mixed TLS and Non-TLS

Redis can serve both:

```conf # Allow both ports port 6379 # Non-TLS tls-port 6380 # TLS

# Or restrict non-TLS to local only bind 127.0.0.1 # Non-TLS localhost only tls-port 6380 # TLS for external ```

Clients connect based on their needs:

```bash # Local non-TLS redis-cli -p 6379 PING

# External TLS redis-cli --tls --cacert /etc/redis/tls/ca.crt -h redis.example.com -p 6380 PING ```