How to Set Up Redis Object Cache for WordPress VPS
Run Redis object cache for WordPress on your VPS: bind am to localhost, set maxmemory and eviction policy, then verify say cache dey work for real.
Wetin Redis object cache dey do for WordPress
Redis object cache for WordPress dey store result of database queries for memory, so the next request go read dem from Redis instead of asking MySQL again. WordPress already get object cache for core, WP_Object_Cache, but e dey live for PHP memory and dem dey throw am away when request finish. A drop-in file dey replace am with one wey dey talk to Redis, so cache go remain from one request to the next.
Object caching no be page caching, and this difference go decide whether this guide worth your time. Page cache dey store the complete HTML of one URL and serve am again without running PHP at all. E faster pass anything Redis fit do, and e work for visitors wey no login. Once person login, put item for cart, or open admin, page cache go comot for road and WordPress go run the whole request: bootstrap, plugins, queries. Object cache dey make that request cheaper. Na the tool for traffic wey page cache no fit handle: logged-in sessions, carts, checkout, wp-admin. For WooCommerce shop, na most of the expensive traffic be that.
The two fit work together, and for busy site both dey useful. Make you clear about the problem wey you dey fix. Brochure site wey get anonymous readers dey get almost all im speed from page cache, and adding Redis to am no go change much.
Make we state one honest limit before you start. Object cache no dey make slow query fast. E dey remove the repeat of query wey don already run. The first request after cache miss go pay the full cost, so plugin wey dey run unindexed query still go run am once for every cache lifetime.
Wetín you need first
- A Linux VPS wey get shell and
sudo. No control panel dey required. - WordPress wey PHP-FPM dey serve, for example for LAMP stack for Ubuntu 24.04.
- WP-CLI for the box. Every step here get equivalent for admin screen, but shell version dey faster.
- Redis for the same machine wey PHP dey run on. Low latency na the main reason, and network hop go cancel the benefit.
Commands below na for Ubuntu 24.04 with PHP 8.3 and www-data web user. Change the PHP version and user make dem match your box. Run the wp commands from your WordPress directory, the one wey hold wp-config.php.
Redis install karna and PHP extension
sudo apt update
sudo apt install -y redis-server php-redis
sudo systemctl enable --now redis-server
redis-cli pingredis-cli ping suppose answer PONG. If e print Could not connect to Redis at 127.0.0.1:6379: Connection refused, server no dey run, so read systemctl status redis-server before you continue.
php-redis na PhpRedis, the C extension from PECL. E faster pass Predis, wey na pure PHP, and the plugin dey use am automatically when e dey available. PHP-FPM dey load extensions when e start, so new extension no go show until you restart the pool.
sudo systemctl restart php8.3-fpm
php -m | grep redisTake care with that last check: php -m dey list the modules for command line PHP, and FPM fit load another set. The check wey matter na the plugin own diagnostics, further down.
As of August 2026, Ubuntu 24.04 packages Redis 7.0.15, and e good for object cache. If you want current release instead, Redis dey publish its own APT repository.
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
sudo chmod 644 /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
sudo apt install -y redisIf your distribution dey ship Valkey, the fork wey start after the 2024 licence change, e dey speak the same protocol and everything below still apply without change.
Bind Redis so nothing else fit reach am
Redis no get password by default. Anything wey fit open connection to port 6379 fit read every cached value and run FLUSHALL. Scanners fit find instances wey expose to internet within hours, so network setting come before tuning.
Open /etc/redis/redis.conf and confirm these lines:
bind 127.0.0.1 -::1
protected-mode yesThen check wetin really dey listen, because config file na claim and ss na the evidence.
sudo ss -lntp | grep 6379127.0.0.1:6379 na wetin you want. 0.0.0.0:6379 mean say Redis dey answer for public interface: fix the bind line and restart am.
When PHP and Redis dey for the same box, Unix socket better pass loopback TCP. TCP stack no dey the path, and file permissions decide access instead of firewall rule wey you fit later change.
unixsocket /run/redis/redis-server.sock
unixsocketperm 770The socket belong to the redis user and group, so web user gatz join that group.
sudo systemctl restart redis-server
sudo usermod -aG redis www-data
sudo systemctl restart php8.3-fpm
redis-cli -s /run/redis/redis-server.sock pingThat one must also print PONG. Could not connect to Redis at /run/redis/redis-server.sock: Permission denied mean say the group no take effect. Check id www-data, and remember say running PHP-FPM keep the groups wey e get when e start, na why restart dey the list. Leave TCP enabled until you prove say the socket dey work, otherwise typo fit remove both paths at once.
How much memory Redis suppose get?
Calculate the number from your own box. Redis without maxmemory go continue grow until kernel run out of memory and OOM killer terminate one process. Most times, na the biggest process, and for WordPress server, na often MySQL. journalctl -k | grep -i "out of memory" go show the kill after e don happen, but by then the site don already go down.
Start with total RAM and subtract the other needs. MySQL or MariaDB reserve innodb_buffer_pool_size plus buffers for each connection. PHP-FPM cost pm.max_children multiply by the real resident size of one worker. For plugin-heavy site, this one commonly dey between 64 MB and 128 MB. Kernel and web server need some hundred megabytes. Wetin remain na your ceiling, and Redis go take part of am.
Example budget for 4 GB VPS wey dey run one shop
These figures na examples, no be measurements from your server. Replace each one with the value wey your box report.
- MariaDB with 1 GB buffer pool: 1024 MB
- PHP-FPM, 10 workers at 96 MB each: 960 MB
- Kernel, nginx or Apache, sshd, logging: 512 MB
- Wetin remain: roughly 1.5 GB
A maxmemory of 256 MB na sensible starting point for there. E leave enough headroom, and one WordPress site rarely need more.
Now measure am instead of guessing. After one day of real traffic:
redis-cli info memory | grep -E 'used_memory_human|maxmemory_human|maxmemory_policy'
redis-cli dbsizeIf used_memory_human dey far below your limit, reduce the limit and give the RAM back to MySQL, wey go use am better. If e dey reach the limit and evicted_keys dey increase throughout the day, raise the limit. Set the value inside /etc/redis/redis.conf.
maxmemory 256mb
maxmemory-policy allkeys-lruredis-cli config set maxmemory 256mb take effect now but e go disappear after the next restart, just like bare sysctl -w. Edit the file, then sudo systemctl restart redis-server, then read the value again. E good make you get second wall: a MemoryMax cap for the systemd unit go stop misconfigured Redis from taking down the box. Set am above maxmemory, never equal to am, because cgroup limit go terminate the process instead of evicting a key. If Redis dey run inside container beside WordPress, put the same figure inside the memory limits for your Compose file, and the same reasoning go guide the choice of running the database inside Docker or for the host.
Choose di eviction policy with purpose
Fresh Redis dey use noeviction by default. Check your own one:
redis-cli config get maxmemory-policyUnder noeviction, full instance go stop accepting writes and return this:
(error) OOM command not allowed when used memory > 'maxmemory'.That one line na the worst failure mode for this guide, because site no go go down. E go just slow down. Every cache write go fail, so WordPress go return to database to get the value, then try store am again for the next request and fail again. Site go now pay for all the original database work plus one round trip to Redis for every key. Nothing for WordPress admin go tell you say this dey happen. The string go show for PHP error log, so grep for OOM command not allowed when site slow down after you add cache.
allkeys-lru na the correct default here. Redis go drop the least recently used key when memory tight, and na exactly wetin object cache want, because every value inside am na copy of data wey still dey MySQL. Losing one key cost one query. Refusing one write cost every query, for every request, until person notice am.
Avoid volatile-* policies for this work. Dem only consider keys wey get expiry, and Redis documentation say dem dey behave like noeviction when no key get expiry. WordPress dey store most object cache entries without TTL, so volatile-lru for object cache fit fill up and start refusing writes. allkeys-lfu na fair alternative if your traffic dey hit small set of keys very often, because e dey evict by frequency instead of recency. Choose one deliberately and write down why.
Persistence: leave am off unless you get reason
The packaged redis.conf dey enable RDB snapshots with lines like save 900 1, and e leave append-only file off. For pure object cache, snapshots no get benefit. By definition, you fit regenerate the data, and cache wey restore from file wey twenty minutes old na stale values wey WordPress go trust.
Snapshots still dey cost resources. BGSAVE dey fork the process, and copy-on-write fit make memory usage rise sharply while the child dey write. For small VPS, you go see am for Redis log:
Can't save in background: fork: Cannot allocate memoryand often this warning when startup happen. Redis dey tell you say the fork fit fail later:
WARNING overcommit_memory is set to 0! Background save may fail under low memory condition.To turn snapshots off, set empty save schedule for /etc/redis/redis.conf, restart, then confirm say the value don return empty.
save ""sudo systemctl restart redis-server
redis-cli config get saveKeep persistence only if the same instance dey hold something wey you no fit rebuild, like job queue or rate-limit counters. For that case, split the two. Cache want keys wey fit evict, while durable data want keys wey dem go keep. maxmemory plus eviction dey apply to the whole instance, no be just one database index. Two instances for two sockets na the clean answer.
Install plugin, and understand the drop-in
wp plugin install redis-cache --activate
wp redis enable
wp redis statuswp redis enable dey print Object cache enabled. when e succeed. Wetin e really do na to copy wp-content/plugins/redis-cache/includes/object-cache.php go wp-content/object-cache.php. That copy na the drop-in, and na the drop-in dey do the work. WordPress loads wp-content/object-cache.php very early, before any plugin code run, na so the cache dey available for the whole request. Active plugin wey no get drop-in for place no dey cache anything.
The failure messages dey tell you which part fail. Object cache could not be enabled. mean say the copy fail, so wp-content no writable by the user wey dey run WP-CLI. A foreign object cache drop-in was found. mean say another caching plugin don already take that filename, and the fix na wp redis update-dropin. Message wey end with Redis server is unreachable: followed by client error mean say the connection settings wrong, so go back to redis-cli ping.
If permissions make the copy fail, put am there by hand and give ownership to the web user.
cp wp-content/plugins/redis-cache/includes/object-cache.php wp-content/object-cache.php
sudo chown www-data:www-data wp-content/object-cache.phpRemoving the plugin no remove the drop-in. Run wp redis disable first; e go print Object cache disabled. and delete the file. If you delete the plugin directory while the drop-in remain, the site go continue to run old cache code without any plugin to update am.
Connection settings for wp-config.php
Add dem above the line wey reads /* That's all, stop editing! */, because constants wey you define after am don too late.
define( 'WP_REDIS_HOST', '127.0.0.1' );
define( 'WP_REDIS_PORT', 6379 );
define( 'WP_REDIS_DATABASE', 0 );
define( 'WP_REDIS_PREFIX', 'shop_prod:' );For Unix socket, set the scheme and path. Host and port go then dey ignored.
define( 'WP_REDIS_SCHEME', 'unix' );
define( 'WP_REDIS_PATH', '/run/redis/redis-server.sock' );
define( 'WP_REDIS_PREFIX', 'shop_prod:' );WP_REDIS_MAXTTL dey force expiry for every key, for seconds. You no need am with allkeys-lru, and e useful if you want hard upper limit for how stale cached value fit be.
One Redis, plenty sites: prefixes and databases
Redis dey give you sixteen numbered databases by default, and each one get one flat keyspace. If two WordPress installs point to database 0 without prefix, dem go write the same key names for the same space. So one site fit read the other site's options and serve dem. Give every site its own prefix.
define( 'WP_REDIS_PREFIX', 'shopA_prod:' );
define( 'WP_REDIS_DATABASE', 1 );The prefix dey separate the key names. The database index dey separate the keyspaces. This matter when you flush: if you empty one index, the others remain untouched. The plugin also document WP_REDIS_SELECTIVE_FLUSH. E dey delete only the keys wey match your prefix instead of the whole database, but e must scan to find dem.
Prefixes and indexes no separate memory. maxmemory and the eviction policy apply to the whole instance. So one busy site fit push another quiet site's keys out, and neither site go report am. Sites wey must not affect each other need separate Redis instances. Each instance go get its own socket and its own limit.
Make staging no enter production cache
Staging site usually na copy of production files and database. This mean e dey copy wp-config.php and e dey use the same prefix and database index. If you point am to the same Redis, e go write production keys with staging values. Test price or changed option fit then show for live site without any deploy or trace.
Set salt for each environment by hand. For staging wp-config.php:
define( 'WP_REDIS_PREFIX', 'shop_staging:' );
define( 'WP_REDIS_DATABASE', 5 );Better pass, give staging im own Redis instance, or no object cache at all. define( 'WP_REDIS_DISABLED', true ); go off the cache when runtime dey run, but e go leave the drop-in for place. This one na also the fastest way to confirm whether bug come from cache or not.
Older tutorials dey set WP_CACHE_KEY_SALT for this. Plugin readme mark that constant as deprecated and say make you use WP_REDIS_PREFIX instead, so use the new name.
Verify am instead of just trust am
Start with the plugin own diagnostic.
wp redis statusThe line wey matter pass na Drop-in. Drop-in: Valid mean say WordPress dey load this plugin file. Drop-in: Not installed mean say the copy never happen and the site no get persistent cache, no matter how green the admin screen look. Status report the connection, and Client name the extension wey dey use. Na there you confirm PhpRedis instead of Predis.
Then ask WordPress core directly, because e no care wetin the plugin think.
wp eval 'var_dump( wp_using_ext_object_cache() );'bool(true) mean say core dey talk to external object cache.
Then prove say keys dey arrive, with the prefix wey you configure.
redis-cli -n 0 dbsize
redis-cli -n 0 --scan --pattern 'shop_prod:*' | headIf dbsize dey rise as you dey click around the site, na proof be that. Zero keys with valid drop-in mean say the connection dey fail quietly, or the prefix no be the one wey you think say e be.
Finally, check wetin Redis dey measure for you.
redis-cli info stats | grep -E 'keyspace_hits|keyspace_misses|evicted_keys|expired_keys'The hit ratio na keyspace_hits / (keyspace_hits + keyspace_misses), and Redis documentation give that formula. Read am with two cautions. The counters cover the whole instance since the last restart, so dem mix every site and every application wey dey share am. And the ratio immediately after flush or restart no mean anything, because the cache still dey fill. Allow am run through one normal traffic day.
No compare your number with hit rate or query count wey hosting company publish. Those ones describe their sites and their plugin set. The figure wey matter na your own, measured before and after for a page wey page cache no fit serve.
curl -o /dev/null -s -w '%{time_starttransfer}\n' -b cookies.txt https://example.com/my-account/Run am with logged-in cookie jar, several times, with cache off (WP_REDIS_DISABLED) and then on. The difference na your result.
When Redis dey make WordPress slow
A full instance wey get wrong policy na the main one, as we don cover above: OOM command not allowed when used memory > 'maxmemory'. for the log, and the site dey pay for both database and cache.
Redis for another host na the second one. WordPress dey make hundreds of object cache calls for one request. If one request make 500 calls and each round trip cost 1 ms, na half second of waiting be that, wey local socket no go need. Keep Redis for the same box, or for private network wey get sub-millisecond latency.
A very big autoloaded options table na the third one, and e common for old sites. WordPress dey cache all autoloaded options as one key, so about one megabyte of dem dey cross the connection for every single request. Measure am:
wp db query "SELECT ROUND(SUM(LENGTH(option_value))/1024) AS kb FROM wp_options WHERE autoload IN ('yes','on','auto','auto-on');"WordPress 6.6 add new autoload values, so old query wey match only 'yes' go under-report for modern install. Anything wey pass one megabyte na problem to fix for the options table, no be for Redis.
Restart dey empty everything, so the minutes after systemctl restart redis-server na all misses and all database work. Restart when traffic low. And object cache no stop wp-cron.php from firing when visitors load pages. Na separate source of slow requests be that: move WP-Cron go real system cron job while you dey work on this.
Housekeeping
Deploy wey change options or theme code finish, run wp cache flush to flush. Run wp redis update-dropin after plugin update if the drop-in no update by itself. Drop-in from older plugin version wey dey run against newer plugin fit cause strange behaviour. Monitor live server with redis-cli --stat; e dey print one line every second. redis-cli monitor dey print every command and e fit use serious CPU for busy instance. Use am for few seconds while you reproduce the issue, then stop am.
One last number wey good make you know: redis-cli info clients dey report connected_clients. PHP-FPM dey hold one connection for each worker, so that figure suppose follow your pm.max_children, no be make e pass am by order of magnitude. If e pass am, something dey open connections and e no dey close dem.
FAQ
I still need page cache if I dey run Redis object cache?
Yes, for anonymous traffic. Page cache dey serve stored HTML without running PHP, and this always cheaper pass running WordPress with warm object cache. Object cache dey handle requests wey page cache must skip: logged-in users, carts, checkout, and wp-admin. For shop or membership site, e good make both dey run. For site wey visitors no dey ever log in, page cache dey do almost all the work.
How much memory I suppose give Redis for WordPress?
Calculate am from your own server instead of copying one figure. Take total RAM, subtract MySQL buffer pool and per-connection buffers, subtract pm.max_children multiplied by resident size of one PHP-FPM worker, then subtract some hundred megabytes for kernel and web server. Give Redis part of wetin remain, then check used_memory_human inside redis-cli info memory after one day of traffic and adjust am. One WordPress site usually settle for tens of megabytes, so 256 MB maxmemory na generous starting point for 4 GB server.
Why my site slow down after I enable Redis object cache?
The usual cause na full instance wey dey use noeviction policy. Redis dey refuse new writes and return OOM command not allowed when used memory > 'maxmemory'., so WordPress fall back to database for every value and still waste time on extra Redis round trip. Check redis-cli config get maxmemory-policy, set allkeys-lru, and confirm say maxmemory no too small. Other common causes na Redis server wey dey for remote host, where hundreds of round trips for each request dey add up, and multi-megabyte autoloaded options value wey cross the connection for every request.
Several WordPress sites fit share one Redis server?
Dem fit, but you need take care. Give each site unique WP_REDIS_PREFIX so key names no go collide, and separate WP_REDIS_DATABASE index so flushing one site no go empty another site. The thing wey dem still share na memory: maxmemory and eviction apply to the whole instance, so busy site fit evict quiet site's keys. Sites wey must not affect each other need separate Redis instances with their own limits.
E safe to delete wp-content/object-cache.php?
Yes. Na drop-in, e no be part of WordPress core, and removing am go return WordPress to the built-in per-request cache. Site go continue to work, but e go simply run more database queries. Prefer wp redis disable, wey go delete the file cleanly and report Object cache disabled.. Deleting am by hand na correct emergency step if Redis dey down or dey misbehave and you no fit reach the admin.