wp-content » cache » WP Rocket Preload 403 Errors: Allowlist the Preload Requests

WP Rocket Preload 403 Errors: Allowlist the Preload Requests

If Tools > Scheduled Actions is full of failed rocket_preload_job_preload_url actions, or your cron logger keeps showing “returned status code 0” with the odd 403 in between, WP Rocket’s preload is being blocked. Pages still get cached when a real visitor opens them, but nothing is warmed after a purge.

It came up again this week in a WordPress.org forum thread. As of 2026-11-02, WP Rocket’s own preload troubleshooting doc gives the same answer I would: find the layer that returns the 403 and allowlist the preload requests there.


WP Rocket preloads through Action Scheduler. It reads your sitemap, queues the URLs and requests them from your own server with the user agent WP Rocket/Preload. Mobile cache uses an iPhone Safari user agent instead.

Most of those requests are sent non-blocking, so WordPress does not wait for the answer. A logging plugin that records them will most likely show status 0. That alone is not proof of a failure.

The 403 is the real signal. Something in front of PHP (a security plugin, ModSecurity, Cloudflare or the host’s firewall) sees a burst of requests from one IP with a non-browser user agent and refuses them.


grep "WP Rocket/Preload" /var/log/nginx/access.log | awk '$9 == 403' | tail -n 20

In the default combined log format the ninth field is the status code, so this prints the last 20 blocked preload requests. On Apache the log is usually /var/log/apache2/access.log or /var/log/httpd/access_log. On shared hosting, download the raw access log from your control panel.

Next, see which IP the preload requests come from:

grep "WP Rocket/Preload" /var/log/nginx/access.log | awk '{print $1}' | sort | uniq -c | sort -rn

Expect one or two addresses: your server’s public IP, or 127.0.0.1 if the domain resolves locally. Write it down for step 3.

No preload lines in the log at all? Then the requests never reach the web server. That is a loopback or DNS problem, not a firewall rule, and my post on loopback requests failing with status code 0 is the better place to start.

The access log tells you a 403 happened, not who sent it. Check these, roughly in order:

  • Your security plugin’s blocked traffic or firewall log, filtered by the IP from step 1.
  • The web application firewall on the server (ModSecurity or Coraza). Its audit log or your control panel’s WAF log shows the rule ID that fired.
  • Cloudflare, under Security > Events, filtered by the user agent.
  • The host’s own firewall or rate limiter. Send support the timestamps of the 403 lines from step 1.

WP Rocket’s doc says allowlisting your site’s IP or the preload user agents should help. I’d match both at once. A user agent is a header anyone can send, so a rule that trusts WP Rocket/Preload alone lets any bot skip your firewall by faking it.

See also  Action Scheduler Past-Due Actions Notice: Fix It With WP-CLI

For ModSecurity, copy your custom rules file first, then add a chained rule. Replace 203.0.113.10 with your server IP and use a rule ID that is not taken yet:

SecRule REMOTE_ADDR "@ipMatch 203.0.113.10" "id:1000100,phase:1,pass,nolog,chain"
    SecRule REQUEST_HEADERS:User-Agent "@beginsWith WP Rocket/Preload" "ctl:ruleEngine=Off"

This turns the rule engine off only for requests that match both conditions. Test the config and reload the web server (nginx -t or apachectl configtest first). If the test fails, restore the copy.

On Cloudflare, create a WAF custom rule with this expression and the Skip action for whatever blocked it in Security Events:

(ip.src eq 203.0.113.10 and http.user_agent contains "WP Rocket/Preload")

In a security plugin, add the server IP to its allowlist. Most of them have an allowlist field in the firewall settings.

On an OpenPanel server the WAF is Coraza with the OWASP Core Rule Set. Under Security > Web Firewall (Coraza), the Logs button on the Domains tab shows the requests flagged for that domain and the rules they triggered, and from there you can disable a rule for just that domain instead of server-wide (see the OpenPanel WAF docs). On cPanel servers you would usually do the same thing with ModSecurity in WHM and a custom exclusion like the one above.

Some firewalls don’t care about the user agent, only the burst. According to WP Rocket’s preload parameters doc, the defaults are up to 45 URLs per batch, 60 seconds between batches and 0.5 seconds between requests.

WP Rocket offers a helper plugin to lower the batch size and stretch those pauses. Note that it also slows down Used CSS generation. Don’t go the other way and raise action_scheduler_queue_runner_concurrent_batches on shared hosting: that filter affects every plugin that uses Action Scheduler, and WP Rocket itself only suggests it for dedicated servers.

Click “Clear and preload cache” in the admin bar, wait a few minutes, then look at WP Rocket’s queue table. This query only reads data:

wp db query "SELECT status, COUNT(*) AS urls FROM wp_wpr_rocket_cache GROUP BY status;"

Statuses are pending, in-progress, completed and failed. The completed count should climb and no new 403 lines should appear in the access log.

💡 Replace wp_ with your table prefix.

If URLs sit in pending and never move, the firewall is no longer the issue. That points at WP-Cron or Action Scheduler not running, which I cover in fixing Action Scheduler past-due actions with WP-CLI. A real server cron that calls wp-cron.php is the more reliable setup for preload anyway.


TL;DR: status 0 in the preload logs is mostly noise, and the 403s are your firewall blocking WP Rocket’s own requests. Grep the access log for WP Rocket/Preload, find the layer that returned 403, and allowlist your server IP together with the preload user agent there. If it’s rate limiting, lower the preload batch size instead.

Was this post helpful?

Leave a Comment

I enjoy constructive responses and professional comments to my posts, and invite anyone to comment or link to my site.

Recommended