Serve files with question mark

1. Caddy version (caddy version):


2. How I run Caddy:


a. System environment:


b. Command:

docker run

c. Service/unit/compose file:

docker run --rm -v $(pwd)/Caddyfile:/etc/caddy/Caddyfile -v $(pwd)/ --publish 80:80

d. My complete Caddyfile or JSON config: {
    root * /www/

    rewrite * {path}%3f{query}

3. The problem I’m having:

I want to serve files, that contain a question mark. They are a scrape/export of a formerly dynamic website so it contains filenames like slick.css?ver=1.3.5

4. Error messages and/or full log output:

Caddy just serves a 404 not found

5. What I already tried:

I tried the rewrite in the config, because I thought maybe it’s enough to rewrite ? to the corresponding encoded %3f

6. Links to relevant resources:

That’s a strange approach…

The usual way bundlers like webpack do cache busting or versioning is by putting a hash to the left of the file extension, so something like slick.a1b2c3.css.

You could rename your files to slick.1.3.5.css and this would work seamlessly without the need for a rewrite.

Another side-effect is that Caddy would be able to infer the mime type of the file from the extension, whereas with your approach it wouldn’t return the correct content type header since the file doesn’t end with .css.

Having a file on disk with a ? is very strange.

Strange indeed. Not strictly unsupported, of course, but the client is responsible for URL-encoding so that they’re not running afoul of the URI specification which requires the first question mark to begin the query component.

I note that it works fine if the client requests slick.css%3Fver=1.3.5. But I believe URL decoding happens before any HTTP handlers get to work, so as far as I’m aware, there are no mechanisms available to get control of this in Caddy.

It’s perfectly normal if you download a website e.g. via wget or

Like I said the website formerly was dynamic and thus actually used query parameters, but now it’s only a static export.

It seems I’m also not the only one with this problem, see e.g. this blog post for a solution with Apache HTTP Server:

Thank you very much, that way it can be solved via a client side redirect. Not optimal, but better than nothing :slight_smile:

    @question_mark {
        expression {uri}.contains('?')
    redir @question_mark {path}%3f{query}

This time I had to modify the filenames because of other reasons which worked reasonably well so I don’t need this feature right now, but I do think it makes sense to be able to host static exports of formerly dynamic websites.
I could do this because in this specific case {query} was only used for cache busting, but it’s not so easy to just cut {query} out of the filename e.g. if you have an export of something with pagination or things like index.php?site=members, index.php?site=homepage,index.php?site=list&page=3

In fact I have the latter case for another website I want to archive that way.

Thank you very much for your quick responses!

1 Like

This topic was automatically closed after 30 days. New replies are no longer allowed.