Server-Side Caching

Server-Side Caching on DomainIndia: Redis, Memcached, Varnish, and OPcache

By Domain India Team · DomainIndia EngineeringPublished · Updated 6 min read
Knowledge base article
Contents (13 sections)
TL;DR

Caching turns a 500ms database query into a 1ms memory lookup. This guide covers the four server-side caching layers you should understand — OPcache (PHP bytecode), Memcached/Redis (data cache), Varnish (HTTP response cache) — and when to use each on DomainIndia hosting.

The four caching layers

Your web stack has four places to cache, from fastest to slowest:

LayerCachesRead timeWhere
OPcachePHP bytecode<0.01 msBuilt into PHP, on every plan
APCuPHP user data (in-process)<0.1 msPHP extension, usually enabled
Redis / MemcachedAny data (across processes)0.5–1 msSeparate process, shared
Varnish / CloudflareFull HTTP responses5–20 ms (cache hit)In front of your app

Use all of them together for a well-tuned stack.

Layer 1 — OPcache (PHP)

PHP compiles every file to bytecode on every request. OPcache stores the compiled version in memory so PHP skips parsing.

Impact: 2–3× speedup on PHP apps. Non-negotiable on production.

On DomainIndia cPanel/DirectAdmin, OPcache is enabled by default on PHP 7.4+. Verify via php -i | grep opcache.enableOpcache.enable => On.

Tuning (in cPanel → MultiPHP INI Editor, or .user.ini):

ini
opcache.enable=1
opcache.memory_consumption=256         ; MB — more = more files cached
opcache.max_accelerated_files=20000    ; number of PHP files
opcache.validate_timestamps=1          ; check file changes (set 0 in production + release restart)
opcache.revalidate_freq=2              ; seconds between checks
opcache.jit=1255                       ; PHP 8+ JIT (tracing mode)
opcache.jit_buffer_size=64M

For Laravel/Symfony deployments: run php artisan opcache:clear (or similar) in deploy hook — otherwise OPcache serves old bytecode.

See our PHP OPcache Configuration article for deep details.

Layer 2 — APCu

In-memory key-value cache local to each PHP process. Good for small hot data — feature flags, config arrays, rate-limit counters.

php
apcu_store('flag_new_checkout', true, 300);   // 300s TTL
if (apcu_fetch('flag_new_checkout')) { /* new checkout */ }

Limits:

  • Not shared across servers / across PHP-FPM pools cleanly
  • Cleared on PHP-FPM reload
  • Memory bound per-process

For shared-across-server caching, use Redis/Memcached instead.

Layer 3 — Redis or Memcached

External in-memory store. Multi-process, multi-server, persistent (Redis).

On DomainIndia hosting:

PlanRedis available?Memcached available?
Shared cPanelYes (local socket, shared instance)Yes
Shared DirectAdminAsk supportYes
VPSInstall yourself (1 command)Install yourself
App PlatformAdd Redis as a service

Redis — use cases

  • Session storage (Laravel/Rails/PHP sessions)
  • Queue backend (Laravel Queues, Sidekiq, BullMQ)
  • Rate limiting (atomic INCR with expiry)
  • Full-page cache
  • Real-time features (pub/sub)
  • Leaderboards (sorted sets)

Redis is the modern default — richer data types, persistence, pub/sub. Memcached is strict key-value only but slightly faster for pure lookups.

Redis example — PHP

php
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);

$cached = $redis->get('user:42:profile');
if (!$cached) {
    $profile = expensiveQuery();
    $redis->setex('user:42:profile', 300, json_encode($profile));
    return $profile;
}
return json_decode($cached, true);

Redis example — Node.js

javascript
import { createClient } from 'redis';
const redis = createClient();
await redis.connect();

const cached = await redis.get(`user:${id}:profile`);
if (cached) return JSON.parse(cached);

const profile = await db.user.findUnique({ where: { id } });
await redis.setEx(`user:${id}:profile`, 300, JSON.stringify(profile));
return profile;

Install Redis on VPS

bash
# AlmaLinux / Rocky
sudo dnf install -y redis
sudo systemctl enable --now redis
redis-cli ping   # expect PONG

# Enable persistence (AOF)
sudo sed -i 's/^appendonly no/appendonly yes/' /etc/redis/redis.conf
sudo systemctl restart redis

Layer 4 — Varnish / HTTP cache

Varnish sits in front of your app, caches full HTTP responses based on Cache-Control headers. Far less common in 2026 — Cloudflare/Fastly cover this with less operational burden.

On shared hosting: Varnish isn't available. Use Cloudflare's edge cache instead — same result, zero config.

On VPS: Varnish is fine if you have specific needs (custom VCL rules, no Cloudflare dependency). Setup:

bash
sudo dnf install -y varnish
# Edit /etc/varnish/default.vcl — proxy to your app on port 8080
sudo systemctl enable --now varnish

For most users: skip Varnish. Let Cloudflare handle HTTP-layer caching. Focus on Redis/OPcache.

Cache invalidation strategies

"There are only two hard things in Computer Science: cache invalidation and naming things."

Three patterns:

1. TTL-only (easy, eventually stale)

  • Set a short TTL (30–300s)
  • Accept stale reads for that window

2. Explicit invalidation (correct, more code)

  • When data changes, delete cache key
  • Example: on updateUser(42), redis.del('user:42:profile')

3. Tags (elegant, complex)

  • Tag cached entries: user:42:profile tagged with user:42
  • On change, invalidate all entries with tag user:42
  • Laravel Cache supports this natively (Cache::tags(['users'])->put(...))

For most apps: TTL-only for read-heavy data (feeds, product catalogs), explicit invalidation for user-specific (profile, cart).

Measuring cache effectiveness

Without measurement, you're guessing.

Redis: redis-cli INFO statskeyspace_hits vs keyspace_misses. Ratio tells you hit rate.

Cloudflare: Dashboard → Analytics → Cache. Look for CF-Cache-Status: HIT ratio.

App-level: log cache HIT/MISS to your logger. Aggregate in Grafana.

Good targets:

  • Redis hit rate > 80%
  • Cloudflare HTML cache hit > 50% (for cacheable pages)
  • OPcache hit rate > 99%

Common pitfalls

Cache stampede
cache expires; 1000 concurrent requests all hit DB simultaneously. Use cache-aside with SETNX lock, or "probabilistic early expiration".
Memory exhaustion
Redis fills up, evicts data. Set maxmemory + maxmemory-policy allkeys-lru.
Cached stale responses after deploy
OPcache doesn't see new files. Run opcache_reset() or php artisan opcache:clear in deploy hook.
Serialising large objects
don't cache 100 MB blobs in Redis. Cache a small summary; fetch big data from object storage.
Cache keys with leaked PII
user_email:[email protected] → search logs expose emails. Hash or prefix keys.
Shared Redis without prefixing
two apps sharing Redis DB step on each other. Use prefix: myapp:user:42.

FAQ

Redis or Memcached — which?

Redis, almost always. Richer data types, persistence, pub/sub. Memcached only if you have a specific reason (pure-simplicity key-value, legacy systems).

Can I use Redis on shared hosting?

On our cPanel shared plans, yes — a shared Redis instance is available via Unix socket. Check with support for connection string. For DirectAdmin, confirm with our support team.

Do I need Varnish if I'm on Cloudflare?

No. Cloudflare's edge cache does everything Varnish does + free DDoS + global CDN. Varnish is only for special cases (custom VCL rules, on-prem requirements).

How do I cache database query results in Laravel?

Cache::remember('users.active', 300, fn() => User::where('active', true)->get()). Laravel picks Redis automatically if configured.

Cache everything vs cache nothing — where to start?

Measure slowest endpoints first (application logs or APM). Cache the top 3 slowest reads. Iterate. Premature caching adds complexity without measurable gain.

Need Redis / Memcached at scale? VPS with root access gives you full control. View VPS plans

Was this article helpful?

Your answer helps us decide what to improve next.

Still need help? Open a support ticket and our team will reply.

Prefer an app? Add this site to your home screen.Get the app
Server-Side Caching on DomainIndia — Redis, Memcached, Varnish, OPcache