• Please be aware: Kaspersky Anti-Virus has been deprecated
    With the upgrade to Plesk Obsidian 18.0.64, "Kaspersky Anti-Virus for Servers" will be automatically removed from the servers it is installed on. We recommend that you migrate to Sophos Anti-Virus for Servers.
  • The Horde webmail has been deprecated. Its complete removal is scheduled for April 2025. For details and recommended actions, see the Feature and Deprecation Plan.
  • We’re working on enhancing the Monitoring feature in Plesk, and we could really use your expertise! If you’re open to sharing your experiences with server and website monitoring or providing feedback, we’d love to have a one-hour online meeting with you.

Question Wordpress permalinks not working with Varnish

Lethalmiko

New Pleskian
I installed Varnish in a Docker image using Plesk CPanel on a WordPress website with pretty permalinks enabled. I used this guide:


When I click on any link to an article or category, I am redirected back to the homepage with a question mark inserted and the rest of the URL. ie


instead of


Everything works fine when I disable Varnish. I even tried cloning the website to a subdomain and permalinks work on the subdomain with Varnish enabled. I have disabled plugins and it makes no difference.

What should I do to fix the problem?

Contents of default.vcl (with fake IP address for host)

---
vcl 4.0;
import std;

# MAIN CONFIGURATION
backend default {
.host = "123.123.123.123";
.port = "7080";
}

# ALLOWED IP OF PURGE REQUESTS
acl purge {
"localhost";
"127.0.0.1";
"172.17.0.1";
"172.17.0.2";
"123.123.123.123";
}

#THE RECV FUNCTION
# Happens before we check if we have this in cache already
sub vcl_recv {

# SET REALIP BY TRIMMING CLOUDFLARE IP WHICH WILL BE USED FOR VARIOUS CHECKS
set req.http.X-Actual-IP = regsub(req.http.X-Forwarded-For, "[, ].*$", "");

# FORWARD THE IP OF THE REQUEST
if (req.restarts == 0) {
if (req.http.x-forwarded-for) {
set req.http.X-Forwarded-For =
req.http.X-Forwarded-For + ", " + client.ip;
} else {
set req.http.X-Forwarded-For = client.ip;
}
}

# Purge request check sections for hash_always_miss, purge and ban
# BLOCK IF NOT IP is not in purge acl
# Enable smart refreshing using hash_always_miss
if (req.http.Cache-Control ~ "no-cache") {
if (client.ip ~ purge || !std.ip(req.http.X-Actual-IP, "1.2.3.4") ~ purge) {
set req.hash_always_miss = true;
}
}

if (req.method == "PURGE") {
if (!client.ip ~ purge || !std.ip(req.http.X-Actual-IP, "1.2.3.4") ~ purge) {
return(synth(405,"Not allowed."));
}
return (purge);
}

if (req.method == "BAN") {
# Same ACL check as above:
if (!client.ip ~ purge || !std.ip(req.http.X-Actual-IP, "1.2.3.4") ~ purge) {
return(synth(403, "Not allowed."));
}
ban("req.http.host == " + req.http.host +
" && req.url == " + req.url);

# Throw a synthetic page so the
# request won't go to the backend.
return(synth(200, "Ban added"));
}

# UNSET CLOUDFLARE COOKIES
# Remove has_js and CloudFlare/Google Analytics __* cookies.
set req.http.Cookie = regsuball(req.http.Cookie, "(^|;\s*)(_[_a-z]+|has_js)=[^;]*", "");
# Remove a ";" prefix, if present.
set req.http.Cookie = regsub(req.http.Cookie, "^;\s*", "");

# For Testing: If you want to test with Varnish passing (not caching) uncomment
# return( pass );

# DO NOT CACHE RSS FEED
if (req.url ~ "/feed(/)?") {
return ( pass );
}

# PASS WP-CRON
if (req.url ~ "wp-cron\.php.*") {
return ( pass );
}

# DO NOT CACHE POST AND EDIT PAGES
if (req.url ~ "(wp-admin|post\.php|edit\.php|wp-login)") {
return(pass);
}

# DO NOT CACHE SEARCH RESULTS
if (req.url ~ "/\?s\=") {
return ( pass );
}

# CLEAN UP THE ENCODING HEADER.
# SET TO GZIP, DEFLATE, OR REMOVE ENTIRELY. WITH VARY ACCEPT-ENCODING
# VARNISH WILL CREATE SEPARATE CACHES FOR EACH
# DO NOT ACCEPT-ENCODING IMAGES, ZIPPED FILES, AUDIO, ETC.
if (req.http.Accept-Encoding) {
if (req.url ~ "\.(jpg|png|gif|gz|tgz|bz2|tbz|mp3|ogg)$") {
# No point in compressing these
unset req.http.Accept-Encoding;
} elsif (req.http.Accept-Encoding ~ "gzip") {
set req.http.Accept-Encoding = "gzip";
} elsif (req.http.Accept-Encoding ~ "deflate") {
set req.http.Accept-Encoding = "deflate";
} else {
# unknown algorithm
unset req.http.Accept-Encoding;
}
}

# PIPE ALL NON-STANDARD REQUESTS
if (req.method != "GET" &&
req.method != "HEAD" &&
req.method != "PUT" &&
req.method != "POST" &&
req.method != "TRACE" &&
req.method != "OPTIONS" &&
req.method != "DELETE") {
return (pipe);
}

# ONLY CACHE GET AND HEAD REQUESTS
if (req.method != "GET" && req.method != "HEAD") {
return (pass);
}

# DO NOT CACHE LOGGED IN USERS (THIS OCCURS IN FETCH TOO)
if ( req.http.cookie ~ "wordpress_logged_in|resetpass" ) {
return (pass);
}

# FIX CLOUDFLARE MIXED CONTENT WITH FLEXIBLE SSL
if (req.http.X-Forwarded-Proto) {
return (hash);
}

# IF THE REQUEST IS NOT FOR A PREVIEW, WP-ADMIN OR WP-LOGIN THEN UNSET THE COOKIES
if (!(req.url ~ "wp-(login|admin)") && !(req.url ~ "&preview=true" )) {
unset req.http.cookie;
}

# IF BASIC AUTH IS ON THEN DO NOT CACHE
if (req.http.Authorization || req.http.Cookie) {
return (pass);
}

# IF YOU GET HERE THEN THIS REQUEST SHOULD BE CACHED
return (hash);
# This is for phpmyadmin
if (req.http.Host == "pmadomain.com") {
return (pass);
}

# STRIP OUT URL PARAMETERS THAT LEAD TO MULTIPLE REDUNDANT CACHING
if (req.url ~ "(\?|&)(gclid|utm_[a-z]+)=") {
set req.url = regsuball(req.url, "(gclid|utm_[a-z]+)=[-_A-z0-9+()%.]+&?", "");
set req.url = regsub(req.url, "[?|&]+$", "");
}
}

sub vcl_hash {
if (req.http.X-Forwarded-Proto) {
hash_data(req.http.X-Forwarded-Proto);
}
}

# HIT FUNCTION
sub vcl_hit {
return (deliver);
}

# MISS FUNCTION
sub vcl_miss {
return (fetch);
}

# FETCH FUNCTION
sub vcl_backend_response {
# IF NOT WP-ADMIN THEN UNSET COOKIES AND SET THE AMOUNT OF TIME THIS PAGE WILL STAY CACHED (TTL)
if (!(bereq.url ~ "wp-(login|admin)") && !bereq.http.cookie ~ "wordpress_logged_in|resetpass" ) {
unset beresp.http.set-cookie;
set beresp.ttl = 1w;
set beresp.grace = 3d;
}

if (beresp.ttl <= 0s || beresp.http.Set-Cookie || beresp.http.Vary == "*") {
set beresp.ttl = 120s;
set beresp.uncacheable = true;
return (deliver);
}

return (deliver);
}

# DELIVER FUNCTION
sub vcl_deliver {
if (obj.hits > 0) {
# IF THIS PAGE IS ALREADY CACHED THEN RETURN A 'HIT' TEXT
set resp.http.X-Cache = "HIT";
} else {
# IF THIS IS A MISS RETURN THAT IN THE HEADER
set resp.http.X-Cache = "MISS";
}
}
 
Back
Top