Wordpress URL rewrite problem

I’m running a Wordpress blog on a subdirectory. The front page loads great, as does wp-admin, but when I try to open any link with a further url element in it, caddy gives me a 404 error. So domain.com/blog/ works, but domain.com/blog/post-name and domain.com/blog/year/month/ do not.

Here are the relevant Caddyfile sections:

domain.com {
	root /var/www/domain.com
	fastcgi / /run/php/php7.2-fpm.sock php
	errors /var/log/caddy/domain.com/error.log
	rewrite / {
		to {path} {path}/ /index.php?{query}
	}
	gzip
}

domain.com/blog {
	root /var/www/domain.com/blog
	fastcgi / /run/php/php7.2-fpm.sock php
	rewrite /blog {
        to {path} {path}/ /index.php?_url={uri}
    }
	gzip
	errors /var/log/caddy/domain.com/error.log 
    log /var/log/caddy/domain.com/access.log 
}

Here’s what I get in access.log:

90.254.54.49 - - [08/Jan/2019:15:50:42 +0000] "GET /blog/2018/10/ HTTP/2.0" 404 38

I imagine there’s a bit of regex which would solve this problem where caddy thinks I’m asking for an existing directory and isn’t rewriting to index.php!

We can test whether this is actually the case. The log directive can be configured to provide other placeholder information for a given request.

Override the log format on the second site definition to provide the {rewrite_uri} placeholder and you can find out which file Caddy is actually 404-ing on:

log / /var/log/caddy/domain.com/access.log "{common} /// {rewrite_uri}"

That’s so cool, I’m very impressed!

90.254.54.49 - - [09/Jan/2019:00:46:13 +0000] "GET /blog/2018/10/ HTTP/2.0" 404 38 /// /2018/10/
90.254.54.49 - - [09/Jan/2019:00:46:26 +0000] "GET /blog/2018/09/ HTTP/2.0" 404 38 /// /2018/09/
90.254.54.49 - - [09/Jan/2019:00:46:30 +0000] "GET /blog/2018/08/ HTTP/2.0" 404 38 /// /2018/08/
90.254.54.49 - - [09/Jan/2019:00:46:35 +0000] "GET /blog/belfort-kohl/ HTTP/2.0" 404 38 /// /belfort-kohl/

I’ve got Wordpress blogs on their own domains which are working fine on this server, so it’s clearly a problem related to the fact that it’s on a subdomain - but it could well be a Wordpress problem, not Caddy’s.

I think I’ve got an idea what might be the issue.

Your site address is domain.com/blog, and you’re rewriting from /blog. It’s possible that the rewrite isn’t even going off unless the client browses to domain.com/blog/blog.

Change rewrite /blog { to just rewrite { to change it into a catch-all, since you don’t need to specify the base path (as the site address requires that path to match in the first place).

Quick edit: I am making the assumption that the directories requested don’t actually exist on disk, e.g. /var/www/domain.com/blog/2018/10/ is not a real folder.

Yes, your assumption is correct, they’re generated as part of Wordpress’s pretty permalinks.

Progress! I’ve changed rewrite /blog { to rewrite { and lo and behold, these fake directory paths work! Sadly, there’s now a different problem, which is that images, .css and .js files (presumably any really existing file) are no longer loading, despite definitely existing in the file tree. Here’s the kinda fascinating access log:

90.254.54.49 - - [09/Jan/2019:01:05:40 +0000] "GET /blog/wp-includes/css/dist/block-library/style.min.css?ver=5.0.2 HTTP/2.0" 404 3393 /// /index.php?ver=5.0.2
90.254.54.49 - - [09/Jan/2019:01:05:40 +0000] "GET /blog/wp-content/themes/html5blank-stable/normalize.css?ver=1.0 HTTP/2.0" 404 3393 /// /index.php?ver=1.0
90.254.54.49 - - [09/Jan/2019:01:05:40 +0000] "GET /blog/wp-content/themes/html5blank-stable/style.css?ver=1.0 HTTP/2.0" 404 3393 /// /index.php?ver=1.0
90.254.54.49 - - [09/Jan/2019:01:05:41 +0000] "GET /blog/wp-includes/js/wp-emoji-release.min.js?ver=5.0.2 HTTP/2.0" 404 3393 /// /index.php?ver=5.0.2
90.254.54.49 - - [09/Jan/2019:01:05:41 +0000] "GET /blog/wp-content/themes/html5blank-stable/js/lib/conditionizr-4.3.0.min.js?ver=4.3.0 HTTP/2.0" 404 3393 /// /index.php?ver=4.3.0
90.254.54.49 - - [09/Jan/2019:01:05:41 +0000] "GET /blog/wp-content/themes/html5blank-stable/js/lib/modernizr-2.7.1.min.js?ver=2.7.1 HTTP/2.0" 404 3393 /// /index.php?ver=2.7.1
90.254.54.49 - - [09/Jan/2019:01:05:41 +0000] "GET /blog/wp-includes/js/jquery/jquery.js?ver=1.12.4 HTTP/2.0" 404 3393 /// /index.php?ver=1.12.4
90.254.54.49 - - [09/Jan/2019:01:05:41 +0000] "GET /blog/wp-includes/js/jquery/jquery-migrate.min.js?ver=1.4.1 HTTP/2.0" 404 3393 /// /index.php?ver=1.4.1
90.254.54.49 - - [09/Jan/2019:01:05:41 +0000] "GET /blog/wp-content/themes/html5blank-stable/js/scripts.js?ver=1.0.0 HTTP/2.0" 404 3393 /// /index.php?ver=1.0.0
90.254.54.49 - - [09/Jan/2019:01:05:41 +0000] "GET /blog/wp-includes/js/wp-embed.min.js?ver=5.0.2 HTTP/2.0" 404 3393 /// /index.php?ver=5.0.2

It appears to be treating the automatic version numbers Wordpress appends to the .js and .css files as the file names themselves, but also ignoring the fact that they exist as real files? (I’ve changed the rewrite rule to to {path} {path}/ /index.php?{query} which is working in my other Wordpress setups).

For reference, some of the access log for one of the working setups is as follows:

90.254.54.49 - - [09/Jan/2019:01:15:09 +0000] "GET /wp-includes/js/wp-embed.min.js?ver=5.0.2 HTTP/2.0" 200 763 /// /wp-includes/js/wp-embed.min.js?ver=5.0.2
90.254.54.49 - - [09/Jan/2019:01:15:09 +0000] "GET /wp-content/themes/twentyfifteen/Artem-signature-logo.png HTTP/2.0" 200 49607 /// /wp-content/themes/twentyfifteen/Artem-signature-logo.png
90.254.54.49 - - [09/Jan/2019:01:15:09 +0000] "GET /wp-content/uploads/2019/01/1958_Book_cropped_colored-2-768x933.jpg HTTP/2.0" 200 65536 /// /wp-content/uploads/2019/01/1958_Book_cropped_colored-2-768x933.jpg
90.254.54.49 - - [09/Jan/2019:01:15:09 +0000] "GET /wp-includes/js/wp-emoji-release.min.js?ver=5.0.2 HTTP/2.0" 200 4090 /// /wp-includes/js/wp-emoji-release.min.js?ver=5.0.2
90.254.54.49 - - [09/Jan/2019:01:15:10 +0000] "GET /wp-content/uploads/2018/07/bg5.png HTTP/2.0" 200 54639 /// /wp-content/uploads/2018/07/bg5.png
90.254.54.49 - - [09/Jan/2019:01:15:10 +0000] "GET /favicon.ico HTTP/2.0" 200 23 /// /index.php

The Caddyfile section for this site is identical to the problem site, just without a subdirectory in the URL, obviously.

This is the expected rewrite result of /index.php?{query}. The query string for the request /blog/wp-includes/css/dist/block-library/style.min.css?ver=5.0.2 would be ver=5.0.2, so the rewrite should result in /index.php?ver=5.0.2, which is the result we got. The issue is that we get that result instead of having the rewrite stop at {path}, since it should exist.

Just to confirm, /var/www/domain.com/blog/wp-includes/css/dist/block-library/style.min.css does exist? You can stat that path?

Oh, of course, that makes sense.

And for sure I can - and it loads fine if I put /blog in the rewrite rule rather than leaving it empty.

Size: 25571     	Blocks: 56         IO Block: 4096   regular file
Device: fc01h/64513d	Inode: 1308066     Links: 1
Access: (0777/-rwxrwxrwx)  Uid: (   33/www-data)   Gid: (   33/www-data)
Access: 2019-01-08 15:27:14.257662832 +0000
Modify: 2019-01-08 15:27:13.953662733 +0000
Change: 2019-01-08 15:27:13.953662733 +0000

I’d put money that the reason this is the case is that the rewrite never fires in this scenario.

I’m pretty sure this has to do with the way Caddy handles site addresses that include paths and how the directives translate (or don’t translate) that path prefix.

You can try combining the two into a single site address with no path. This will be pretty easy to test because the /blog web root exists directly under the main site’s web root; you just need to overload the rewrite so that it prepends /blog for blog requests that get rewritten.

domain.com {
	root /var/www/domain.com
	fastcgi / /run/php/php7.2-fpm.sock php
	errors /var/log/caddy/domain.com/error.log
	log / /var/log/caddy/domain.com/access.log "{common} /// {rewrite_uri}"
	rewrite {
		to {path} {path}/ /index.php?{query}
	}
	rewrite /blog {
		to {path} {path}/ /blog/index.php?{query}
	}
	gzip
}

That did the trick! Thank you so much for your help!

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.