Caddy keeps redirecting to root URL?

Using Caddy to reverse proxy to my webserver (locally hosted)

For whatever reason it seems like I cannot get past my base site URL ie: works but doesn’t… so most of the site is broken. Clicking on links the page reloads back to every time.

I have no idea what is going on.

Here is my Caddyfile:

#SE Website {
    proxy /
        fastcgi / php

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


FWIW, I don’t have this issue with any of my other sites using same/similar configs for other web applications (nzbget, sonarr, etc) all are functioning correctly… only when dealing with my webserver/wordpress (wordpress site functions 100% w/o SSL).

This is very odd, for a number of reasons. Firstly, fastcgi here will never operate, because proxy always runs first, and the catch-all proxy always handles the request. Secondly, you are rewriting as though you expect fastcgi to operate, but it never does - proxy simply sends the rewritten URI upstream. Thirdly, your upstream host appears to be the same host you’re serving!

I’m not sure what your intention is, but you should determine whether you want to A) pass off all traffic to another webserver, or B) serve WordPress via FastCGI, because the two are mutually exclusive.

For reference, the middleware operation order, with proxy and fastcgi highlighted:

thank you for the reply.

Admittedly I’m new to Caddy. I’ve been using it for some time now to reverse proxy my web applications (self-hosted) as I’ve mentioned already, like Plex, sonarr, etc.

That said I admit that some things here might not make sense. I started to get desperate getting this all to work for my web site to work I started trying things (like adding fastcgi) and I have no idea what that even does. But I’ve seen most that attempt to pipe through a wordpress site have that.

when you say my upstream host appears to be the same host i’m serving… I suppose you mean the proxy address is the same host name/url as the one i’m offering through caddy.

The explanation for this is my webserver (apache) is multi-site. So apache only responds when I access my site through it’s URL. Not sure how else to handle this, hope that makes sense.

Additionally, I was looking for a way just to “pass-through” my site w/o SSL for troubleshooting but haven’t been able to figure out if that is possible with Caddy.

No worries. Lets look into this Apache multi-site thing - I’m going to make a few assumptions: that Caddy doesn’t need to manipulate the traffic to Apache in any way, and your Apache server is on a static internal IP address (I will use by way of example).

The simplest way to get this happening would be like this: {
  proxy / {

The transparent preset here tells Caddy to preserve details from the original request, including the requested Host and the connecting client’s IP. It will tell Apache which site is being requested, so it can respond properly.

The reason I suggest using the IP address rather than the host is because the latter will only work in a split DNS setup - externally, that domain needs to resolve to Caddy’s host, but internally, it must resolve to Apache’s host. Configuring your webserver contingent on a specific DNS configuration is one complexity I’ve found best to be avoided.

For reference, the scheme http:// and port :80 are implicit for the upstream server.

If you are having trouble with HTTPS, a neat way to bring Caddy up just with HTTP is to prefix the site with a scheme: {

You are correct in your assumptions!

if I map my DNS server (or even the windows hosts file) to map the host name to the webserver’s IP, the whole site works perfectly fine.

Unfortunately even with your suggestion with the transparent flag (and http:// flag to avoid the SSL connection) the site is still broken.

Regarding internal/external DNS issue… I have forward lookup zones setup on my AD server to handle this…

if you like you can see for yourself by visiting the site: to get an idea of what is going on.

Here is the current Caddy config section of my site as per your suggestions (tried w/ and w/o http:// in front of the host name for what it’s worth):

#SE Website {
    proxy / {

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


OK, check this out, broken resources:

Lets check out one of these resources:

Huh? Why is the resource at Didn’t we want wp-embed.min.js? Lets check the requests…

That doesn’t look good. Bunch of 301s. These redirects are coming from Apache, too. And they’re telling us to go get for some reason…

OK, so we’re getting redirected away from all of our static resources, and being given a HTML document for every request instead! Not what we want at all. Why is that? To explain, lets analyse the rewrite you’re using:

What’s the rewrite doing? If the conditions match, it checks whether {path} exists on disk in the webroot. What’s the webroot? Well, it wasn’t set explicitly, so it’ll be the working directory of the Caddy process on the Caddy host. This rewrite expects WordPress files to be there. What does it do if it can’t find them?

It changes every single request to read{query}, because that’s the last rewrite target. Then, rewrite done, proxy sends that request upstream!

What does Apache do with that? Well, firstly, /index.php?ver=4.4.16 is the wrong way to request an index. Apache wants to tell you that you can just request /?ver=4.4.16. We’ve just explained our Status 301 response with the Location: header.

What happens next, once the browser goes to the new location for the resource? It gets an index file, of course. HTML - when it was expecting JavaScript. And now we’ve explained the console errors and the lack of any site resources or styling.

How do we fix it? TL;DR: Just remove the rewrite from your Caddyfile entirely. You don’t need it - Apache handles that routing already. When I posted the example above, that was the whole Caddyfile.

1 Like

Well that was very in depth! I understand a little more now about what is happening I suppose.

Unfortunately removing the rewrite rules didn’t fix the site completely (it seems anything beyond the base url is still missing/broken, images, pages, etc.), but at least it goes to the actual links now ( it just doesn’t find the content so I get a 404 Error.

BTW, thanks for the help so far!

That 404 error is coming from apache so I would check your apache logs to find the reason. Are you able to browse to /contact-us/ successfully if you do so directly (bypassing the caddy server)? From the error page it looks like caddy is passing the correct path for the request.

huh, you are correct… /contact-us/ doesn’t resolve… I’ll check that later to see what happened to the pages.

the rest of the main page and blog seems to work but only on Edge for some reason… w/ Chrome on my desktop and android/mobile I get the connection not private error and it just goes into a loop even if I say go ahead… strange… I notice that Chrome reports my host/domain is using the ssl cert of another domain in Caddy. You can see this below in the picture.


Could be something to do with the permalinks, I see this happen all the time in WordPress. Go to your site settings, under permalinks, click “Save” without changing anything, and it should fix Apache’s .htaccess file… I’d give it a fifty fifty that solves the problem, or we can look somewhere else.

Just to confirm, did you clear your cache when performing this test?

Weird! Check out the results from cURL:

whitestrake at apollo in ~
❯ curl -IL
HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
Date: Tue, 11 Sep 2018 23:31:59 GMT
Link: <>; rel=""
Server: Caddy
Server: Apache/2.4.7 (Ubuntu)

whitestrake at apollo in ~
❯ curl -kiL
HTTP/2 421
content-type: text/plain; charset=utf-8
server: Caddy
x-content-type-options: nosniff
content-length: 65
date: Tue, 11 Sep 2018 23:31:53 GMT

421 Site is not served on this interface

That shouldn’t be happening. Maybe you are using in your Caddyfile?

yes I am using that right now to avoid the SSL headache w/ WP.

That said, I think it is a browser cache issue since it is working on a fresh laptop install I just completed. So for now I have to say thank you for working with me on this. I think i’m ok with how it is running at this point and will tinker with it and Caddy as I go.

When you specify HTTP-only, Caddy won’t actually respond to HTTPS requests for the site. If Caddy doesn’t have HTTPS enabled for the site, it won’t keep the certificate for it, and when Caddy gets a request for a HTTPS site it isn’t serving, it will attempt to satisfy the certificate requirement with a random certificate.

To prevent this, if you explicitly want to discourage HTTPS access to your WordPress site, I’d suggest adding the following to your Caddyfile: {

This will let users who have the HTTPS site cached, or users who manually browse to HTTPS, access the site without certificate errors (they will be redirected to HTTP). If/when the WordPress HTTPS issues are resolved, remove this block and the http:// prefix from the other block to go back to a secure setup.

Maybe I’m missing something but adding that to my Caddyfile breaks caddy after the restart.

I added it to the end of the file, but also tried to integrate it into the working part of the proxy part without luck.

How does it break Caddy, exactly (what did you do, what did you expect to happen, what happened instead)?

It belongs completely outside any other configuration block - for example, appended to the end of the Caddyfile like you said. It won’t work inside the other configuration.

Right, so adding it at the end of the file (outside of any other config) didn’t breka the config for Caddy but when visiting the site the browser was going back and forth between http and https URL’s at a rapid rate and wouldn’t stop until I closed the tab.

Sounds like something is redirecting HTTP to HTTPS. There are no redir statements in your http:// version of the site? The Caddyfile looks something like this? {
  # actual site configuration
} {

If that’s the case, check your browser cache isn’t causing issues, and check that WordPress itself isn’t trying to redirect to HTTPS (what’s the site address in the wp-admin site settings?).

If I add the redir part as you put it above Caddy errors out when I restart it.

systemctl status caddy returns the following:

â caddy.service - Caddy HTTP/2 web server
   Loaded: loaded (/etc/systemd/system/caddy.service; enabled; vendor preset: disabled)
   Active: failed (Result: exit-code) since Thu 2018-09-13 17:39:51 EDT; 9s ago
  Process: 3518 ExecStart=/usr/local/bin/caddy -log stdout -agree=true -conf=/etc/caddy/Caddyfile -root=/var/tmp (code=exited, status=1/FAILURE)
 Main PID: 3518 (code=exited, status=1/FAILURE)

Sep 13 17:39:51 systemd[1]: Started Caddy HTTP/2 web server.
Sep 13 17:39:51 systemd[1]: Starting Caddy HTTP/2 web server...
Sep 13 17:39:51 systemd[1]: caddy.service: main process exited, code=exited, status=1/FAILURE
Sep 13 17:39:51 systemd[1]: Unit caddy.service entered failed state.
Sep 13 17:39:51 systemd[1]: caddy.service failed.

What do you get from the stdout log?

sudo journalctl -b -u caddy

Caddy should print something at startup - including why it decided to exit.

Sorry for the delay in replying… At this point I’d say the site is working well enough in non SSL until I decide to redo the site completely. For not it seems to work correctly from all browsers/platforms that I can tell so I’m going to leave it as is.

I wanted to thank you for the support with this though it was very helpful!