Shahid Malla

Redis and OPcache for WHMCS: The Performance Setup

OPcache plus Redis cuts WHMCS page generation time by 4-6x on a busy install. Both take 30 minutes to set up. Neither requires code changes. Here is the working config.

S Shahid Malla
· Feb 9, 2026 · 7 min read · 80 views
shahidmalla.com/blog/redis-and-opcache-for-whmcs-the-performance-setup
Redis and OPcache for WHMCS: The Performance Setup
On this page (18 sections)

"WHMCS is slow" is solved by two things: OPcache and Redis. Together they cut typical page generation time by 4-6x on a busy install. Neither requires code changes. Neither requires a marketplace module. Both take 30 minutes to set up. Yet most WHMCS installs ship without either.

This is the working setup.

What OPcache and Redis actually do

OPcache is a PHP extension that caches compiled PHP bytecode in shared memory. Without it, every page request reparses every .php file from disk. WHMCS has hundreds of files; the savings are massive. OPcache is non-optional in production.

Redis is an in-memory data store. For WHMCS, it serves three purposes:

  1. Session storage — faster than the default file-based PHP sessions, plus survives traffic spikes.
  2. Application cache — many WHMCS-aware caching modules (and your own custom hooks) can store derived data here.
  3. Rate limiting + queues — if you're building advanced integrations.

OPcache caches code. Redis caches data. They're complementary; you want both.

Part 1 — OPcache setup (15 minutes)

OPcache ships with PHP. You just enable and tune it.

Edit your php.ini (or the OPcache-specific config file — varies by distro, often /etc/php.d/10-opcache.ini):

; Enable OPcache
opcache.enable = 1
opcache.enable_cli = 0           ; don't enable for CLI — saves RAM, no benefit for cron

; Memory
opcache.memory_consumption = 256
opcache.interned_strings_buffer = 16

; File count
opcache.max_accelerated_files = 20000   ; WHMCS + custom modules easily exceed default 4000

; Validation strategy
opcache.revalidate_freq = 60     ; check if files changed every 60 sec
opcache.validate_timestamps = 1  ; set to 0 only if your deploy clears OPcache explicitly

; Performance
opcache.fast_shutdown = 1
opcache.enable_file_override = 1
opcache.huge_code_pages = 0      ; usually 0 unless you've configured huge pages

Restart PHP-FPM (or Apache):

systemctl restart php-fpm
# or for cPanel
/usr/local/cpanel/scripts/restartsrv_apache_php_fpm

Verify:

php -i | grep opcache.enable
# Should show: opcache.enable => On

For more detail, install opcache-gui — a single-file PHP app that shows hit rate, memory usage, and cached file count. Aim for hit rate >95% under load.

Part 2 — Redis setup (15 minutes)

Install Redis

# RHEL / Rocky / AlmaLinux
yum install epel-release
yum install redis
systemctl enable --now redis

# Debian / Ubuntu
apt update
apt install redis-server
systemctl enable --now redis-server

# Verify
redis-cli ping
# Should respond: PONG

Configure Redis for WHMCS

Edit /etc/redis.conf (or /etc/redis/redis.conf on Debian/Ubuntu):

# Memory — size depends on your WHMCS scale
maxmemory 512mb

# Eviction policy — least-recently-used is the right choice for caching
maxmemory-policy allkeys-lru

# Persistence — for cache-only, disable to save IO
save ""
appendonly no

# Bind only to localhost unless you're running WHMCS on a different server
bind 127.0.0.1
protected-mode yes

# If WHMCS is on a different server, bind to the private IP and require a password
# bind 10.0.0.1
# requirepass strong-random-password-here

Restart Redis:

systemctl restart redis

Install the PHP Redis extension

# RHEL / Rocky / AlmaLinux
yum install php-pecl-redis

# Debian / Ubuntu
apt install php-redis

# Or via PECL for custom PHP builds
pecl install redis
echo "extension=redis.so" > /etc/php.d/40-redis.ini

# Verify
php -m | grep redis

Restart PHP-FPM after installing the extension.

Point WHMCS sessions to Redis

Edit your php.ini:

session.save_handler = redis
session.save_path = "tcp://127.0.0.1:6379"

; If you set a Redis password:
; session.save_path = "tcp://127.0.0.1:6379?auth=YOUR_PASSWORD"

Restart PHP-FPM. WHMCS now stores sessions in Redis instead of disk. You should see immediate improvement on session-heavy pages (admin panel, client area).

Caching strategy — what to cache in your custom code

Once Redis is available, your custom hooks and modules can use it directly. The pattern I use:

function getCachedClientLoyaltyTier(int $clientId): string
{
    static $redis = null;
    if ($redis === null) {
        $redis = new \Redis();
        $redis->connect('127.0.0.1', 6379);
    }

    $cacheKey = "client:loyalty:{$clientId}";
    $cached = $redis->get($cacheKey);
    if ($cached !== false) {
        return $cached;
    }

    // Expensive calculation
    $monthsActive = Capsule::table('tblclients')
        ->where('id', $clientId)
        ->value(Capsule::raw('TIMESTAMPDIFF(MONTH, datecreated, NOW())'));

    $tier = match (true) {
        $monthsActive >= 60 => 'Diamond',
        $monthsActive >= 36 => 'Platinum',
        $monthsActive >= 12 => 'Gold',
        default             => 'Silver',
    };

    $redis->setex($cacheKey, 3600, $tier);  // expire in 1 hour
    return $tier;
}

Used inside the ClientAreaPage hook (which fires on every client page load), this cuts the per-page DB query overhead substantially.

What NOT to cache

Some data must never be cached:

  • Financial state (invoices owed, account balance, ticket status).
  • Anything used for an authorization decision (permissions, role, suspended status).
  • Anything that changes in response to user actions on the same page.

Cache derived, slow-to-compute, non-authoritative data: loyalty tiers, recent activity summaries, aggregated stats. Authoritative data stays in MySQL.

How to verify everything is working

OPcache

php -r 'print_r(opcache_get_status());'
# Look at: hit_rate, num_cached_files, used_memory

After WHMCS pages have been hit a few times: hit rate >90%, used memory under your limit, no "out of memory" entries.

Redis

redis-cli info stats
# total_connections_received: should grow steadily
# keyspace_hits / keyspace_misses: ratio should improve as cache warms

redis-cli info memory
# used_memory_human: confirm it's growing but under your maxmemory

redis-cli --stat
# Live view of operations per second

WHMCS sessions in Redis

redis-cli keys "PHPREDIS_SESSION:*" | wc -l
# Should be roughly equal to concurrent WHMCS users

Page-load improvement

Measure before and after. WHMCS admin pages: open browser DevTools → Network → reload your dashboard. Compare "Server response time" (TTFB).

Typical improvement on a moderately busy install: 600-900ms → 150-300ms. Bigger improvements on slower hardware.

Going further — full WHMCS object caching

WHMCS doesn't ship native Redis object caching, but you can build it via hooks. The pattern:

  1. Use ClientAreaPage filter hook to intercept expensive queries.
  2. Check Redis first; query DB only on miss.
  3. Use InvoicePaid, ClientEdit, etc. action hooks to invalidate relevant cache keys when underlying data changes.

This is a meaningful engineering effort but pays off on installs with >10k customers. Below that, the OPcache + Redis-sessions setup above is enough.

Common pitfalls

"Redis is installed but sessions still feel slow." PHP didn't pick up the session config change. Check php -i | grep session.save_handler — should say redis. If it says files, your php.ini edit didn't apply (wrong file, didn't restart PHP-FPM).

"OPcache is enabled but hit rate is low (<50%)." opcache.max_accelerated_files is too low and OPcache is evicting recently-used files. Raise it to 20000.

"Random 'session not found' errors after enabling Redis." Redis ran out of memory and evicted active sessions. Increase maxmemory or change maxmemory-policy to volatile-lru (only evicts items with TTL set, which sessions have).

"Code changes don't appear after deploy." OPcache is caching the old version. Either:

  • Set opcache.revalidate_freq = 0 in dev (revalidate on every request — slower but accurate).
  • In production with validate_timestamps = 0, restart PHP-FPM after deploy, or call opcache_reset() programmatically.

"Redis is being accessed remotely without auth." Critical security issue. Bind only to localhost, or set a password + use TLS. Redis defaults are open by design for ease of dev; for production lock it down.

My take — order of operations

  1. Enable OPcache first. Free. Massive impact. Every install should have it.
  2. Add Redis once you exceed ~500 customers — meaningful gain for session-heavy admin areas.
  3. Skip "WHMCS speed-up" marketplace modules until you've done the above. Most of them are wrappers around what OPcache and Redis do for free.
  4. Tune MySQL aggressively too — see my system requirements guide.

Going further


I tune WHMCS deployments for performance — OPcache + Redis, MySQL config, slow-query analysis, caching strategy in custom code. If your WHMCS feels sluggish, tell me about your setup and I'll send a quote in 24 hours.

Share this article

S

Written by

Shahid Malla

WHMCS expert, full-stack developer, technical lead at Fada.cloud. 10+ years building hosting platforms, custom modules, and automation that ships.

Trusted platforms

Prefer to hire through a platform?

Not sure about working directly? Hire me through Fiverr or Upwork instead - same me, same work, with the platform's buyer protection and escrow.

Got a project like this?

Tell me what you need - I'll send a real quote within 24 hours.