Set up high-performance Nginx caching with Redis backend using SSL/TLS encryption and authentication. This tutorial covers Redis 7 SSL configuration, Nginx cache module setup, and comprehensive security hardening for production environments.
Prerequisites
- Root or sudo access
- Basic Nginx knowledge
- Understanding of SSL/TLS concepts
- Redis fundamentals
What this solves
High-traffic websites need efficient caching to reduce database load and improve response times. This tutorial configures Nginx with Redis as a caching backend using SSL/TLS encryption and authentication for secure, production-ready caching. You'll learn to implement encrypted Redis connections, configure Nginx cache modules, and apply security hardening measures.
Step-by-step installation
Update system packages
Start by updating your system packages to ensure compatibility with the latest Redis and Nginx versions.
sudo apt update && sudo apt upgrade -y
Install Redis 7 and dependencies
Install Redis server with SSL support and necessary development tools for compilation.
sudo apt install -y redis-server redis-tools build-essential libssl-dev pkg-config
Install Nginx with additional modules
Install Nginx with the Redis module and SSL support for caching functionality.
sudo apt install -y nginx nginx-module-njs libnginx-mod-http-redis2
Create SSL certificates for Redis
Generate self-signed certificates for Redis SSL encryption. In production, use certificates from a trusted CA.
sudo mkdir -p /etc/redis/ssl
sudo openssl req -x509 -nodes -newkey rsa:4096 -keyout /etc/redis/ssl/redis.key -out /etc/redis/ssl/redis.crt -days 365 -subj "/C=US/ST=State/L=City/O=Organization/CN=redis.example.com"
Set SSL certificate permissions
Configure proper ownership and permissions for Redis SSL certificates. The redis user needs read access to certificates.
sudo chown redis:redis /etc/redis/ssl/redis.key /etc/redis/ssl/redis.crt
sudo chmod 600 /etc/redis/ssl/redis.key
sudo chmod 644 /etc/redis/ssl/redis.crt
Configure Redis with SSL and authentication
Create a secure Redis configuration with SSL/TLS encryption, authentication, and performance optimizations.
# Network and SSL Configuration
port 0
tls-port 6380
tls-cert-file /etc/redis/ssl/redis.crt
tls-key-file /etc/redis/ssl/redis.key
tls-protocols "TLSv1.2 TLSv1.3"
tls-ciphersuites "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256"
tls-ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256"
Authentication
requirepass "your_strong_redis_password_here_min_32_chars"
Security Settings
protected-mode yes
bind 127.0.0.1
tcp-backlog 511
timeout 300
tcp-keepalive 300
Memory and Performance
maxmemory 1gb
maxmemory-policy allkeys-lru
save 900 1
save 300 10
save 60 10000
Logging
loglevel notice
logfile /var/log/redis/redis-server.log
syslog-enabled yes
syslog-ident redis
Disable dangerous commands
rename-command FLUSHDB ""
rename-command FLUSHALL ""
rename-command KEYS ""
rename-command CONFIG "CONFIG_9f2ca1d8b5a3e7f4c6d2a8b1e5f9c3d7"
rename-command DEBUG ""
rename-command EVAL ""
rename-command SHUTDOWN SHUTDOWN_a8c2e4f6b9d1c3e5a7f2b8d4c6e9a1f3
Create Redis log directory
Set up the log directory with proper permissions for the Redis service.
sudo mkdir -p /var/log/redis
sudo chown redis:redis /var/log/redis
sudo chmod 755 /var/log/redis
Configure Nginx with Redis caching
Set up Nginx with Redis backend caching and SSL upstream connections. This configuration includes cache zones and security headers.
upstream redis_backend {
server 127.0.0.1:6380;
keepalive 32;
}
Cache zones
proxy_cache_path /var/cache/nginx/redis levels=1:2 keys_zone=redis_cache:10m max_size=1g inactive=60m use_temp_path=off;
proxy_cache_path /var/cache/nginx/static levels=1:2 keys_zone=static_cache:10m max_size=2g inactive=24h use_temp_path=off;
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com www.example.com;
# SSL Configuration
ssl_certificate /etc/nginx/ssl/nginx.crt;
ssl_certificate_key /etc/nginx/ssl/nginx.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# Security Headers
add_header X-Frame-Options DENY always;
add_header X-Content-Type-Options nosniff always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy strict-origin-when-cross-origin always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self';" always;
# Cache configuration
location ~* \.(jpg|jpeg|png|gif|ico|css|js|pdf|txt)$ {
proxy_cache static_cache;
proxy_cache_valid 200 301 302 24h;
proxy_cache_valid 404 1m;
proxy_cache_key $scheme$proxy_host$uri$is_args$args;
proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504;
proxy_cache_lock on;
expires 1y;
add_header Cache-Control "public, immutable";
add_header X-Cache-Status $upstream_cache_status always;
proxy_pass http://backend;
}
# API and dynamic content caching with Redis
location /api/ {
# Redis cache lookup
set $redis_key "api:$uri$is_args$args";
redis2_query auth your_strong_redis_password_here_min_32_chars;
redis2_query get $redis_key;
redis2_pass redis_backend;
# Handle cache miss
error_page 404 502 504 = @fallback;
}
location @fallback {
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Cache the response in Redis
proxy_cache redis_cache;
proxy_cache_valid 200 301 302 10m;
proxy_cache_valid 404 1m;
proxy_cache_key $scheme$proxy_host$uri$is_args$args;
proxy_cache_use_stale error timeout invalid_header updating;
add_header X-Cache-Status $upstream_cache_status always;
}
# Main location
location / {
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Basic caching
proxy_cache redis_cache;
proxy_cache_valid 200 301 302 5m;
proxy_cache_valid 404 1m;
proxy_cache_key $scheme$proxy_host$uri$is_args$args;
proxy_cache_bypass $http_pragma $http_authorization;
proxy_no_cache $http_pragma $http_authorization;
add_header X-Cache-Status $upstream_cache_status always;
}
}
Backend application servers
upstream backend {
server 127.0.0.1:8080;
server 127.0.0.1:8081 backup;
keepalive 16;
}
Create Nginx SSL certificates
Generate SSL certificates for Nginx. Replace with valid certificates in production.
sudo mkdir -p /etc/nginx/ssl
sudo openssl req -x509 -nodes -newkey rsa:4096 -keyout /etc/nginx/ssl/nginx.key -out /etc/nginx/ssl/nginx.crt -days 365 -subj "/C=US/ST=State/L=City/O=Organization/CN=example.com"
Create cache directories
Set up Nginx cache directories with proper permissions for the web server user.
sudo mkdir -p /var/cache/nginx/redis /var/cache/nginx/static
sudo chown -R www-data:www-data /var/cache/nginx
sudo chmod -R 755 /var/cache/nginx
Configure Nginx main settings
Update the main Nginx configuration to load Redis modules and optimize for caching workloads.
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
Load Redis module
load_module modules/ndk_http_module.so;
load_module modules/ngx_http_redis2_module.so;
events {
worker_connections 2048;
use epoll;
multi_accept on;
}
http {
# Basic Settings
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
server_tokens off;
client_max_body_size 64M;
# Buffer settings for performance
proxy_buffering on;
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
# Cache settings
proxy_temp_path /var/cache/nginx/temp;
proxy_cache_lock on;
proxy_cache_lock_timeout 5s;
proxy_cache_use_stale updating;
# MIME types
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Logging
log_format cache_status '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'rt=$request_time ut="$upstream_response_time" '
'cs="$upstream_cache_status"';
access_log /var/log/nginx/access.log cache_status;
error_log /var/log/nginx/error.log;
# Gzip Settings
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json;
# Rate limiting
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s;
# Include site configurations
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
Enable the site configuration
Link the Redis cache configuration and remove the default site.
sudo ln -sf /etc/nginx/sites-available/redis-cache /etc/nginx/sites-enabled/
sudo rm -f /etc/nginx/sites-enabled/default
Configure Redis security hardening
Apply additional security measures to the Redis systemd service and system configuration.
[Service]
Security hardening
NoNewPrivileges=true
PrivateTmp=true
PrivateDevices=true
ProtectHome=true
ProtectSystem=strict
ReadWritePaths=/var/lib/redis /var/log/redis
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
RestrictRealtime=true
RestrictSUIDSGID=true
LockPersonality=true
MemoryDenyWriteExecute=true
RestrictNamespaces=true
SystemCallFilter=@system-service
SystemCallErrorNumber=EPERM
Create systemd override directory
Create the directory for Redis service overrides if it doesn't exist.
sudo mkdir -p /etc/systemd/system/redis.service.d
Configure system limits
Set appropriate system limits for Redis and Nginx to handle high connection loads.
# Redis limits
redis soft nofile 65535
redis hard nofile 65535
redis soft memlock unlimited
redis hard memlock unlimited
Nginx limits
www-data soft nofile 65535
www-data hard nofile 65535
Configure kernel parameters
Optimize kernel parameters for Redis and Nginx performance with high connection loads.
# Redis optimizations
vm.overcommit_memory = 1
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 5000
TCP optimizations
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_intvl = 60
net.ipv4.tcp_keepalive_probes = 3
File descriptor limits
fs.file-max = 2097152
Apply kernel parameter changes
Load the new kernel parameters without requiring a reboot.
sudo sysctl -p /etc/sysctl.d/99-redis-nginx.conf
Start and enable services
Reload systemd configuration and start both Redis and Nginx services with auto-start on boot.
sudo systemctl daemon-reload
sudo systemctl enable --now redis-server
sudo systemctl enable --now nginx
Verify your setup
Test the Redis SSL connection, Nginx configuration, and cache functionality.
# Check Redis SSL connectivity
redis-cli --tls --cert /etc/redis/ssl/redis.crt --key /etc/redis/ssl/redis.key --cacert /etc/redis/ssl/redis.crt -p 6380 ping
Test Redis authentication
redis-cli --tls --cert /etc/redis/ssl/redis.crt --key /etc/redis/ssl/redis.key --cacert /etc/redis/ssl/redis.crt -p 6380 -a your_strong_redis_password_here_min_32_chars ping
Verify Nginx configuration
sudo nginx -t
Check service status
sudo systemctl status redis-server nginx
Test cache functionality
curl -H "Host: example.com" https://localhost/api/test
curl -I -H "Host: example.com" https://localhost/api/test
For more comprehensive monitoring, consider setting up Prometheus and Grafana monitoring to track cache performance metrics.
Common issues
| Symptom | Cause | Fix |
|---|---|---|
| Redis connection refused | SSL configuration error | Check certificate paths and permissions in /etc/redis/redis.conf |
| Authentication failed | Wrong Redis password | Verify password in Redis config matches Nginx upstream auth |
| Cache not working | Redis module not loaded | Ensure ngx_http_redis2_module is loaded in nginx.conf |
| Permission denied errors | Incorrect file ownership | sudo chown redis:redis /etc/redis/ssl/* and sudo chown www-data:www-data /var/cache/nginx |
| SSL handshake failure | Incompatible TLS versions | Check TLS protocol configuration in Redis and ensure client supports TLS 1.2+ |
| High memory usage | No memory limits set | Configure maxmemory and maxmemory-policy in Redis configuration |
Next steps
- Optimize Nginx caching performance with Redis backend for advanced performance tuning
- Configure Redis Sentinel with SSL/TLS encryption for high availability Redis clusters
- Setup nginx reverse proxy with SSL certificates for additional load balancing configuration
- Configure Nginx Redis cluster caching for high availability for multi-node Redis setups
- Implement Nginx SSL certificate automation with Let's Encrypt for production SSL certificates
Automated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
# Default values
DOMAIN="${1:-redis.example.com}"
REDIS_PASSWORD="${2:-$(openssl rand -base64 32)}"
# Usage message
usage() {
echo "Usage: $0 [domain] [redis_password]"
echo " domain: Domain for SSL certificate (default: redis.example.com)"
echo " redis_password: Redis authentication password (auto-generated if not provided)"
exit 1
}
log() {
echo -e "${GREEN}[INFO]${NC} $1"
}
warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
error() {
echo -e "${RED}[ERROR]${NC} $1"
exit 1
}
# Cleanup on failure
cleanup() {
warn "Installation failed. Cleaning up..."
systemctl stop redis-server 2>/dev/null || systemctl stop redis 2>/dev/null || true
systemctl stop nginx 2>/dev/null || true
rm -rf /etc/redis/ssl /var/cache/nginx/redis /var/cache/nginx/static 2>/dev/null || true
}
trap cleanup ERR
# Check if running as root
if [[ $EUID -eq 0 ]]; then
SUDO=""
else
SUDO="sudo"
if ! command -v sudo >/dev/null 2>&1; then
error "This script requires sudo or root access"
fi
fi
# Auto-detect distribution
if [ -f /etc/os-release ]; then
. /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_UPDATE="apt update && apt upgrade -y"
PKG_INSTALL="apt install -y"
REDIS_SERVICE="redis-server"
REDIS_CONFIG="/etc/redis/redis.conf"
NGINX_CONFIG_DIR="/etc/nginx/sites-available"
NGINX_ENABLED_DIR="/etc/nginx/sites-enabled"
REDIS_USER="redis"
;;
almalinux|rocky|centos|rhel|ol)
PKG_MGR="dnf"
PKG_UPDATE="dnf update -y"
PKG_INSTALL="dnf install -y"
REDIS_SERVICE="redis"
REDIS_CONFIG="/etc/redis/redis.conf"
NGINX_CONFIG_DIR="/etc/nginx/conf.d"
NGINX_ENABLED_DIR="/etc/nginx/conf.d"
REDIS_USER="redis"
;;
fedora)
PKG_MGR="dnf"
PKG_UPDATE="dnf update -y"
PKG_INSTALL="dnf install -y"
REDIS_SERVICE="redis"
REDIS_CONFIG="/etc/redis/redis.conf"
NGINX_CONFIG_DIR="/etc/nginx/conf.d"
NGINX_ENABLED_DIR="/etc/nginx/conf.d"
REDIS_USER="redis"
;;
amzn)
PKG_MGR="yum"
PKG_UPDATE="yum update -y"
PKG_INSTALL="yum install -y"
REDIS_SERVICE="redis"
REDIS_CONFIG="/etc/redis/redis.conf"
NGINX_CONFIG_DIR="/etc/nginx/conf.d"
NGINX_ENABLED_DIR="/etc/nginx/conf.d"
REDIS_USER="redis"
;;
*)
error "Unsupported distribution: $ID"
;;
esac
else
error "Cannot detect distribution. /etc/os-release not found."
fi
log "[1/10] Updating system packages..."
$SUDO $PKG_UPDATE
log "[2/10] Installing Redis and dependencies..."
case "$ID" in
ubuntu|debian)
$SUDO $PKG_INSTALL redis-server redis-tools build-essential libssl-dev pkg-config
;;
*)
$SUDO $PKG_INSTALL redis redis-devel gcc gcc-c++ make openssl-devel pkgconfig epel-release
;;
esac
log "[3/10] Installing Nginx with additional modules..."
case "$ID" in
ubuntu|debian)
$SUDO $PKG_INSTALL nginx nginx-module-njs
# Install nginx-extras for redis2 module or compile if needed
$SUDO $PKG_INSTALL nginx-extras 2>/dev/null || warn "nginx-extras not available, using base nginx"
;;
*)
$SUDO $PKG_INSTALL nginx nginx-module-njs
;;
esac
log "[4/10] Creating SSL certificates for Redis..."
$SUDO mkdir -p /etc/redis/ssl
$SUDO openssl req -x509 -nodes -newkey rsa:4096 \
-keyout /etc/redis/ssl/redis.key \
-out /etc/redis/ssl/redis.crt \
-days 365 \
-subj "/C=US/ST=State/L=City/O=Organization/CN=$DOMAIN"
log "[5/10] Setting SSL certificate permissions..."
$SUDO chown $REDIS_USER:$REDIS_USER /etc/redis/ssl/redis.key /etc/redis/ssl/redis.crt
$SUDO chmod 600 /etc/redis/ssl/redis.key
$SUDO chmod 644 /etc/redis/ssl/redis.crt
log "[6/10] Creating Redis log directory..."
$SUDO mkdir -p /var/log/redis
$SUDO chown $REDIS_USER:$REDIS_USER /var/log/redis
$SUDO chmod 755 /var/log/redis
log "[7/10] Configuring Redis with SSL and authentication..."
$SUDO cp $REDIS_CONFIG ${REDIS_CONFIG}.backup
$SUDO tee $REDIS_CONFIG > /dev/null <<EOF
# Network and SSL Configuration
port 0
tls-port 6380
tls-cert-file /etc/redis/ssl/redis.crt
tls-key-file /etc/redis/ssl/redis.key
tls-protocols "TLSv1.2 TLSv1.3"
tls-ciphersuites "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256"
tls-ciphers "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256"
# Authentication
requirepass "$REDIS_PASSWORD"
# Security Settings
protected-mode yes
bind 127.0.0.1
tcp-backlog 511
timeout 300
tcp-keepalive 300
# Memory and Performance
maxmemory 1gb
maxmemory-policy allkeys-lru
save 900 1
save 300 10
save 60 10000
# Logging
loglevel notice
logfile /var/log/redis/redis-server.log
syslog-enabled yes
syslog-ident redis
# Disable dangerous commands
rename-command FLUSHDB ""
rename-command FLUSHALL ""
rename-command KEYS ""
rename-command CONFIG "CONFIG_9f2ca1d8b5a3e7f4c6d2a8b1e5f9c3d7"
rename-command DEBUG ""
rename-command EVAL ""
rename-command SHUTDOWN SHUTDOWN_a8c2e4f6b9d1c3e5a7f2b8d4c6e9a1f3
EOF
log "[8/10] Creating Nginx cache directories..."
$SUDO mkdir -p /var/cache/nginx/redis /var/cache/nginx/static
$SUDO chown www-data:www-data /var/cache/nginx/redis /var/cache/nginx/static 2>/dev/null || \
$SUDO chown nginx:nginx /var/cache/nginx/redis /var/cache/nginx/static
$SUDO chmod 755 /var/cache/nginx/redis /var/cache/nginx/static
log "[9/10] Configuring Nginx with Redis caching..."
NGINX_CONF_FILE="$NGINX_CONFIG_DIR/redis-cache.conf"
$SUDO tee $NGINX_CONF_FILE > /dev/null <<EOF
upstream redis_backend {
server 127.0.0.1:6380;
keepalive 32;
}
proxy_cache_path /var/cache/nginx/redis levels=1:2 keys_zone=redis_cache:10m max_size=1g inactive=60m use_temp_path=off;
proxy_cache_path /var/cache/nginx/static levels=1:2 keys_zone=static_cache:10m max_size=2g inactive=24h use_temp_path=off;
server {
listen 80;
server_name $DOMAIN;
location / {
proxy_cache redis_cache;
proxy_cache_valid 200 302 10m;
proxy_cache_valid 404 1m;
proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504;
proxy_cache_revalidate on;
proxy_cache_lock on;
add_header X-Cache-Status \$upstream_cache_status;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host \$host;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto \$scheme;
}
location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg)$ {
proxy_cache static_cache;
proxy_cache_valid 200 24h;
expires 1y;
add_header Cache-Control "public, immutable";
proxy_pass http://127.0.0.1:8080;
}
}
EOF
# Enable site for Debian-based systems
if [[ "$ID" == "ubuntu" || "$ID" == "debian" ]]; then
$SUDO ln -sf $NGINX_CONF_FILE $NGINX_ENABLED_DIR/redis-cache.conf
$SUDO rm -f $NGINX_ENABLED_DIR/default
fi
log "[10/10] Starting and enabling services..."
$SUDO systemctl daemon-reload
$SUDO systemctl enable $REDIS_SERVICE nginx
$SUDO systemctl restart $REDIS_SERVICE
$SUDO systemctl restart nginx
# Verification
log "Verifying installation..."
if ! $SUDO systemctl is-active --quiet $REDIS_SERVICE; then
error "Redis service is not running"
fi
if ! $SUDO systemctl is-active --quiet nginx; then
error "Nginx service is not running"
fi
log "Installation completed successfully!"
log "Redis password: $REDIS_PASSWORD"
log "Configuration files:"
log " Redis: $REDIS_CONFIG"
log " Nginx: $NGINX_CONF_FILE"
log " SSL certificates: /etc/redis/ssl/"
warn "Please save the Redis password securely and update your application configuration"
Review the script before running. Execute with: bash install.sh