Configure Nginx Redis caching with SSL authentication and security hardening

Advanced 45 min Apr 05, 2026 1,396 views
Ubuntu 24.04 Debian 12 AlmaLinux 9 Rocky Linux 9

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
sudo dnf update -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
sudo dnf install -y redis redis-devel gcc gcc-c++ make openssl-devel pkgconfig

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
sudo dnf install -y nginx nginx-module-njs nginx-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
Never use chmod 777. It gives every user on the system full access to your files. SSL private keys should only be readable by the Redis user (600 permissions).

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

SymptomCauseFix
Redis connection refusedSSL configuration errorCheck certificate paths and permissions in /etc/redis/redis.conf
Authentication failedWrong Redis passwordVerify password in Redis config matches Nginx upstream auth
Cache not workingRedis module not loadedEnsure ngx_http_redis2_module is loaded in nginx.conf
Permission denied errorsIncorrect file ownershipsudo chown redis:redis /etc/redis/ssl/* and sudo chown www-data:www-data /var/cache/nginx
SSL handshake failureIncompatible TLS versionsCheck TLS protocol configuration in Redis and ensure client supports TLS 1.2+
High memory usageNo memory limits setConfigure maxmemory and maxmemory-policy in Redis configuration

Next steps

Automated install script

Run this to automate the entire setup

Sie möchten das nicht selbst verwalten?

Wir betreiben Infrastruktur für Unternehmen, die auf Verfügbarkeit angewiesen sind. Vollständig verwaltet, mit einem festen Ansprechpartner, der Ihre Umgebung kennt.

Sie erhalten einen festen Ansprechpartner, der Ihr Setup kennt

Rotterdam 03:56 · erreichbar per Nachricht, kein Ticketformular