Conf Caddy addon Home assistant 404 Error

Hi. Welcome! :slight_smile:

1. The problem I’m having:

I try to configure caddy fileserver but I have 404 error.

I use the url: https://mydomain.duckdns.org/index.html
And I have on server the file in the path: /srv/www/index.html
I gave the permissions with: chmod -r 777 /srv/

My conf is:
{
debug
}
https://mydomain.duckdns.org {
root * /srv/www
file_server browse
}

2. Error messages and/or full log output:

in the log I have:

{“remote_ip”:“xxx.xxx.xxx.xxx”,“remote_port”:“38585”,“client_ip”:“xxx.xxx.xxx.xxx”,“proto”:“HTTP/2.0”,“method”:“GET”,“host”:“mydomain.duckdns.org”,“uri”:“/index.html”,“headers”:{“Accept-Encoding”:[“gzip, deflate, br, zstd”],“Sec-Fetch-Dest”:[“document”],“Accept-Language”:[“it-IT,it;q=0.9,en-US;q=0.8,en;q=0.7”],“Sec-Fetch-User”:[“?1”],“Priority”:[“u=0, i”],“Sec-Fetch-Site”:[“none”],“Sec-Fetch-Mode”:[“navigate”],“Dnt”:[“1”],“Sec-Ch-Ua”:[“"Google Chrome";v="131", "Chromium";v="131", "Not_A Brand";v="24"”],“Sec-Ch-Ua-Platform”:[“"Windows"”],“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.7”],“Sec-Ch-Ua-Mobile”:[“?0”],“User-Agent”:[“Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36”],“Upgrade-Insecure-Requests”:[“1”],“Cache-Control”:[“max-age=0”]},“tls”:{“resumed”:false,“version”:772,“cipher_suite”:4867,“proto”:“h2”,“server_name”:“mydomain.duckdns.org”}},“duration”:0.000068157,“status”:404,“err_id”:“zc06rf35m”,“err_trace”:“fileserver.(*FileServer).notFound (staticfiles.go:705)”}

I see in the log when start caddy:
{“level”:“debug”,“ts”:1738601880.577652,“logger”:“http.auto_https”,“msg”:“adjusted config”,“tls”:{“automation”:{“policies”:[{}]}},“http”:{“servers”:{“remaining_auto_https_redirects”:{“listen”:[“:80”],“routes”:[{},{}]},“srv0”:{“listen”:[“:443”],“routes”:[{“handle”:[{“handler”:“subroute”,“routes”:[{“handle”:[{“handler”:“vars”,“root”:“/srv/www”},{“browse”:{},“handler”:“file_server”,“hide”:[“/config/Caddyfile”]}]}]}],“terminal”:true}],“tls_connection_policies”:[{}],“automatic_https”:{}}}}}

3. Caddy version:

Add-on: Caddy 2
Open source web and proxy server with automatic HTTPS

Add-on version: 2.0.2
You are running the latest version of this add-on.
System: Home Assistant OS 14.2 (amd64 / qemux86-64)
Home Assistant Core: 2025.1.4
Home Assistant Supervisor: 2024.12.3

Please, share the above information when looking for help
or support in, e.g., GitHub, forums or the Discord chat.

s6-rc: info: service base-addon-banner successfully started
s6-rc: info: service fix-attrs: starting
s6-rc: info: service base-addon-log-level: starting
s6-rc: info: service fix-attrs successfully started
Log level is set to DEBUG
s6-rc: info: service base-addon-log-level successfully started
s6-rc: info: service legacy-cont-init: starting
s6-rc: info: service legacy-cont-init successfully started
s6-rc: info: service caddy: starting
s6-rc: info: service caddy successfully started
s6-rc: info: service legacy-services: starting
INFO: Prepare Caddy…
INFO: Checking path: /config/caddy
s6-rc: info: service legacy-services successfully started
INFO: Use built-in Caddy
v2.9.1 h1:OEYiZ7DbCzAWVb6TNEkjRcSCRGHVoZsJinoDR/n9oaY=

4. How I installed and ran Caddy:

Run Caddy with HomeAssistant AddOn

a. System environment:

Home Assistant OS 14.2 (amd64 / qemux86-64)

You specify Caddy version as simply Caddy 2. I’m not great with Caddy, but I suspect something. I found in the documentation for the root directive:
“Prior to v2.8.0, the <path> argument could be confused by the parser for a matcher token if it began with /, so it was necessary to specify a wildcard matcher token (*).”

Later, it says:
The root directive is commonly paired with file_server to serve static files and/or with php_fastcgi to serve a PHP site:

example.com {
	root * /srv
	file_server
}

So if I’m understanding correctly, this directive sets the root directory for serving files and when a request comes in for /index.html, Caddy looks for the file at /srv/www/index.html, which is correct.

In the file_server directive, it states:
" A static file server that supports real and virtual file systems. It forms file paths by appending the request’s URI path to the site’s root path.

"By default, it enforces canonical URIs; meaning HTTP redirects will be issued for requests to directories that do not end with a trailing slash (to add it), or requests to files that have a trailing slash (to remove it). However, redirects are not issued if an internal rewrite modifies the last element of the path (the filename).

"Most often, the file_server directive is paired with the root directive to set the file root for the whole site. This directive also has a root subdirective (see below) to set the root only for this handler (not recommended).

" When using browse, the default output is produced by the the HTML template. Clients may request the directory listing as either JSON or plaintext, by using the Accept: application/json or Accept: text/plain headers respectively. The JSON output can be useful for scripting, and the plaintext output can be useful for human terminal usage."

So from my limited understand, it looks like your Caddyfile should be:

{
debug
}
https://mydomain.duckdns.org {
        root * /srv/www
        file_server browse {
                index index.html
        }
}

Hello TheRottom, thank you so much for the help…

I try you CaddyFile.

But not work :frowning:
whether I invoke the urls:
mydomain.duckdns.org/index.html
mydomain.duckdns.org/index

the log say:

{
"level": "debug",
"ts": 1738857544.7539551,
"logger": "http.handlers.file_server",
"msg": "sanitized path join",
"site_root": "/srv/www",
"fs": "",
"request_path": "/index",
"result": "/srv/www/index"
}
{
"level": "debug",
"ts": 1738857544.7540944,
"logger": "http.log.error",
"msg": "{id=9gw5r70iq} fileserver.(*FileServer).notFound (staticfiles.go:705): HTTP 404",
"request": {
"remote_ip": "151.64.117.188",
"remote_port": "1920",
"client_ip": "151.64.117.188",
"proto": "HTTP/2.0",
"method": "GET",
"host": "mydomain.duckdns.org",
"uri": "/index",
"headers": {
    "Accept-Language": [
        "it-IT,it;q=0.9,en-US;q=0.8,en;q=0.7"
    ],
    "Sec-Ch-Ua-Platform": [
        "\"Windows\""
    ],
    "Sec-Fetch-Site": [
        "none"
    ],
    "Dnt": [
        "1"
    ],
    "Sec-Ch-Ua": [
        "\"Google Chrome\";v=\"131\", \"Chromium\";v=\"131\", \"Not_A Brand\";v=\"24\""
    ],
    "Sec-Fetch-Mode": [
        "navigate"
    ],
    "Sec-Ch-Ua-Mobile": [
        "?0"
    ],
    "Accept-Encoding": [
        "gzip, deflate, br, zstd"
    ],
    "Upgrade-Insecure-Requests": [
        "1"
    ],
    "User-Agent": [
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36"
    ],
    "Sec-Fetch-User": [
        "?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.7"
    ],
    "Sec-Fetch-Dest": [
        "document"
    ],
    "Priority": [
        "u=0, i"
    ]
},
"tls": {
    "resumed": true,
    "version": 772,
    "cipher_suite": 4867,
    "proto": "h2",
    "server_name": "mydomain.duckdns.org"
}
},
"duration": 0.000148647,
"status": 404,
"err_id": "9gw5r70iq",
"err_trace": "fileserver.(*FileServer).notFound (staticfiles.go:705)"
}
'

'
{
    "level": "debug",
    "ts": 1738858042.6028745,
    "logger": "http.handlers.file_server",
    "msg": "sanitized path join",
    "site_root": "/srv/www",
    "fs": "",
    "request_path": "/index.html",
    "result": "/srv/www/index.html"
}
{
    "level": "debug",
    "ts": 1738858042.6029818,
    "logger": "http.log.error",
    "msg": "{id=iv2frm6ax} fileserver.(*FileServer).notFound (staticfiles.go:705): HTTP 404",
    "request": {
        "remote_ip": "151.64.117.188",
        "remote_port": "2727",
        "client_ip": "151.64.117.188",
        "proto": "HTTP/2.0",
        "method": "GET",
        "host": "mydomain.duckdns.org",
        "uri": "/index.html",
        "headers": {
            "Upgrade-Insecure-Requests": [
                "1"
            ],
            "Sec-Fetch-Site": [
                "none"
            ],
            "Sec-Fetch-Mode": [
                "navigate"
            ],
            "Dnt": [
                "1"
            ],
            "User-Agent": [
                "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36"
            ],
            "Sec-Fetch-Dest": [
                "document"
            ],
            "Sec-Ch-Ua": [
                "\"Google Chrome\";v=\"131\", \"Chromium\";v=\"131\", \"Not_A Brand\";v=\"24\""
            ],
            "Sec-Ch-Ua-Platform": [
                "\"Windows\""
            ],
            "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.7"
            ],
            "Sec-Fetch-User": [
                "?1"
            ],
            "Priority": [
                "u=0, i"
            ],
            "Accept-Language": [
                "it-IT,it;q=0.9,en-US;q=0.8,en;q=0.7"
            ],
            "Sec-Ch-Ua-Mobile": [
                "?0"
            ],
            "Accept-Encoding": [
                "gzip, deflate, br, zstd"
            ]
        },
        "tls": {
            "resumed": false,
            "version": 772,
            "cipher_suite": 4867,
            "proto": "h2",
            "server_name": "mydomain.duckdns.org"
        }
    },
    "duration": 0.000097592,
    "status": 404,
    "err_id": "iv2frm6ax",
    "err_trace": "fileserver.(*FileServer).notFound (staticfiles.go:705)"
}

When start with your configuration I see in the log:

{
    "level": "debug",
    "ts": 1738858013.87577,
    "logger": "http.auto_https",
    "msg": "adjusted config",
    "tls": {
        "automation": {
            "policies": [
                {}
            ]
        }
    },
    "http": {
        "servers": {
            "remaining_auto_https_redirects": {
                "listen": [
                    ":80"
                ],
                "routes": [
                    {},
                    {},
                    {}
                ]
            },
            "srv0": {
                "listen": [
                    ":443"
                ],
                "routes": [
                    {
                        "handle": [
                            {
                                "handler": "subroute",
                                "routes": [
                                    {
                                        "handle": [
                                            {
                                                "handler": "vars",
                                                "root": "/srv/www"
                                            },
                                            {
                                                "browse": {},
                                                "handler": "file_server",
                                                "hide": [
                                                    "/config/Caddyfile"
                                                ],
                                                "index_names": [
                                                    "index.html"
                                                ]
                                            }
                                        ]
                                    }
                                ]
                            }
                        ],
                        "terminal": true
                    }
                ],
                "tls_connection_policies": [
                    {}
                ],
                "automatic_https": {}
            }
        }
    }
}

Your suggestion seems right to me! but not working :frowning:

anyway thanks

Can you use:

sudo ls -la /srv/www

and post the output? It almost seems like it’s not finding the index.html file in the /srv/www directory.