The Problem
TLS-encrypted connections to Redis fail with various errors:
Redis::ConnectionError: SSL_connect returned=1 errno=0 state=error: certificate verify failed
Error: Connection refused (TLS required)
SSL handshake failed: wrong version numberSecure 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
redis-cli CONFIG GET tls-*Output:
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 300Check Certificate Files
ls -la /etc/redis/tls/Verify Certificate Validity
openssl x509 -in /etc/redis/tls/redis.crt -text -noout | grep -E "Issuer|Subject|Not Before|Not After"Test TLS Connection
redis-cli --tls --cert /etc/redis/tls/client.crt \
--key /etc/redis/tls/client.key \
--cacert /etc/redis/tls/ca.crt \
PINGCheck OpenSSL Connection
openssl s_client -connect localhost:6379 -CAfile /etc/redis/tls/ca.crt \
-cert /etc/redis/tls/client.crt \
-key /etc/redis/tls/client.keyCommon TLS Errors
Error 1: Certificate Verify Failed
SSL_connect returned=1 errno=0 state=error: certificate verify failedDiagnosis:
```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.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.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.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
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
SSL handshake failed: wrong version numberDiagnosis:
```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
No client certificate providedDiagnosis:
redis-cli CONFIG GET tls-auth-clientsValues:
- 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
Error loading certificate fileDiagnosis:
ls -la /etc/redis/tls/
ps aux | grep redis # Check Redis userSolution:
```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
SSL handshake failed: no shared ciphersDiagnosis:
redis-cli CONFIG GET tls-ciphers
redis-cli CONFIG GET tls-ciphersuitesSolution:
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 ```