File_server browse not listing files on /

1. Caddy version (caddy version):

docker: caddy:alpine

2. How I run Caddy:


a. System environment:

Archlinux Host, alpine docker container

c. Service/unit/compose file:

version: "2"
    image: caddy:alpine
    container_name: caddy
    working_dir: /config
    restart: unless-stopped
      - 80:80
      - 443:443
      - ./caddy/:/config
      - ./caddy/caddy.conf:/etc/caddy/Caddyfile
      - ./caddy/.data/:/data
      - ./samba:/share

d. My complete Caddyfile or JSON config:

Two files, seperated by ## filename

## cady.conf
(cloudflare) {
	tls /config/certs/ /config/certs/

import /config/sites/*/caddy.conf

## /config/sites/ {
	import cloudflare
	root * /share/cdn
	log {
		format console
		output file /config/sites/

	file_server browse {
		hide .git
	@mdcheck path *.md
	route @mdcheck {
			try_files *.md /assets/templates/markdown.html

3. The problem I’m having:

I get an 404 error when I go to view the file listings of a folder, but when I go to a file, I can see the file just fine, even with templating

EDIT: subfolders that are not / work just fine
so /assets works just fine, but not /

4. Error messages and/or full log output: - View paste xkcjP < reformatted logs so linters and highlighting programs dont break,

5. What I already tried:

I rebuilt my entire config from scratch and have had no luck, just error 404, this was working just fine last week, but now it isnt for some reason and I dont know why

Turn on the debug global option, reload Caddy, then take a look at Caddy’s logs after trying a request. It should show some additional details as to why it’s not working.

To see your logs, run docker-compose logs caddy.

FYI *.md does not work when used as an argument to try_files. You should use {path}.md instead. The path matcher should work though.

1 Like

*.md does actually work in my configs, but debug completely breaks on site config for
this is the whole caddyfile for that config

:80 {
	reverse_proxy pihole
{"level":"info","ts":1641921828.7869596,"msg":"using provided configuration","config_file":"/etc/caddy/Caddyfile","config_adapter":"caddyfile"}
run: adapting config using caddyfile: /config/sites/ unrecognized directive: :80
Did you mean to define a second site? If so, you must use curly braces around each site to separate their configurations.```

When you enable global options, they must be the first thing in the entire config, including imports. So it needs to go inside your /etc/caddy/Caddyfile, at the top, like this:


That’s because *.md does not match to a file on disk, so it always falls back to /assets/templates/markdown.html. If that’s your intent, then you can just do try_files /assets/templates/markdown.html which would save some syscalls.

1 Like

logs from debug.

The weirdest part is that if I were to access
and (images contains NSFW, you have been warned)
work just fine,

EDIT: something went wrong!? why is it 500ing?! all i did was change the *.md to {path}

Hmm, might be cause templates failed to render or something. What’s the full part you changed? What’s in Caddy’s logs?

1 Like

logs for the 500 error

{"level":"debug","ts":1641994819.2463953,"logger":"tls.handshake","msg":"no matching certificate; will choose from all certificates","identifier":""}
{"level":"debug","ts":1641994819.2464316,"logger":"tls.handshake","msg":"choosing certificate","identifier":"","num_choices":1}
{"level":"debug","ts":1641994819.2464478,"logger":"tls.handshake","msg":"custom certificate selection results","identifier":"","subjects":["cloudflare origin certificate","*",""],"managed":false,"issuer_key":"","hash":"43f754a9769aa18222926916dfc46c2a3a5eeac688311beb037e42c19500c1d5"}
{"level":"debug","ts":1641994819.2464569,"logger":"tls.handshake","msg":"matched certificate in cache","subjects":["cloudflare origin certificate","*",""],"managed":false,"expiration":2108501640,"hash":"43f754a9769aa18222926916dfc46c2a3a5eeac688311beb037e42c19500c1d5"}
{"level":"debug","ts":1641994819.310624,"logger":"http.handlers.file_server","msg":"sanitized path join","site_root":"/share/cdn","request_path":"/assets/","result":"/share/cdn/assets/"}
{"level":"debug","ts":1641994819.310688,"logger":"http.handlers.file_server","msg":"no index file in directory","path":"/share/cdn/assets/","index_filenames":["index.html","index.txt"]}
{"level":"debug","ts":1641994819.3106961,"logger":"http.handlers.file_server","msg":"browse enabled; listing directory contents","path":"/share/cdn/assets/","root":"/share/cdn"}
{"level":"error","ts":1641994819.3114436,"logger":"http.log.error.log0","msg":"parsing browse template: parsing browse template file: open /*: no such file or directory","request":{"remote_addr":"","proto":"HTTP/2.0","method":"GET","host":"","uri":"/assets/","headers":{"Sec-Gpc":["1"],"Cf-Connecting-Ip":[""],"X-Forwarded-For":[""],"Sec-Fetch-Site":["none"],"Sec-Fetch-Dest":["document"],"Cf-Ipcountry":["US"],"User-Agent":["Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36"],"X-Forwarded-Proto":["https"],"Cf-Visitor":["{\"scheme\":\"https\"}"],"Upgrade-Insecure-Requests":["1"],"Accept":["text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"],"Sec-Fetch-User":["?1"],"Cdn-Loop":["cloudflare"],"Accept-Encoding":["gzip"],"Sec-Fetch-Mode":["navigate"],"Accept-Language":["en-US,en;q=0.9"],"Cf-Ray":["6cc98ac3fb3ce38e-SEA"],"Cache-Control":["max-age=0"]},"tls":{"resumed":false,"version":772,"cipher_suite":4867,"proto":"h2","proto_mutual":true,"server_name":""}},"duration":0.000879025}
{"level":"error","ts":1641994819.3114834,"logger":"http.log.access.log0","msg":"handled request","request":{"remote_addr":"","proto":"HTTP/2.0","method":"GET","host":"","uri":"/assets/","headers":{"Cf-Ipcountry":["US"],"User-Agent":["Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36"],"Sec-Fetch-Site":["none"],"Sec-Fetch-Dest":["document"],"Accept":["text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"],"Sec-Fetch-User":["?1"],"Cdn-Loop":["cloudflare"],"Accept-Encoding":["gzip"],"X-Forwarded-Proto":["https"],"Cf-Visitor":["{\"scheme\":\"https\"}"],"Upgrade-Insecure-Requests":["1"],"Cf-Ray":["6cc98ac3fb3ce38e-SEA"],"Cache-Control":["max-age=0"],"Sec-Fetch-Mode":["navigate"],"Accept-Language":["en-US,en;q=0.9"],"Cf-Connecting-Ip":[""],"X-Forwarded-For":[""],"Sec-Gpc":["1"]},"tls":{"resumed":false,"version":772,"cipher_suite":4867,"proto":"h2","proto_mutual":true,"server_name":""}},"common_log":" - - [12/Jan/2022:13:40:19 +0000] \"GET /assets/ HTTP/2.0\" 500 0","user_id":"","duration":0.000879025,"size":0,"status":500,"resp_headers":{"Server":["Caddy"]}}

And I undid the change and still getting the 500 error…

Yeah there it is, templates failed to render. Something in your template must be broken.

template, css is availiable at (because the file sharing itself is working just fine)

Figured that out, I mistyped the browse directive in file_server

but / is still 404’ing so Im back where I started

{"level":"debug","ts":1641996847.9177809,"logger":"http.handlers.file_server","msg":"sanitized path join","site_root":"/share/cdn","request_path":"/","result":"/share/cdn"}
{"level":"debug","ts":1641996847.9179192,"logger":"http.handlers.file_server","msg":"no index file in directory","path":"/share/cdn","index_filenames":["index.html","index.txt"]}
{"level":"debug","ts":1641996847.9179468,"logger":"http.handlers.file_server","msg":"browse enabled; listing directory contents","path":"/share/cdn","root":"/share/cdn"}
{"level":"error","ts":1641996847.9184728,"logger":"http.log.access.log0","msg":"handled request","request":{"remote_addr":"","proto":"HTTP/2.0","method":"GET","host":"","uri":"/","headers":{"Accept":["text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"],"Cf-Ipcountry":["T1"],"X-Forwarded-Proto":["https"],"Cache-Control":["max-age=0"],"Cf-Connecting-Ip":[""],"Accept-Encoding":["gzip"],"X-Forwarded-For":[""],"User-Agent":["Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36"],"Sec-Gpc":["1"],"Sec-Fetch-Mode":["navigate"],"Sec-Fetch-User":["?1"],"Sec-Fetch-Dest":["document"],"Cdn-Loop":["cloudflare"],"Cf-Visitor":["{\"scheme\":\"https\"}"],"Upgrade-Insecure-Requests":["1"],"Referer":[""],"Accept-Language":["en-US,en;q=0.9"],"Cookie":["cf_clearance=mzUic0_CqKVjw8ekr3UftR6Mqjij0bRd5oqhY.iDqxg-1642025543-0-150"],"Cf-Ray":["6cc9bc4ab8922bce-FRA"],"Sec-Fetch-Site":["same-origin"]},"tls":{"resumed":false,"version":772,"cipher_suite":4867,"proto":"h2","proto_mutual":true,"server_name":""}},"common_log":" - - [12/Jan/2022:14:14:07 +0000] \"GET / HTTP/2.0\" 404 0","user_id":"","duration":0.000765317,"size":0,"status":404,"resp_headers":{"Server":["Caddy"]}}

Only thing I can think of is that it might be some kind of file permission issue with the directory it’s trying to read from. That’s definitely strange.

Try getting a shell into the container with docker-compose exec caddy /bin/sh and look around at the permissions in /share.

/share uses dperson/samba:latest for its samba share, which has a permission fixer to set the permissions to owner 100:101 and chmod 777, and since caddy in the container runs as root, it should not be having any permission issues,

EDIT: also if there were permission issues, everything else wouldnt work either, just / stopped working for some reason

any ideas?

I have removed anything fancy such as my markdown parsing template, and I am still having this issue {
	import cloudflare
	root * /share/cdn
	file_server browse

	log {
		output file /config/sites/

Can you make a minimally reproducible example that exhibits the behaviour?

Like, make a new directory with only one file in it, try removing templates, etc.

I’m not sure what’s going on, and if it might be a bug I need a way to be able to replicate the issue precisely so I can debug it.

1 Like

its a zip file, of this structure


the setup is meant to mimic my current setup so you can see if anything went wrong there,
only differences are TLS and domain specifics

EDIT: I realized I scuffed the ports on docker-compose, my bad, make them open 8080
EDIT2: I realized I broke more than just that…

link with fixed zip

Okay, thanks for that - I’m away for the weekend, I’ll take a look when I’m back, if someone else doesn’t try it out first

1 Like

Sorry I took so long on this.

I tried out your Docker stack on my Windows machine and it works just fine, the browse shows up. So my suspicion is that it’s a file permission issue (cause Windows does weird things with file permissions, making things more permissive by default when crossing the border over to Linux).

I’ll have to try it on my Linux laptop (I can probably do that tomorrow).

Just as something to try if you have a minute, I committed to a branch on the Caddy repo in a couple spots where I think some additional debug logging is appropriate.

If you build from this Dockerfile instead, you should get a build from that branch. Could you try this out?

FROM caddy:2.4.6-builder AS builder

RUN xcaddy build browse-errors

FROM caddy:2.4.6

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

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