? '127.0.0.1';
$port = (int) ($_ENV['REDIS_PORT'] ?? 6379);
$timeout = 2.0;
$socket = @stream_socket_client(
"tcp://{$host}:{$port}",
$errno,
$errstr,
$timeout
);
if (!$socket) {
http_response_code(503);
exit("Cache backend unreachable: {$errstr} (Code: {$errno})");
}
fwrite($socket, "PING\r\n");
$response = fgets($socket, 512);
fclose($socket);
if (trim($response) === '+PONG') {
http_response_code(200);
exit("Cache backend operational. Latency: " . number_format(microtime(true) - $_SERVER['REQUEST_TIME_FLOAT'], 4) . "s");
}
http_response_code(500);
exit("Unexpected cache response: " . trim($response));
Run this script via CLI or a temporary web endpoint. A `+PONG` response confirms the daemon is alive. If you receive `Connection refused` or `Operation timed out`, the issue is either a stopped service or a network binding mismatch. Check `/etc/redis/redis.conf` for the `bind` directive. If it is restricted to `127.0.0.1` and your application connects via a private LAN IP or hostname, the handshake will fail regardless of WordPress configuration.
### Step 2: Align Authentication & Database Indexing
Redis supports multiple logical databases (indexed 0β15 by default) and optional password authentication. Mismatches here are the second most common cause of connection failures. Instead of hardcoding values directly into `wp-config.php`, implement an environment-driven configuration loader that maps deployment variables to the required plugin constants.
```php
<?php
// cache-config-loader.php
$required_env = [
'CACHE_HOST' => '127.0.0.1',
'CACHE_PORT' => 6379,
'CACHE_DB_INDEX' => 0,
'CACHE_TIMEOUT' => 1.0,
'CACHE_READ_TOUT'=> 1.0
];
foreach ($required_env as $env_key => $default) {
$value = getenv($env_key) ?: $default;
if ($env_key === 'CACHE_PORT' || $env_key === 'CACHE_DB_INDEX') {
$value = (int) $value;
}
putenv("{$env_key}={$value}");
}
// Map to plugin-expected constants
define('WP_REDIS_HOST', getenv('CACHE_HOST'));
define('WP_REDIS_PORT', (int) getenv('CACHE_PORT'));
define('WP_REDIS_DATABASE', (int) getenv('CACHE_DB_INDEX'));
define('WP_REDIS_TIMEOUT', (float) getenv('CACHE_TIMEOUT'));
define('WP_REDIS_READ_TIMEOUT', (float) getenv('CACHE_READ_TOUT'));
$cache_pass = getenv('CACHE_AUTH_TOKEN');
if ($cache_pass !== false && strlen($cache_pass) > 0) {
define('WP_REDIS_PASSWORD', $cache_pass);
}
This pattern isolates credentials from version control, supports multi-environment deployments, and centralizes timeout configuration. The WP_REDIS_TIMEOUT controls the initial TCP handshake, while WP_REDIS_READ_TIMEOUT governs how long the PHP process waits for a response after sending a command. Separating these prevents slow Redis operations from blocking PHP-FPM workers indefinitely.
The caching plugin requires a backend driver to serialize and transmit commands. You have two production-ready options:
- phpredis: A compiled C extension. Offers connection pooling, lower memory footprint, and faster serialization. Requires server-level installation (
pecl install redis or OS package manager).
- Predis: A pure-PHP library. Zero compilation required, but executes entirely within the PHP interpreter, increasing CPU utilization under high concurrency.
To explicitly declare the driver without relying on auto-detection, inject the following into your configuration loader:
$preferred_driver = getenv('CACHE_DRIVER') ?: 'phpredis';
define('WP_REDIS_CLIENT', $preferred_driver);
If phpredis is unavailable and you force the plugin to use it, the connection will fail silently or throw a fatal error. Always verify driver availability before deployment.
Step 4: Implement Graceful Degradation
Strict cache failures should never take down a production site. The caching plugin uses a drop-in file (wp-content/object-cache.php) to intercept WordPress caching calls. If the backend becomes unreachable, you can bypass the plugin entirely by renaming this file. However, a more robust approach is to configure the plugin to allow fallback behavior.
Most modern caching plugins support a WP_REDIS_DISABLE_BANNERS or WP_REDIS_GRACEFUL constant. When enabled, the plugin logs connection failures to debug.log instead of halting execution, allowing WordPress to revert to its native WP_Object_Cache class. This ensures the site remains functional while your monitoring stack alerts you to the infrastructure issue.
Pitfall Guide
1. Localhost Assumption on Managed Infrastructure
Explanation: Developers frequently set WP_REDIS_HOST to 127.0.0.1 on managed platforms where Redis runs on a dedicated caching node or container. The TCP handshake fails because the application server cannot route to the loopback address of a different machine.
Fix: Query the hosting control panel or environment variables for the actual Redis endpoint. Use private network IPs or internal DNS names instead of loopback addresses.
2. Credential Rotation Without Config Sync
Explanation: Managed hosts and container orchestration platforms often rotate Redis passwords automatically for security compliance. If WP_REDIS_PASSWORD is hardcoded in wp-config.php, authentication fails after rotation.
Fix: Store credentials in environment variables or a secrets manager. Inject them at runtime using the configuration loader pattern shown above.
3. Ignoring Read Timeout Boundaries
Explanation: Setting only WP_REDIS_TIMEOUT controls the initial connection, but not how long PHP waits for data retrieval. Slow Redis operations (e.g., large key deletions, persistence forks) can hang PHP-FPM workers.
Fix: Always configure both WP_REDIS_TIMEOUT and WP_REDIS_READ_TIMEOUT. Set read timeouts to 1.0β2.0 seconds for standard workloads. Monitor slowlog in Redis to identify commands exceeding these thresholds.
4. Database Index Collision
Explanation: Redis uses logical databases indexed 0β15. If multiple applications share the same Redis instance and use index 0 by default, cache keys collide, causing data corruption or unexpected cache invalidation.
Fix: Assign a unique WP_REDIS_DATABASE index per application. Document the mapping in your infrastructure runbook. Avoid using index 0 for production WordPress sites.
5. Relying on Predis in High-Concurrency Environments
Explanation: Predis executes entirely in PHP. Under sustained traffic (>500 req/s), the interpreter overhead increases CPU load, causing request queuing and elevated TTFB.
Fix: Deploy phpredis for production. Use Predis only in staging, development, or environments where server-level extension installation is restricted.
6. Missing Systemd Auto-Restart Configuration
Explanation: On self-hosted VPS environments, Redis may stop after a kernel update or OOM kill. Without automatic restart policies, WordPress encounters persistent connection failures until manual intervention.
Fix: Configure Restart=always and RestartSec=5 in the Redis systemd unit file. Verify with systemctl daemon-reload and test failure recovery using systemctl stop redis.
7. Treating the Drop-In File as Optional
Explanation: The object-cache.php file in wp-content/ is not a standard plugin. It is a WordPress drop-in that overrides the core caching class. Deleting it breaks the integration entirely, but leaving a corrupted version causes fatal errors.
Fix: Never manually edit the drop-in. If the plugin fails to install it correctly, reinstall via WP-CLI: wp plugin install redis-cache --activate. Verify file integrity with checksums if deployment pipelines modify wp-content/.
Production Bundle
Action Checklist
Decision Matrix
| Scenario | Recommended Approach | Why | Cost Impact |
|---|
| Shared hosting with no SSH access | Predis + Graceful Fallback | No compiled extensions allowed; fallback prevents downtime | Low (CPU overhead) |
| High-traffic production site | phpredis + Unix Socket | Lowest latency, highest throughput, reduced TCP overhead | Medium (requires server config) |
| Multi-tenant Redis instance | Dedicated DB Index + Unique Prefix | Prevents cache pollution and key collisions across apps | None |
| Containerized/Kubernetes deployment | Environment-driven config + Health probes | Supports dynamic credential rotation and automated scaling | Low (infrastructure complexity) |
| Development/Local environment | Native WP_Object_Cache or Predis | Zero setup overhead; matches local database performance | None |
Configuration Template
<?php
/**
* Production-Ready Redis Cache Configuration Loader
* Place in wp-content/mu-plugins/ or include before wp-config.php
*/
// 1. Load environment variables with secure defaults
$cache_config = [
'host' => getenv('REDIS_CACHE_HOST') ?: '127.0.0.1',
'port' => (int) (getenv('REDIS_CACHE_PORT') ?: 6379),
'database' => (int) (getenv('REDIS_CACHE_DB') ?: 2),
'timeout' => (float) (getenv('REDIS_CACHE_TIMEOUT') ?: 1.0),
'read_tout'=> (float) (getenv('REDIS_CACHE_READ_TIMEOUT') ?: 1.0),
'prefix' => getenv('REDIS_CACHE_PREFIX') ?: 'wp_prod_',
'driver' => getenv('REDIS_CACHE_DRIVER') ?: 'phpredis'
];
// 2. Map to plugin constants
define('WP_REDIS_HOST', $cache_config['host']);
define('WP_REDIS_PORT', $cache_config['port']);
define('WP_REDIS_DATABASE', $cache_config['database']);
define('WP_REDIS_TIMEOUT', $cache_config['timeout']);
define('WP_REDIS_READ_TIMEOUT', $cache_config['read_tout']);
define('WP_REDIS_PREFIX', $cache_config['prefix']);
define('WP_REDIS_CLIENT', $cache_config['driver']);
// 3. Optional authentication (never hardcode)
$auth_token = getenv('REDIS_CACHE_AUTH');
if ($auth_token !== false && strlen($auth_token) > 0) {
define('WP_REDIS_PASSWORD', $auth_token);
}
// 4. Enable production safeguards
define('WP_REDIS_DISABLE_BANNERS', true);
define('WP_REDIS_GRACEFUL', true);
define('WP_REDIS_MAXTTL', 86400); // 24-hour max cache lifetime
Quick Start Guide
- Verify Service Health: Run
redis-cli ping on the server hosting Redis. Confirm a PONG response. If using a remote endpoint, test connectivity with nc -zv <host> <port>.
- Deploy Configuration Loader: Add the provided template to your project. Populate environment variables in your deployment platform or
.env file. Ensure REDIS_CACHE_DB is set to a unique index.
- Install & Activate Plugin: Execute
wp plugin install redis-cache --activate via WP-CLI. Navigate to the plugin settings page and verify the status shows Connected with the correct client type.
- Validate Graceful Fallback: Temporarily stop the Redis service (
systemctl stop redis). Confirm the site remains accessible and logs a warning instead of throwing a fatal error. Restart Redis and verify cache restoration.
- Monitor Performance: Enable Redis
slowlog and configure application metrics to track cache hit ratios. Adjust WP_REDIS_MAXTTL and timeout values based on actual query patterns.