Skip to main content
Tutorials

Redis Caching Guide: Setup for WordPress, Magento, and Custom Apps

How to configure Redis for object caching, session storage, and full-page cache. Step-by-step setup for WordPress, Magento 2, and custom PHP/Node applications.

Redis Caching Guide: Setup for WordPress, Magento, and Custom Apps

Every millisecond your application spends waiting on a database query is a millisecond your visitor spends staring at a blank screen. For high-traffic WordPress stores, Magento 2 catalogs, and custom-built PHP or Node applications, the single most impactful performance upgrade you can make is putting an in-memory cache layer between your application logic and your database. That cache layer is Redis.

This guide walks through what Redis actually does under the hood, how to install and harden it on Ubuntu, and then provides concrete, copy-paste configuration for WordPress, Magento 2, and custom applications in both PHP and Node.js. Every config block is production-tested on ZenoCloud managed infrastructure.

What Redis Is and Why It Matters

Redis (Remote Dictionary Server) is an open-source, in-memory data structure store. Unlike MySQL or PostgreSQL, which persist data to disk and read it back on every query, Redis keeps its entire dataset in RAM. Reads and writes happen in microseconds rather than milliseconds.

Redis supports several data structures beyond simple key-value pairs: strings, hashes, lists, sets, sorted sets, bitmaps, and streams. This versatility makes it useful for far more than basic caching. Common use cases in web hosting include:

  • Object caching — storing the results of expensive database queries so they do not need to run again on subsequent page loads.
  • Session storage — keeping user session data in memory instead of writing session files to disk, which eliminates filesystem I/O bottlenecks on busy servers.
  • Full-page caching — serving entire rendered HTML pages from memory, bypassing PHP or Node execution entirely for repeat visitors.
  • Queue backend — acting as a message broker for background job processing in Laravel, Magento, or custom queue workers.
  • Rate limiting — tracking request counts per IP or API key with automatic expiration using Redis TTL (time-to-live) values.

The performance difference is not incremental. A typical uncached WordPress page load that takes 800ms to generate from MySQL can drop to 150ms or less with Redis object caching enabled. For Magento 2 stores with thousands of SKUs, the improvement is even more dramatic because Magento’s EAV (Entity-Attribute-Value) database schema requires dozens of joins per product page.

Redis Caching Guide: Setup for WordPress, Magento, and Custom Apps — concept

Installing Redis on Ubuntu

The following steps apply to Ubuntu 22.04 and 24.04 LTS. If you are on a ZenoCloud managed server, Redis is pre-installed and tuned — skip to the application-specific section that applies to your stack.

Step 1: Install from the Official Repository

sudo apt update
sudo apt install redis-server -y

Verify the installation:

redis-server --version

You should see output similar to Redis server v=7.2.4. Confirm the service is running:

sudo systemctl status redis-server

Step 2: Configure Redis for Production

Open the Redis configuration file:

sudo nano /etc/redis/redis.conf

Apply the following changes. Each setting is explained inline.

# Bind to localhost only. Never expose Redis to the public internet.
bind 127.0.0.1 ::1

# Disable protected mode only if you have bind set correctly.
protected-mode yes

# Set a maximum memory limit. Adjust based on your server RAM.
# A good starting point is 25% of total RAM for dedicated cache servers,
# or 256-512MB on shared application servers.
maxmemory 512mb

# Set the eviction policy. allkeys-lru evicts the least recently used
# keys when maxmemory is reached. This is correct for caching workloads.
maxmemory-policy allkeys-lru

# Disable RDB snapshotting for pure cache use cases.
# If Redis is only used for caching (not as a primary data store),
# there is no need to persist data to disk.
save ""

# Disable AOF (append-only file) for pure cache use cases.
appendonly no

# Set a password. Generate a strong random string.
requirepass your-strong-redis-password-here

# Limit the number of connected clients.
maxclients 10000

# Set TCP backlog for high-connection environments.
tcp-backlog 511

Restart Redis to apply changes:

sudo systemctl restart redis-server

Test the connection with authentication:

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

You should see PONG.

Step 3: Enable Redis at Boot

sudo systemctl enable redis-server

Step 4: Kernel Tuning

For production servers handling thousands of connections, apply these kernel tweaks:

# Prevent Redis warnings about overcommit
echo "vm.overcommit_memory = 1" | sudo tee -a /etc/sysctl.conf

# Increase TCP backlog
echo "net.core.somaxconn = 65535" | sudo tee -a /etc/sysctl.conf

sudo sysctl -p

Disable Transparent Huge Pages, which causes latency spikes:

echo never | sudo tee /sys/kernel/mm/transparent_hugepage/enabled

To make this persist across reboots, add the command to /etc/rc.local or create a systemd service.

WordPress Integration

WordPress does not ship with Redis support out of the box. You need a drop-in object cache plugin and a few lines in wp-config.php.

Step 1: Install the Redis Object Cache Plugin

Install via WP-CLI (recommended on managed servers):

wp plugin install redis-cache --activate --path=/var/www/html

Or install through the WordPress admin dashboard by searching for “Redis Object Cache” by Till Kruss.

Step 2: Configure wp-config.php

Add the following lines to wp-config.php above the line that says /* That's all, stop editing! */:

/* Redis Object Cache Configuration */
define('WP_REDIS_HOST', '127.0.0.1');
define('WP_REDIS_PORT', 6379);
define('WP_REDIS_PASSWORD', 'your-strong-redis-password-here');
define('WP_REDIS_DATABASE', 0);
define('WP_REDIS_TIMEOUT', 1);
define('WP_REDIS_READ_TIMEOUT', 1);

/* Key prefix prevents collisions when multiple WordPress sites
   share the same Redis instance. Use a unique prefix per site. */
define('WP_REDIS_PREFIX', 'wp_mysite_');

/* Disable Redis cache for logged-in users if needed */
define('WP_REDIS_SELECTIVE_FLUSH', true);

/* Maximum TTL for cached objects (in seconds). 86400 = 24 hours. */
define('WP_REDIS_MAXTTL', 86400);

Step 3: Enable the Object Cache

wp redis enable --path=/var/www/html

Verify the connection:

wp redis status --path=/var/www/html

You should see Status: Connected and Client: phpredis or predis.

Step 4: Verify in the Admin Dashboard

Navigate to Settings > Redis in the WordPress admin. The status page shows hit rate, memory usage, and connection details. A healthy cache shows a hit rate above 80% after the site has been accessed a few times.

Multisite Configuration

For WordPress multisite installations, add an additional constant to isolate each sub-site:

define('WP_REDIS_PREFIX', 'wp_' . $blog_id . '_');

This prevents cache collisions between network sites sharing the same Redis instance.

Magento 2 Integration

Magento 2 supports Redis natively for three distinct purposes: default cache, page cache, and session storage. Each should be configured to use a separate Redis database number.

Step 1: Edit app/etc/env.php

Open the Magento environment configuration:

sudo nano /var/www/magento2/app/etc/env.php

Replace or add the cache and session sections:

'cache' => [
    'frontend' => [
        'default' => [
            'backend' => 'Magento\\Framework\\Cache\\Backend\\Redis',
            'backend_options' => [
                'server' => '127.0.0.1',
                'port' => '6379',
                'password' => 'your-strong-redis-password-here',
                'database' => '0',
                'compress_data' => '1',
                'compression_lib' => 'gzip',
                'preload_keys' => [
                    'EAV_ENTITY_TYPES',
                    'GLOBAL_PLUGIN_LIST',
                    'DB_IS_UP_TO_DATE',
                    'SYSTEM_DEFAULT',
                ],
            ],
        ],
        'page_cache' => [
            'backend' => 'Magento\\Framework\\Cache\\Backend\\Redis',
            'backend_options' => [
                'server' => '127.0.0.1',
                'port' => '6379',
                'password' => 'your-strong-redis-password-here',
                'database' => '1',
                'compress_data' => '0',
            ],
        ],
    ],
],
'session' => [
    'save' => 'redis',
    'redis' => [
        'host' => '127.0.0.1',
        'port' => '6379',
        'password' => 'your-strong-redis-password-here',
        'database' => '2',
        'timeout' => '2.5',
        'persistent_identifier' => '',
        'compression_threshold' => '2048',
        'compression_library' => 'gzip',
        'log_level' => '1',
        'max_concurrency' => '6',
        'break_after_frontend' => '5',
        'break_after_adminhtml' => '30',
        'first_lifetime' => '600',
        'bot_first_lifetime' => '60',
        'bot_lifetime' => '7200',
        'disable_locking' => '0',
        'min_lifetime' => '60',
        'max_lifetime' => '2592000',
    ],
],

Note the database numbers: 0 for default cache, 1 for page cache, 2 for sessions. This separation lets you flush one type of cache without affecting others.

Step 2: Flush Existing Cache

cd /var/www/magento2
bin/magento cache:flush
bin/magento cache:status

Step 3: Verify Redis Is Active

redis-cli -a your-strong-redis-password-here -n 0 DBSIZE
redis-cli -a your-strong-redis-password-here -n 1 DBSIZE
redis-cli -a your-strong-redis-password-here -n 2 DBSIZE

Each command returns the number of keys in that database. After browsing the storefront, all three databases should contain keys.

Magento Cloud and Cluster Considerations

For multi-server Magento deployments, replace 127.0.0.1 with the private IP of your Redis server. On ZenoCloud managed clusters, we configure Redis Sentinel for automatic failover. If you need a Sentinel-aware configuration, contact support for the Sentinel host list and port.

Custom Application Integration

PHP with phpredis

The phpredis extension is the fastest PHP Redis client. Install it:

sudo apt install php-redis -y
sudo systemctl restart php8.3-fpm

Basic usage pattern for caching database query results:

<?php

$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$redis->auth('your-strong-redis-password-here');

function getCachedQuery(Redis $redis, PDO $pdo, string $key, string $sql, int $ttl = 3600): array
{
    $cached = $redis->get($key);

    if ($cached !== false) {
        return json_decode($cached, true);
    }

    $stmt = $pdo->query($sql);
    $results = $stmt->fetchAll(PDO::FETCH_ASSOC);

    $redis->setex($key, $ttl, json_encode($results));

    return $results;
}

// Usage
$products = getCachedQuery(
    $redis,
    $pdo,
    'products:featured:page1',
    'SELECT * FROM products WHERE featured = 1 LIMIT 20',
    1800
);

Session storage in PHP with Redis:

; php.ini or pool-specific .conf
session.save_handler = redis
session.save_path = "tcp://127.0.0.1:6379?auth=your-strong-redis-password-here&database=3"

Node.js with ioredis

Install ioredis, the most reliable Node.js Redis client:

npm install ioredis

Caching middleware for an Express application:

const Redis = require('ioredis');
const express = require('express');

const redis = new Redis({
  host: '127.0.0.1',
  port: 6379,
  password: 'your-strong-redis-password-here',
  db: 0,
  maxRetriesPerRequest: 3,
  retryStrategy(times) {
    const delay = Math.min(times * 50, 2000);
    return delay;
  },
});

function cacheMiddleware(ttl = 3600) {
  return async (req, res, next) => {
    const key = `cache:${req.originalUrl}`;

    try {
      const cached = await redis.get(key);
      if (cached) {
        return res.json(JSON.parse(cached));
      }
    } catch (err) {
      console.error('Redis read error:', err.message);
    }

    const originalJson = res.json.bind(res);
    res.json = async (data) => {
      try {
        await redis.setex(key, ttl, JSON.stringify(data));
      } catch (err) {
        console.error('Redis write error:', err.message);
      }
      return originalJson(data);
    };

    next();
  };
}

const app = express();

app.get('/api/products', cacheMiddleware(1800), async (req, res) => {
  // Expensive database query runs only on cache miss
  const products = await db.query('SELECT * FROM products WHERE active = true');
  res.json(products);
});

app.listen(3000);

Session storage with connect-redis for Express:

const session = require('express-session');
const RedisStore = require('connect-redis').default;
const Redis = require('ioredis');

const redisClient = new Redis({
  host: '127.0.0.1',
  port: 6379,
  password: 'your-strong-redis-password-here',
  db: 4,
});

app.use(
  session({
    store: new RedisStore({ client: redisClient }),
    secret: 'your-session-secret',
    resave: false,
    saveUninitialized: false,
    cookie: {
      secure: true,
      httpOnly: true,
      maxAge: 86400000, // 24 hours in milliseconds
    },
  })
);

Redis Caching Guide: Setup for WordPress, Magento, and Custom Apps — solution

Monitoring Redis

Knowing how to inspect Redis at runtime is critical for diagnosing performance issues and capacity planning.

The INFO Command

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

This outputs a large block of metrics. The most important sections for caching are:

# Memory section
redis-cli -a your-strong-redis-password-here INFO memory

Key metrics to watch:

  • used_memory_human — current RAM usage by Redis.
  • used_memory_peak_human — highest RAM usage since the process started.
  • maxmemory — the limit you configured. If used_memory approaches this, eviction kicks in.
  • mem_fragmentation_ratio — ratio of OS-allocated memory to Redis-used memory. Values above 1.5 indicate fragmentation; a restart may help.
# Stats section
redis-cli -a your-strong-redis-password-here INFO stats

Key metrics:

  • keyspace_hits — number of successful key lookups (cache hits).
  • keyspace_misses — number of failed key lookups (cache misses).
  • Hit rate = keyspace_hits / (keyspace_hits + keyspace_misses) * 100. A healthy cache maintains a hit rate above 85%.
  • evicted_keys — number of keys removed due to maxmemory pressure. If this number climbs steadily, you need more memory or a shorter TTL.
  • connected_clients — current client connections. Compare against maxclients.

Monitoring with redis-cli —stat

For a live dashboard:

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

This prints a refreshing line every second showing keys, memory, connections, and commands per second.

Key-Level Inspection

Check how many keys exist per database:

redis-cli -a your-strong-redis-password-here INFO keyspace

Output example:

db0:keys=4523,expires=4523,avg_ttl=1423567
db1:keys=892,expires=892,avg_ttl=3012433
db2:keys=156,expires=156,avg_ttl=86234112

Find the largest keys consuming memory:

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

This scans the keyspace and reports the largest key in each data type. Run this during low-traffic periods as it performs a full scan.

SLOWLOG for Latency Issues

redis-cli -a your-strong-redis-password-here SLOWLOG GET 10

This returns the 10 most recent commands that exceeded the slowlog threshold (default: 10ms). If you see KEYS * or FLUSHALL commands in production, that is a problem.

Common Pitfalls and How to Avoid Them

1. No maxmemory Limit

Without a maxmemory setting, Redis grows without bound until it consumes all available RAM, at which point the OS OOM killer terminates it (or worse, your database). Always set maxmemory in /etc/redis/redis.conf.

2. Wrong Eviction Policy

The default eviction policy is noeviction, which returns errors when memory is full instead of evicting old keys. For caching workloads, use allkeys-lru so Redis automatically removes the least recently used keys to make room for new ones. If you mix cache data with data that must not be evicted, use volatile-lru instead and set TTL values on all cache keys.

3. Using KEYS in Production

The KEYS * command blocks the Redis server while it scans every key. On a database with millions of keys, this can freeze Redis for seconds. Use SCAN with a cursor instead:

redis-cli -a your-strong-redis-password-here SCAN 0 MATCH "wp_mysite_*" COUNT 100

4. Single Redis Instance for Everything

Running cache, sessions, and queues on the same Redis database means flushing cache also destroys user sessions. Always use separate database numbers (as shown in the Magento configuration above) or separate Redis instances for workloads that have different persistence and eviction requirements.

5. No Authentication

A Redis instance without requirepass is an open door. Attackers routinely scan for exposed Redis instances on port 6379. At minimum, set a strong password and bind to 127.0.0.1. For multi-server setups, use TLS and Redis ACLs.

6. Not Monitoring Evictions

If evicted_keys in INFO stats is growing rapidly, your cache is thrashing — keys are being evicted before they can be re-used. The fix is either to increase maxmemory, reduce TTL values to keep the working set smaller, or cache fewer low-value items.

7. Stale Cache After Deployments

After deploying new code, old cached data can cause bugs if the data format has changed. Build a cache flush step into your deployment pipeline:

# WordPress
wp cache flush --path=/var/www/html

# Magento 2
bin/magento cache:flush

# Custom -- flush a specific prefix
redis-cli -a your-strong-redis-password-here EVAL "local keys = redis.call('keys', ARGV[1]) for i=1,#keys do redis.call('del', keys[i]) end return #keys" 0 "cache:v1:*"

For the custom approach in production, prefer SCAN + DEL over KEYS + DEL to avoid blocking.

8. Ignoring Serialization Overhead

Large PHP objects serialized with serialize() and stored in Redis can be slow to encode and decode. Use json_encode/json_decode where possible — it is faster and produces smaller payloads. In Magento, enable the compress_data option (set to 1 in the config above) to gzip large cache entries.

Performance Benchmarks to Expect

After properly configuring Redis on a ZenoCloud managed server, these are typical improvements measured across customer deployments:

  • WordPress (WooCommerce, 5,000 products): TTFB drops from 650ms to 180ms. Admin dashboard loads 3x faster.
  • Magento 2 (10,000 SKUs, Luma theme): Category pages drop from 2.1s to 0.6s. Checkout completion time improves by 40%.
  • Custom PHP API (50 endpoints, PostgreSQL backend): P95 response time drops from 320ms to 45ms for cached routes.

These numbers assume Redis is running on the same server as the application (localhost) with at least 512MB of allocated memory.

Next Steps

Redis is one layer in a well-optimized hosting stack. For the best results, combine Redis caching with a properly tuned PHP-FPM pool, database query optimization, a CDN for static assets, and HTTP/2 or HTTP/3 at the edge.

If you are running a high-traffic WordPress or Magento store on ZenoCloud infrastructure and want Redis tuned specifically for your workload, open a support ticket. Our engineering team configures Redis as part of every managed hosting plan — including memory allocation, eviction policy selection, and monitoring integration with our alerting stack.

Need help with this?

We manage servers, cloud, and security so you can focus on building.

Learn more