-
Notifications
You must be signed in to change notification settings - Fork 233
Description
Describe the bug
I am Senior Engineer from the Cloudways reporting an important issue which was recently observed with the wp-rocket and varnish purging. Cloudways has recently change their VCL where PURGE request will only work when the Real-IP header and request and is routed through the Nginx but on the Wp-rocket, The request is directly going on the varnish without the real IP header and PURGE request is getting blocked.
Working PURGE request:
* << Request >> 65581
- Begin req 65580 rxreq
- Timestamp Start: 1764849175.476370 0.000000 0.000000
- Timestamp Req: 1764849175.476370 0.000000 0.000000
- ReqStart 127.0.0.1 15930 a0
- ReqMethod PURGE
- ReqURL /.*
- ReqProtocol HTTP/1.0
- ReqHeader X-Real-IP: 127.0.0.1
- ReqHeader X-Forwarded-For: 127.0.0.1
- ReqHeader X-Client-Real-IP: 127.0.0.1
- ReqHeader Host: wordpress-1559331-6048096.cloudwaysapps.com
- ReqHeader X-Forwarded-Proto: http
- ReqHeader X-Forwarded-Host: wordpress-1559331-6048096.cloudwaysapps.com
- ReqHeader X-Application: wordpress
- ReqHeader X-App-User: vjjvvmutve
- ReqHeader X-Version: latest
- ReqHeader Connection: close
- ReqHeader User-Agent: W3 Total Cache
- ReqUnset X-Forwarded-For: 127.0.0.1
- ReqHeader X-Forwarded-For: 127.0.0.1, 127.0.0.1
- VCL_call RECV
- ReqUnset X-Forwarded-For: 127.0.0.1, 127.0.0.1
- ReqHeader x-forwarded-for: 127.0.0.1
- ReqUnset Host: wordpress-xxxx-xxxx.cloudwaysapps.com
- ReqHeader Host: wordpress-xxxx-xxxx.cloudwaysapps.com
- VCL_return purge
- VCL_call HASH
- VCL_return lookup
- VCL_call PURGE
- VCL_return synth
- RespProtocol HTTP/1.1
- RespStatus 200
- RespReason OK
- RespReason Purged
- RespHeader Date: Thu, 04 Dec 2025 11:52:55 GMT
- RespHeader Server: Varnish
- RespHeader X-Varnish: 65581
- VCL_call SYNTH
- RespHeader Content-Type: text/html; charset=utf-8
- RespHeader Retry-After: 5
- VCL_return deliver
- Timestamp Process: 1764849175.476509 0.000139 0.000139
- RespHeader Content-Length: 0
- Storage malloc Transient
- RespHeader Accept-Ranges: bytes
- RespHeader Connection: close
- Timestamp Resp: 1764849175.476591 0.000221 0.000083
- ReqAcct 356 0 356 211 0 211
- End
Request through WP-Rocket:
Begin req 65573 rxreq
Timestamp Start: 1764842237.777350 0.000000 0.000000
Timestamp Req: 1764842237.777350 0.000000 0.000000
ReqStart 127.0.0.1 53716 a0
ReqMethod PURGE
ReqURL /page/.*
ReqProtocol HTTP/1.1
ReqHeader Host: http://wordpress-xxx-xxx.cloudwaysapps.com
ReqHeader User-Agent: WordPress/6.9; https://wordpress-xxx-xxx.cloudwaysapps.com
ReqHeader Accept: /
ReqHeader Accept-Encoding: deflate, gzip, br, zstd
ReqHeader X-Purge-Method: regex
ReqHeader Connection: close
ReqHeader X-Forwarded-For: 127.0.0.1
VCL_call RECV
ReqUnset X-Forwarded-For: 127.0.0.1
ReqHeader x-forwarded-for:
VCL_return synth
ReqUnset Accept-Encoding: deflate, gzip, br, zstd
ReqHeader Accept-Encoding: gzip
VCL_call HASH
VCL_return lookup
RespProtocol HTTP/1.1
RespStatus 405
RespReason Method Not Allowed
RespReason This IP is not allowed to send PURGE requests.
RespHeader Date: Thu, 04 Dec 2025 09:57:17 GMT
RespHeader Server: Varnish
RespHeader X-Varnish: 65574
VCL_call SYNTH
RespHeader Content-Type: text/html; charset=utf-8
RespHeader Retry-After: 5
VCL_return deliver
Timestamp Process: 1764842237.777404 0.000054 0.000054
RespHeader Content-Length: 0
Storage malloc Transient
RespHeader Connection: close
Timestamp Resp: 1764842237.777443 0.000093 0.000039
ReqAcct 255 0 255 229 0 229
End
The reverse proxy configuration for Varnish should be set through port 80 so that all requests are routed through Nginx, ensuring the request headers—such as the real-ip header—are preserved as expected. Without this adjustment, thousands of users will be unable to use WP-Rocket on the new Cloudways servers. We also intend to apply this change to the older servers, so please prioritize and expedite this ticket to prevent any plugin compatibility issues.
Varnish VCL:
# PURGING
# SMART PURGE CACHE BY URL
if (req.method == "URLPURGE") {
if (req.http.X-Real-IP != "127.0.0.1" && req.http.X-Real-IP != "::1" && req.http.X-Real-IP != "localhost" && req.http.X-Real-IP != "157.245.126.171") {
return(synth(405, "This IP is not allowed to send PURGE requests."));
}
ban("req.http.host == " + req.http.host + " && req.url == " + req.url);
return(synth(200, "Purged"));
}
# PURGE CACHE BY HOSTNAME
if (req.method == "PURGE") {
if (req.http.X-Real-IP != "127.0.0.1" && req.http.X-Real-IP != "::1" && req.http.X-Real-IP != "localhost" && req.http.X-Real-IP != "157.245.126.171") {
return(synth(405, "Not allowed."));
}
ban("req.http.host ~ " + req.http.host);
return (purge);
}
#BANING
if (req.method == "BAN") {
if (req.http.X-Real-IP != "127.0.0.1" && req.http.X-Real-IP != "::1" && req.http.X-Real-IP != "localhost" && req.http.X-Real-IP != "157.245.126.171") {
return(synth(405, "This IP is not allowed to send PURGE requests."));
}
ban("req.http.host == " + req.http.host + " && req.url == " + req.url);
return(synth(200, "Ban added"));
}