Simple redirect or status directives won't work

1. My Caddy version (caddy -version):


2. How I run Caddy:

Docker image:

a. System environment:


d. My complete Caddyfile: {

header /wp-content Cache-Control "max-age=86400"
header /blog/wp-includes/js Cache-Control "max-age=86400"

status 404 /autodiscover/*

redir /new-customer /some-other-page 301

root /www
fastcgi / fpm:9000 php

log / /var/log/caddy/access.log "{combined}" {
  except /autodiscover/autodiscover.xml
  except /banner
  rotate_age 30
  rotate_keep 6
errors /var/log/caddy/error.log

# Prevent malicious PHP uploads from running
rewrite {
	r /uploads\/(.*)\.php
	to /

rewrite {
	if {path} not_match ^\/wp-admin
	to {path} {path}/ /index.php?{query}

3. The problem I’m having:

Caddy is ignoring the redirect and status configuration. The page was transitioned from nginx to caddy and some redirects needed to be carried over from the old configuration.

As you can see in 4. Caddy is not redirecting but sending the site to the fast_cgi processor and php returns a 404 code because the page does not exist. Instead it should just return a 301 with the other page.

Same thing happens for the /autodiscover/ url. This one is sent to php too instead of just being rejected by caddy with a 404.

4. Error messages and/or full log output:

Caddy is not giving me any error messages.

HTTP Code: 301
HTTP/2 404 
cache-control: no-cache, must-revalidate, max-age=0
content-type: text/html; charset=UTF-8
expires: Wed, 11 Jan 1984 05:00:00 GMT
pragma: no-cache
server: Caddy
set-cookie: PHPSESSID=4a3e093b9761d4ce5091cd117d1d47a0; path=/
status: 404 Not Found
vary: Accept-Encoding, Cookie
x-powered-by: PHP/7.3.12
date: Wed, 27 Nov 2019 14:35:37 GMT

5. What I already tried:

Everything. Nothing worked so I’m asking here… :slight_smile:

Hi @mgray, welcome to the Caddy community.

Rewrites execute earlier in the middleware chain than redirects or manual status (see:

This means that due to this fairly widely scoped rewrite:

The paths you’ve set manual status or redirect on:

Get rewritten away from these paths before those directives ever operate, unless they’re paths with a corresponding file/indexed directory in the webroot (because you rewrite to {path} {path}/ first). By the time it gets to redirect or status, the path has likely become /index.php?.

The solution should be to ensure the rewrite doesn’t do that. This should work:

rewrite {
	if {path} not_starts_with /wp-admin
	if {path} not_starts_with /autodiscover/
	if {path} not_starts_with /new-customer
	to {path} {path}/ /index.php?{query}

(Note that I have also rewritten your first if statement to use a substring check instead of a regex, which saves a few CPU cycles).

@Whitestrake, that’s exactly what was happening.

I think I found the link you gave about the order of middleware chaining by myself but concentrated more on fastcgi than rewrite rules. The rewrite rule is also copied from the caddy Wordpress repository so it never occurred to me that this rule could do any harm. :slight_smile:

Perhaps the caddy documentation should mention the order how middleware is chained so this could be easier to spot/debug.

1 Like

Possibly, yeah - it’s kinda hinted at in the HTTP Caddyfile doc, but never stated outright as far as I know. It’s something that is handled differently in Caddy v2, though; directives are executed in order of appearance in the configuration, so your above example (adapted for v2) would have worked perfectly.

That’s great. Was close to offering to add it to the documentation. :slight_smile:

Thank you very much for your great help here and to @matt for his work on caddy. This tool was a game changer for me!


That’s not the case, we haven’t decided yet what the default will be… So far, there is still an order to them.

Welp, glad you corrected me on that one.

Is that the case overall, or just in the Caddyfile? Obviously my recollection on this is poor but I remember talking about this in relation to JSON config.

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