Serving static file is not working

1. Caddy version (caddy version):

v2.2.1

2. How I run Caddy:

In official Docker image

a. System environment:

Ubuntu 18.04 as host, Docker container

b. Command:

docker start

c. Service/unit/compose file:

FROM caddy:2.2.1-builder AS builder

RUN xcaddy build v2.2.1 \
    --with github.com/caddy-dns/gandi

FROM caddy:2.2.1

COPY --from=builder /usr/bin/caddy /usr/bin/caddy

d. My complete Caddyfile or JSON config:

api.mydomain.de {
    root /v1/chargers /srv/data
    file_server {
        index index.json
    }

    log {
        format console
    }
}

3. The problem I’m having:

I want the JSON file in /srv/data/index.json to be served when the url https://api.mydomain.de/v1/chargers is called. However Caddy is returning a HTTP 404.

If I change the root directive in the config to root * /srv/data calling https://api.mydomain.de/ will result in the delivery of the file.

4. Error messages and/or full log output:

1.605785800275067e+09	error	http.log.access.log0	handled request	{"request": {"remote_addr": "94.217.4.90:49548", "proto": "HTTP/2.0", "method": "GET", "host": "api.mydomain.de", "uri": "/v1/chargers", "headers": {"User-Agent": ["curl/7.54.0"], "Accept": ["*/*"]}, "tls": {"resumed": false, "version": 771, "cipher_suite": 49196, "proto": "h2", "proto_mutual": true, "server_name": "api.e-wald.eu"}}, "common_log": "94.217.4.90 - - [19/Nov/2020:11:36:40 +0000] \"GET /v1/chargers HTTP/2.0\" 404 0", "duration": 0.000356268, "size": 0, "status": 404, "resp_headers": {"Server": ["Caddy"]}}

5. What I already tried:

A lot, tried all kind of configurations without any success.

6. Links to relevant resources:

I think you’re looking for handle_path, which will strip the path prefix before handling the request:

handle_path /v1/chargers {
	root * /srv/data
	file_server {
		index index.json
	}
}

Please note that path matching is exact-match in Caddy v2, so /v1/chargers will only match /v1/chargers, but not /v1/chargers/foo, in case that matters.

Also note that any other unhandled paths will result in empty HTTP 200 responses unless you do something else with them.

Thanks @francislavoie, this is giving me some progress but unfortunately not the solution. Caddy is now returning a 308 with location “/”:

< HTTP/2 308 
< content-type: text/html; charset=utf-8
< location: /
< server: Caddy
< content-length: 37
< date: Thu, 19 Nov 2020 15:46:43 GMT
< 
<a href="/">Permanent Redirect</a>.

In V1 I was doing it like this, which seems far easier than the new method, is it really the only way to do what I’m looking for?

api.mydomain.de/v1/chargers {
    root /srv/data
    index index.json
}

I would also suggest to output the path in the logs where caddy is looking for the file on the file system. This would tremendously help debugging these kind of problems by myself.

Right - the file server handler is triggering a redirect to canonicalize the URL in this case. Basically if it sees that the request is for a directory, it will redirect to append a / to the path. Since the path was stripped by handle_path, the file server sees the path as just an empty string.

So the solution is to put a rewrite inside the handle_path to make sure the file server looks at your JSON file instead of the directory.

handle_path /v1/chargers {
	root * /srv/data
	rewrite * /index.json
	file_server
}

Also you asked about logs, you can add the debug global option to see more details about how the handlers are handling the request.

1 Like

Hi @francislavoie,

this actually solved my problem, I still think it’s a rather cumbersome syntax and I wouldn’t have come to that solution without your help just by reading the documentation which could easily be done in V1 of caddy.
Perhaps adding the path/file which is accessed on the file system level would be a good addition to the debug or error logging option.

I don’t see how it could be any simpler, frankly. Every part of it has a purpose and they do it in a consistent way.

I strongly disagree. Caddy v1 had huge limitations that made many things impossible to do. Every directive in v1 had their own concept of request matching which made it very inconsistent to write, you’d need to use rewrites to chain matching logic, etc. It suffered from having every new feature being tacked on one after the other with a lack of cohesion.

Caddy v2 was a complete rewrite with a huge focus on the underlying design to build a system that would make it possible to do much more powerful things in a more pluggable way. I think it’s been a huge success.

Yeah I think you’re right - we generally added debug logs on a per-need basis, probably a good idea to add one for the filename the file server is attempting to read.

1 Like

Well there you go, @matt just made a quick commit to add debug logging for file_server, coming in the next release.

:+1: