Caddy: URL rewrite performing 301 redirect

Created on 30 Jun 2017  路  17Comments  路  Source: caddyserver/caddy

1. What version of Caddy are you using (caddy -version)?

0.10.4

2. What are you trying to do?

Rewrite incoming URLs, so assets are served correctly and everything else resovles to index.html.

3. What is your entire Caddyfile?

:5000, https://redacted.domain {
  root /src/dist

  tls {%CADDY_TLS_SETTING%}

  rewrite /revision {
    to REVISION
  }

  rewrite / {
    regexp .*
    to {path} /index.html
  }

  gzip

  log stdout
  errors stdout
}

4. How did you run Caddy (give the full command and describe the execution environment)?

In Docker:

CMD ["caddy", "--conf", "/src/Caddyfile", "--log", "stdout"]

5. Please paste any relevant HTTP request(s) here.

Curl:

 curl -Ik https://redacted.domain/people
HTTP/1.1 301 Moved Permanently
Content-Type: text/plain; charset=utf-8
Date: Fri, 30 Jun 2017 08:55:09 GMT
Location: /
Server: Caddy
Connection: keep-alive

Access log:

2017-06-30T09:00:09Z web:RQKEUGQPVAP/22508fd20d03 10.0.1.144 - - [30/Jun/2017:09:00:09 +0000] "GET /people?as HTTP/1.1" 301 63
2017-06-30T09:00:09Z web:RQKEUGQPVAP/22508fd20d03 10.0.1.144 - - [30/Jun/2017:09:00:09 +0000] "GET /?as HTTP/1.1" 200 683
2017-06-30T09:00:13Z web:RQKEUGQPVAP/22508fd20d03 10.0.2.46 - - [30/Jun/2017:09:00:13 +0000] "GET / HTTP/1.1" 200 683

6. What did you expect to see?

Caddy is serving a static SPA, so we expected that the page corresponding to /people in the app would render. This is what happens in 0.10.3 and is confirmed by reverting to that version of Caddy.

7. What did you see instead (give full error messages and/or log)?

Caddy redirects all of the requests to /.

8. How can someone who is starting from scratch reproduce the bug as minimally as possible?

Build a minimal frontend app that rewrites all requests to index.html and uses client-side routing to decide what to render on the client.

Most helpful comment

Hey @leemachin, thanks for taking the time to fill out the issue template!

This is expected behavior. Your rewrite rule is telling Caddy to rewrite _all_ requests to the same path (if it exists on disk) or, if not, to /index.html.

If the path is rewritten to /index.html, the static file server issues a redirect to canonicalize the path to /, which is correct for serving index files.

If you change your rewrite rule to:

rewrite {
    regexp .*
    to {path} /
}

then it will not issue the redirect anymore, since the rewritten path is correct this way.

Hope this helps!

All 17 comments

Hey @leemachin, thanks for taking the time to fill out the issue template!

This is expected behavior. Your rewrite rule is telling Caddy to rewrite _all_ requests to the same path (if it exists on disk) or, if not, to /index.html.

If the path is rewritten to /index.html, the static file server issues a redirect to canonicalize the path to /, which is correct for serving index files.

If you change your rewrite rule to:

rewrite {
    regexp .*
    to {path} /
}

then it will not issue the redirect anymore, since the rewritten path is correct this way.

Hope this helps!

Hey, I have a potentially related problem happening to me since the unofficial joshix/caddy Docker image updated 18 days ago. Sadly I don't have time at the moment to exactly narrow it down, but it seems that Caddy started throwing 301s where it did not before, which was breaking our app.

This is my configuration:

0.0.0.0:8080 {
        rewrite {
                to {path} {path}/ index.html
        }

        header / Cache-Control "no-cache"
}

In joshix/caddy before 0.10.x, if we were to curl http://localhost:8080/folder/, we would get 200 OK.
In joshix/caddy after 0.10.x, if we were to curl http://localhost:8080/folder/, we would get 301, and it would redirect to http://localhost:8080/folder.

I will absolutely try to dig into this later when I have more time, but it seems awfully like some kind of regression, and it might be more obvious to some people. I realize the joshix/caddy image is not official and was reasonably out of date until recently, but it looks like this may possibly coincide with this bug: #1177. We rely on directory-style URLs in our SPA, so without a solution this causes quite some trouble.

Hopefully this isn't wholly unrelated to this thread, but I apologize if it happens to be. Either way, again, I'll try to take a deeper look at this later on.

@johnwchadwick I think (hope) that's different. Did you try with Caddy 0.10.4 (released 2 days ago)?

@mholt thank you for the explanation. If this is expected behaviour, why is it that 0.10.3 and 0.10.4 behave differently with the same config? I've looked through the changelog and commits and cannot see anything that would break things.

We've since reverted to the previous version (easy fix ;)) but I will use your suggestion and see how that goes, since it would be good to stay updated.

@leemachin

If this is expected behaviour, why is it that 0.10.3 and 0.10.4 behave differently with the same config? I've looked through the changelog and commits and cannot see anything that would break things.

Commit f4b6f15e07b91976d6579c8445a3321dcc63d8ae.

It fixed a regression. :wink:

@mholt to confirm the config in https://github.com/mholt/caddy/issues/1737#issuecomment-312294705 or https://github.com/mholt/caddy/issues/1737#issuecomment-312339423 is the recommended way to handle SPAs since the regression fix?

@OmgImAlexis I dunno, I haven't tried it, but it seems like it would do what you need!

@mholt I am still having this issue as of version 0.10.6. I have also tried the solution that you posted above, but Caddy continues to bring me back to/ with a 301.

@dtrinh100 Make sure to clear your browser cache; check it with curl just to be sure!

This may help if you need Caddy to always return index.html for SPA routes:

rewrite {
  to {file} index.html
}

I've been banging my head against the wall for the past couple of hours trying to figure out where the redirect was coming from. found out that caddy automatically redirects any filename listed under the index label to not include the index.html part aka it is very unhappy about serving files named index.html by default. Either add an index label or set your redirect to / instead of /index.html Why did this take me so long to realise :man_facepalming: Hopefully someone else sees this sooner than I did. (maybe add it to the docs :wink:)

@psrcek In Caddy 2, you can turn off URI canonicalization: https://caddyserver.com/docs/json/apps/http/servers/routes/handle/file_server/

We can also expose that for the Caddyfile (https://caddyserver.com/docs/caddyfile/directives/file_server) but we just haven't gotten around to that yet.

Thanks guys for your help, but as I use Caddy v2, I can't convert the old syntax:

rewrite {
  to {file} index.html
}

to the new one : rewrite ...

Any ideas ? Thanks

@mkhennoussi please ask your usage questions at https://caddy.community. This is the issues board for bugs and feature requests.

Thanks guys for your help, but as I use Caddy v2, I can't convert the old syntax:

rewrite {
  to {file} index.html
}

to the new one : rewrite ...

Any ideas ? Thanks

You can use try_files directive in v2:

handle {
  root {$WWW_ROOT}
  try_files {path} /index.html
  file_server
}

Thanks guys for your help, but as I use Caddy v2, I can't convert the old syntax:

rewrite {
  to {file} index.html
}

to the new one : rewrite ...
Any ideas ? Thanks

You can use try_files directive in v2:

handle {
  root {$WWW_ROOT}
  try_files {path} /index.html
  file_server
}

I use vue with history mode, it dose not work. Anything help?

Hey @Virgil-N, I created this repo showcasing how to use it with Vue router in history mode: https://github.com/RecuencoJones/caddy-vue-router

Looks like since rc version we also need to add matcher to root directive.

You can test with npm

npm install
npm run serve:caddy

or docker

npm install
npm run build
docker build -t caddy-vue-router .
docker run -dit --name caddy-vue-router -p 8080:8080 caddy-vue-router
Was this page helpful?
0 / 5 - 0 ratings