Redis is an open-source, in-memory data structure store that functions as a database, cache, message broker, and streaming engine. Its ability to serve data directly from RAM makes it extraordinarily fast, with typical response times under one millisecond. This guide walks you through deploying Redis on Ubuntu Server, configuring it for production workloads, securing it against common threats, and monitoring its performance with built-in tools.

Prerequisites

Before you begin, make sure you have:

  • Ubuntu Server 20.04, 22.04, or 24.04
  • Terminal access with sudo privileges
  • At least 1 GB of available RAM (more for production datasets)
  • Basic familiarity with the Linux command line
  • A firewall configured to restrict access (see our UFW guide)

What Is Redis?

Redis stands for Remote Dictionary Server. Created by Salvatore Sanfilippo in 2009, it has grown into one of the most widely used in-memory data stores in the world. Unlike traditional databases that read and write to disk, Redis keeps the entire dataset in memory, which allows it to deliver sub-millisecond latency for both read and write operations.

Key characteristics of Redis:

  • In-memory storage — all data lives in RAM for maximum speed
  • Rich data structures — supports strings, hashes, lists, sets, sorted sets, streams, and more
  • Optional persistence — can write data to disk for durability
  • Replication — supports master-replica architecture for high availability
  • Atomic operations — all commands are executed atomically
  • Pub/Sub messaging — built-in publish/subscribe system for real-time communication
  • Lua scripting — execute server-side scripts for complex operations

Redis Use Cases

Redis excels in scenarios where speed is critical:

Caching layer: Place Redis between your application and primary database to serve frequently requested data from memory. This reduces database load and improves response times dramatically.

Session storage: Store user sessions in Redis instead of disk-based stores. This enables session sharing across multiple application servers and provides fast read/write access.

Message queues: Use Redis lists or streams as lightweight message queues for asynchronous task processing. Workers can consume messages reliably using blocking pops or consumer groups.

Pub/Sub messaging: Broadcast real-time events to multiple subscribers. Common for chat applications, live notifications, and real-time dashboards.

Rate limiting: Implement API rate limiting using Redis counters with automatic expiration. The atomic increment and TTL features make this straightforward.

Leaderboards and rankings: Sorted sets provide natural support for ranked data with O(log N) insertion and retrieval by score.

Installing Redis on Ubuntu

The recommended approach is to install Redis from the official APT repository to get the latest stable version.

Add the Official Redis Repository

sudo apt update
sudo apt install -y lsb-release curl gpg
curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/redis.list
sudo apt update

Install Redis

sudo apt install -y redis-server

Verify the Installation

redis-cli ping

You should receive:

PONG

Check the installed version:

redis-server --version

Check the service status:

sudo systemctl status redis-server

Enable Redis to start on boot:

sudo systemctl enable redis-server

Configuration Basics

The main Redis configuration file is located at /etc/redis/redis.conf. Before making changes, create a backup:

sudo cp /etc/redis/redis.conf /etc/redis/redis.conf.backup

Open the configuration file:

sudo nano /etc/redis/redis.conf

Network Binding

By default, Redis binds to 127.0.0.1 (localhost only). For a caching layer accessed by local applications, this is the safest setting:

bind 127.0.0.1 ::1

If remote clients need access, add the server’s private IP:

bind 127.0.0.1 192.168.1.100

Warning: Never bind Redis to 0.0.0.0 on a public-facing server without proper authentication and firewall rules. Exposed Redis instances are a frequent target for automated attacks.

Port Configuration

The default port is 6379. Change it if you want to reduce automated scanning:

port 6379

Maximum Memory

Set a hard memory limit to prevent Redis from consuming all system RAM:

maxmemory 256mb

Adjust this value based on your server’s available memory. A common rule is to allocate no more than 75% of total RAM to Redis if it is the primary workload on the server.

Eviction Policies

When Redis reaches the maxmemory limit, it uses an eviction policy to decide which keys to remove. Set the policy with:

maxmemory-policy allkeys-lru

Available eviction policies:

PolicyDescription
noevictionReturn errors when memory limit is reached (default)
allkeys-lruEvict least recently used keys from all keys
allkeys-lfuEvict least frequently used keys from all keys
volatile-lruEvict least recently used keys with an expiration set
volatile-lfuEvict least frequently used keys with an expiration set
allkeys-randomEvict random keys from all keys
volatile-randomEvict random keys with an expiration set
volatile-ttlEvict keys with the nearest expiration time

For a general-purpose cache, allkeys-lru is the most common choice. For workloads where access frequency matters more than recency, use allkeys-lfu.

After modifying the configuration, restart Redis:

sudo systemctl restart redis-server

Persistence Options

Redis provides two mechanisms to persist data to disk.

RDB Snapshots

RDB creates point-in-time snapshots at configured intervals. This is enabled by default:

save 3600 1 300 100 60 10000

This means:

  • Save if at least 1 key changed in 3600 seconds (1 hour)
  • Save if at least 100 keys changed in 300 seconds (5 minutes)
  • Save if at least 10000 keys changed in 60 seconds (1 minute)

The snapshot file is stored at:

dbfilename dump.rdb
dir /var/lib/redis

Advantages of RDB:

  • Compact single-file representation of your data
  • Perfect for backups and disaster recovery
  • Minimal performance impact during normal operations
  • Faster restarts compared to AOF

Disadvantages of RDB:

  • Data loss between snapshots (up to several minutes)
  • Fork operation can be slow on large datasets

AOF (Append Only File)

AOF logs every write operation for better durability:

appendonly yes
appendfilename "appendonly.aof"

Configure the sync policy:

# appendfsync always   # Sync after every write (safest, slowest)
appendfsync everysec    # Sync once per second (recommended)
# appendfsync no        # Let the OS handle syncing (fastest, least safe)

Advantages of AOF:

  • Better durability (at most 1 second of data loss with everysec)
  • Append-only format is corruption-resistant
  • Automatically rewrites to compact the log

Disadvantages of AOF:

  • Larger file size compared to RDB
  • Slower restarts for large datasets

Using Both

For maximum data safety, enable both RDB and AOF:

save 3600 1 300 100 60 10000
appendonly yes
appendfsync everysec

When both are enabled, Redis uses the AOF file to restore data on startup since it is typically more complete.

Security Hardening

An unsecured Redis instance is a significant security risk. Apply the following measures for production deployments.

Set a Password

Configure authentication with a strong password:

requirepass your-very-strong-password-here

Clients must authenticate before running commands:

redis-cli
AUTH your-very-strong-password-here

Or connect with the password inline:

redis-cli -a your-very-strong-password-here

Rename Dangerous Commands

Disable or rename commands that could cause damage:

rename-command FLUSHDB ""
rename-command FLUSHALL ""
rename-command DEBUG ""
rename-command CONFIG "ADMIN_CONFIG_b4f8e2a1"

Setting a command to an empty string "" disables it entirely. Renaming it to a long random string makes it accessible only to administrators who know the new name.

Restrict Network Access

Always bind Redis to specific interfaces and use a firewall:

bind 127.0.0.1 192.168.1.100
protected-mode yes

Add a UFW rule to restrict Redis access:

sudo ufw allow from 192.168.1.0/24 to any port 6379

Enable TLS (Redis 6+)

For encrypted connections, configure TLS:

tls-port 6380
port 0
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

Generate certificates for testing:

sudo mkdir -p /etc/redis/tls
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
  -keyout /etc/redis/tls/redis.key \
  -out /etc/redis/tls/redis.crt \
  -subj "/CN=redis-server"
sudo cp /etc/redis/tls/redis.crt /etc/redis/tls/ca.crt
sudo chown redis:redis /etc/redis/tls/*

Connect with TLS:

redis-cli --tls --cert /etc/redis/tls/redis.crt --key /etc/redis/tls/redis.key --cacert /etc/redis/tls/ca.crt -p 6380

Disable the Default User (Redis 6+ ACLs)

Redis 6 introduced Access Control Lists for fine-grained permissions:

redis-cli
ACL SETUSER admin on >strong-password ~* +@all
ACL SETUSER default off

This creates an admin user with full access and disables the default user.

Data Types and Operations

Redis supports several data structures, each optimized for specific use cases.

Strings

The most basic type. Store text, numbers, or serialized data:

SET user:1:name "Alice"
GET user:1:name
# "Alice"

SET counter 100
INCR counter
# 101

SET session:abc123 "session_data" EX 3600
# Expires in 3600 seconds

Hashes

Store objects as field-value pairs:

HSET user:1 name "Alice" email "alice@example.com" age 30
HGET user:1 name
# "Alice"

HGETALL user:1
# 1) "name"
# 2) "Alice"
# 3) "email"
# 4) "alice@example.com"
# 5) "age"
# 6) "30"

Lists

Ordered collections (linked lists) ideal for queues:

LPUSH tasks "send_email"
LPUSH tasks "process_payment"
RPOP tasks
# "send_email"

LRANGE tasks 0 -1
# 1) "process_payment"

Sets

Unordered collections of unique elements:

SADD tags:post:1 "redis" "caching" "nosql"
SMEMBERS tags:post:1
# 1) "redis"
# 2) "caching"
# 3) "nosql"

SISMEMBER tags:post:1 "redis"
# 1

Sorted Sets

Sets ordered by a score, perfect for leaderboards:

ZADD leaderboard 100 "player1" 250 "player2" 175 "player3"
ZREVRANGE leaderboard 0 -1 WITHSCORES
# 1) "player2"
# 2) "250"
# 3) "player3"
# 4) "175"
# 5) "player1"
# 6) "100"

ZRANK leaderboard "player3"
# 1

Memory Management and Eviction Policies

Effective memory management is critical for Redis performance and stability.

Monitoring Memory Usage

redis-cli INFO memory

Key metrics to watch:

MetricDescription
used_memoryTotal bytes allocated by Redis
used_memory_humanHuman-readable used memory
used_memory_rssResident Set Size (actual RAM used)
used_memory_peakPeak memory usage
mem_fragmentation_ratioRatio of RSS to used_memory

A mem_fragmentation_ratio significantly above 1.5 indicates memory fragmentation. Values below 1.0 mean Redis is swapping to disk, which severely degrades performance.

Reducing Memory Usage

Use shorter key names where practical:

# Instead of
SET user:session:authentication:token:abc123 "data"

# Use
SET u:s:t:abc123 "data"

Set TTL on cached keys to ensure stale data is removed:

SET cache:product:42 "product_data" EX 300

Use hashes for small objects — Redis optimizes small hashes with ziplist encoding:

HSET user:1 name "Alice" email "alice@example.com"

Enable lazy freeing to avoid blocking during large key deletions:

lazyfree-lazy-eviction yes
lazyfree-lazy-expire yes
lazyfree-lazy-server-del yes

Memory Defragmentation (Redis 4+)

Enable active defragmentation to reclaim fragmented memory:

activedefrag yes
active-defrag-ignore-bytes 100mb
active-defrag-threshold-lower 10
active-defrag-threshold-upper 100

Monitoring with redis-cli and INFO Command

Redis provides several built-in tools for monitoring.

The INFO Command

The INFO command returns comprehensive server information:

redis-cli INFO

Request specific sections:

redis-cli INFO server
redis-cli INFO memory
redis-cli INFO stats
redis-cli INFO replication
redis-cli INFO clients
redis-cli INFO keyspace

Real-Time Monitoring

Watch all commands processed by Redis in real time:

redis-cli MONITOR

Caution: The MONITOR command introduces overhead and should not be left running in production. Use it for debugging sessions only.

Slow Log

Identify commands that exceed a specified execution time:

redis-cli SLOWLOG GET 10

Configure the slow log threshold (in microseconds):

slowlog-log-slower-than 10000
slowlog-max-len 128

This logs any command taking longer than 10 milliseconds.

Client Connections

List all connected clients:

redis-cli CLIENT LIST

Check the total number of connections:

redis-cli INFO clients

Key client metrics:

connected_clients:15
blocked_clients:0
maxclients:10000

Latency Monitoring

Enable latency monitoring and measure it:

redis-cli CONFIG SET latency-monitor-threshold 100
redis-cli LATENCY LATEST
redis-cli LATENCY HISTORY event-name

Redis as a Session Store

Redis is an excellent choice for storing application sessions, enabling session sharing across multiple servers.

Node.js Example with Express

const express = require('express');
const session = require('express-session');
const RedisStore = require('connect-redis').default;
const { createClient } = require('redis');

const redisClient = createClient({
  url: 'redis://127.0.0.1:6379',
  password: 'your-redis-password'
});
redisClient.connect();

const app = express();

app.use(session({
  store: new RedisStore({ client: redisClient }),
  secret: 'your-session-secret',
  resave: false,
  saveUninitialized: false,
  cookie: {
    secure: true,
    httpOnly: true,
    maxAge: 1800000 // 30 minutes
  }
}));

app.get('/', (req, res) => {
  req.session.views = (req.session.views || 0) + 1;
  res.send(`Views: ${req.session.views}`);
});

app.listen(3000, () => console.log('Server running on port 3000'));

Python Example with Flask

from flask import Flask, session
from flask_session import Session
import redis

app = Flask(__name__)
app.config['SESSION_TYPE'] = 'redis'
app.config['SESSION_REDIS'] = redis.Redis(
    host='127.0.0.1',
    port=6379,
    password='your-redis-password'
)
app.config['SESSION_PERMANENT'] = True
app.config['PERMANENT_SESSION_LIFETIME'] = 1800  # 30 minutes

Session(app)

@app.route('/')
def index():
    session['views'] = session.get('views', 0) + 1
    return f"Views: {session['views']}"

if __name__ == '__main__':
    app.run()

Essential redis-cli Commands Reference

CommandDescription
redis-cli pingTest server connectivity
redis-cli INFODisplay server information and statistics
redis-cli INFO memoryDisplay memory usage details
redis-cli MONITORWatch all commands in real time
redis-cli DBSIZEReturn the number of keys in the current database
redis-cli KEYS patternFind keys matching a pattern (use with caution in production)
redis-cli SCAN 0 MATCH pattern COUNT 100Iteratively scan keys (production-safe alternative to KEYS)
redis-cli SET key value EX secondsSet a key with expiration
redis-cli GET keyRetrieve the value of a key
redis-cli DEL keyDelete one or more keys
redis-cli TTL keyCheck remaining time-to-live of a key
redis-cli EXPIRE key secondsSet a timeout on a key
redis-cli FLUSHDBRemove all keys from the current database
redis-cli SLOWLOG GET 10View the 10 most recent slow queries
redis-cli CLIENT LISTList all connected clients
redis-cli CONFIG GET maxmemoryRetrieve a configuration parameter
redis-cli CONFIG SET maxmemory 512mbChange a configuration parameter at runtime
redis-cli BGSAVETrigger a background RDB snapshot
redis-cli BGREWRITEAOFTrigger an AOF rewrite
redis-cli SHUTDOWN SAVEStop the server and save data to disk

Troubleshooting

Redis Fails to Start

Check the logs for errors:

sudo journalctl -u redis-server -n 50
sudo cat /var/log/redis/redis-server.log

Common causes:

  • Syntax error in redis.conf — validate the configuration file
  • Port already in use — check with sudo ss -tlnp | grep 6379
  • Insufficient memory — verify available RAM with free -h

High Memory Usage

redis-cli INFO memory
redis-cli MEMORY DOCTOR

If mem_fragmentation_ratio is above 1.5:

  • Enable active defragmentation
  • Restart Redis to reclaim fragmented memory

If used_memory is near maxmemory:

  • Review and adjust the eviction policy
  • Set TTL values on cache keys
  • Increase the maxmemory limit

Connection Refused Errors

Verify Redis is listening on the expected interface:

sudo ss -tlnp | grep redis

Check the bind directive in redis.conf and ensure your firewall allows connections:

sudo ufw status | grep 6379

Slow Performance

Investigate with the slow log:

redis-cli SLOWLOG GET 25

Check for large keys that may be blocking:

redis-cli --bigkeys

Avoid using KEYS * in production. Use SCAN instead:

redis-cli SCAN 0 MATCH "user:*" COUNT 100

Persistence Errors

If RDB snapshots fail:

redis-cli INFO persistence

Look for rdb_last_bgsave_status:err. Common fixes:

  • Ensure the Redis data directory is writable: sudo chown redis:redis /var/lib/redis
  • Verify sufficient disk space: df -h /var/lib/redis
  • Check overcommit settings: sudo sysctl vm.overcommit_memory=1

Summary

Redis is a powerful in-memory data store that can dramatically improve your application’s performance when used as a caching layer, session store, or message broker. By properly configuring memory limits, eviction policies, persistence, and security settings, you can run Redis reliably in production environments.

Key takeaways:

  • Install Redis from the official repository for the latest stable version
  • Always set maxmemory and an appropriate eviction policy to prevent uncontrolled memory growth
  • Choose your persistence strategy based on durability requirements — RDB for periodic snapshots, AOF for near-real-time durability, or both
  • Harden Redis with password authentication, network binding restrictions, and renamed dangerous commands
  • Monitor performance with INFO, SLOWLOG, and redis-cli --bigkeys to catch issues early
  • Use SCAN instead of KEYS in production to avoid blocking the server

For a comprehensive server security setup, see our guides on UFW Firewall Configuration and the Linux Server Security Checklist.