tl;dr: Caddy runs fine, but returns a 403 on an existing file. Caddy runs as user caddy, group caddy, file is owned by caddy:caddy as well. Path is readable and writable for caddy (access.log in same path works). Requesting the access.log works as well!
1. The problem I’m having:
I set up caddy to server a static file, just for testing the setup, but I’m getting a 403 back, when requesting the index.html file. I checked all the permission issues in here already and non seems to be related. The file path is /srv/www/vrwyw/index.html
.
I configured Caddy to write an access.log to /srv/www/vrwyw/access.log
and it works fine. Even curl https://domain.tld/access.log
works as expected, while curl https://domain.tld
returns a 404 and curl https://domain.tld/index.html
returns a 403.
Trying to rescue my sanity, I even deleted index.html and cp access.log index.html
but it still fails! My assumption is, that caddy somehow forbids serving HTML files. Does that even make sense? I also tried to create files with different names: cp index.html bccess.log
and cp access.log cccess.log
. They all behave like index.html.
2. Error messages and/or full log output:
Disclaimer: I replaced the real domain with “domain.tld”, because it might be counted as company secret for now. All subdomains and file paths are unchanged.
#> curl https://test.domain.tld/index.html
HTTP/2 403
alt-svc: h3=":443"; ma=2592000
permissions-policy: interest-cohort=()
referrer-policy: no-referrer-when-downgrade
server: Caddy
x-content-type-options: nosniff
x-frame-options: DENY
x-xss-protection: 1; mode=block
date: Thu, 21 Nov 2024 10:50:18 GMT
#> curl https://test.domain.tld
HTTP/2 404
alt-svc: h3=":443"; ma=2592000
permissions-policy: interest-cohort=()
referrer-policy: no-referrer-when-downgrade
server: Caddy
x-content-type-options: nosniff
x-frame-options: DENY
x-xss-protection: 1; mode=block
date: Thu, 21 Nov 2024 10:57:06 GMT
#> curl https://test.domain.tld/access.log
HTTP/2 200
accept-ranges: bytes
alt-svc: h3=":443"; ma=2592000
content-type: text/x-log; charset=utf-8
etag: "snarr654x"
last-modified: Thu, 21 Nov 2024 10:57:06 GMT
permissions-policy: interest-cohort=()
referrer-policy: no-referrer-when-downgrade
server: Caddy
x-content-type-options: nosniff
x-frame-options: DENY
x-xss-protection: 1; mode=block
content-length: 6657
date: Thu, 21 Nov 2024 10:57:49 GMT
Corresponding log, retrieved with journalctl -u caddy --no-pager
(empty lines added for clarity):
Nov 21 10:50:15 scw-nice-cori caddy[483257]: {"level":"debug","ts":1732186215.2315962,"logger":"events","msg":"event","name":"tls_get_certificate","id":"8888db05-93ba-4c31-8c5f-f4eb165e4d43","origin":"tls","data":{"client_hello":{"CipherSuites":[4866,4867,4865,4868,49196,49200,52393,52392,49325,49195,49199,49324,49187,49191,49162,49172,49161,49171,157,49309,156,49308,61,60,53,47,159,52394,49311,158,49310,107,103,57,51,255],"ServerName":"test.domain.tld","SupportedCurves":[29,23,30,25,24,256,257,258,259,260],"SupportedPoints":"AAEC","SignatureSchemes":[1027,1283,1539,2055,2056,2057,2058,2059,2052,2053,2054,1025,1281,1537,771,769],"SupportedProtos":["h2","http/1.1"],"SupportedVersions":[772,771],"RemoteAddr":{"IP":"2.215.191.80","Port":62560,"Zone":""},"LocalAddr":{"IP":"51.158.175.161","Port":443,"Zone":""}}}}
Nov 21 10:50:15 scw-nice-cori caddy[483257]: {"level":"debug","ts":1732186215.2427142,"logger":"tls.handshake","msg":"choosing certificate","identifier":"test.domain.tld","num_choices":1}
Nov 21 10:50:15 scw-nice-cori caddy[483257]: {"level":"debug","ts":1732186215.2441688,"logger":"tls.handshake","msg":"default certificate selection results","identifier":"test.domain.tld","subjects":["test.domain.tld"],"managed":true,"issuer_key":"acme-v02.api.letsencrypt.org-directory","hash":"6c98033f7a175b8f53023703d923f9fd8f5a105cabfb5240a91b205b375c9c19"}
Nov 21 10:50:15 scw-nice-cori caddy[483257]: {"level":"debug","ts":1732186215.24433,"logger":"tls.handshake","msg":"matched certificate in cache","remote_ip":"2.215.191.80","remote_port":"62560","subjects":["test.domain.tld"],"managed":true,"expiration":1739887666,"hash":"6c98033f7a175b8f53023703d923f9fd8f5a105cabfb5240a91b205b375c9c19"}
Nov 21 10:50:15 scw-nice-cori caddy[483257]: {"level":"debug","ts":1732186215.4678802,"logger":"http.handlers.file_server","msg":"sanitized path join","site_root":"/srv/www/vrwyw","request_path":"/index.html","result":"/srv/www/vrwyw/index.html"}
Nov 21 10:50:15 scw-nice-cori caddy[483257]: {"level":"debug","ts":1732186215.472384,"logger":"http.log.error.log0","msg":"stat /srv/www/vrwyw/index.html: permission denied","request":{"remote_ip":"2.215.191.80","remote_port":"62560","client_ip":"2.215.191.80","proto":"HTTP/2.0","method":"GET","host":"test.domain.tld","uri":"/index.html","headers":{"User-Agent":["curl/8.9.1"],"Accept":["*/*"]},"tls":{"resumed":false,"version":772,"cipher_suite":4865,"proto":"h2","server_name":"test.domain.tld"}},"duration":0.00495795,"status":403,"err_id":"hxq5d8a6y","err_trace":"fileserver.(*FileServer).ServeHTTP (staticfiles.go:282)"}
Nov 21 10:50:18 scw-nice-cori caddy[483257]: {"level":"debug","ts":1732186218.2765286,"logger":"events","msg":"event","name":"tls_get_certificate","id":"c89b226e-9ec5-40ae-bc10-6ee267cff891","origin":"tls","data":{"client_hello":{"CipherSuites":[4866,4867,4865,4868,49196,49200,52393,52392,49325,49195,49199,49324,49187,49191,49162,49172,49161,49171,157,49309,156,49308,61,60,53,47,159,52394,49311,158,49310,107,103,57,51,255],"ServerName":"test.domain.tld","SupportedCurves":[29,23,30,25,24,256,257,258,259,260],"SupportedPoints":"AAEC","SignatureSchemes":[1027,1283,1539,2055,2056,2057,2058,2059,2052,2053,2054,1025,1281,1537,771,769],"SupportedProtos":["h2","http/1.1"],"SupportedVersions":[772,771],"RemoteAddr":{"IP":"2.215.191.80","Port":37626,"Zone":""},"LocalAddr":{"IP":"51.158.175.161","Port":443,"Zone":""}}}}
Nov 21 10:50:18 scw-nice-cori caddy[483257]: {"level":"debug","ts":1732186218.278414,"logger":"tls.handshake","msg":"choosing certificate","identifier":"test.domain.tld","num_choices":1}
Nov 21 10:50:18 scw-nice-cori caddy[483257]: {"level":"debug","ts":1732186218.2788136,"logger":"tls.handshake","msg":"default certificate selection results","identifier":"test.domain.tld","subjects":["test.domain.tld"],"managed":true,"issuer_key":"acme-v02.api.letsencrypt.org-directory","hash":"6c98033f7a175b8f53023703d923f9fd8f5a105cabfb5240a91b205b375c9c19"}
Nov 21 10:50:18 scw-nice-cori caddy[483257]: {"level":"debug","ts":1732186218.2790442,"logger":"tls.handshake","msg":"matched certificate in cache","remote_ip":"2.215.191.80","remote_port":"37626","subjects":["test.domain.tld"],"managed":true,"expiration":1739887666,"hash":"6c98033f7a175b8f53023703d923f9fd8f5a105cabfb5240a91b205b375c9c19"}
Nov 21 10:50:18 scw-nice-cori caddy[483257]: {"level":"debug","ts":1732186218.6354177,"logger":"http.handlers.file_server","msg":"sanitized path join","site_root":"/srv/www/vrwyw","request_path":"/index.html","result":"/srv/www/vrwyw/index.html"}
Nov 21 10:50:18 scw-nice-cori caddy[483257]: {"level":"debug","ts":1732186218.6393092,"logger":"http.log.error.log0","msg":"stat /srv/www/vrwyw/index.html: permission denied","request":{"remote_ip":"2.215.191.80","remote_port":"37626","client_ip":"2.215.191.80","proto":"HTTP/2.0","method":"HEAD","host":"test.domain.tld","uri":"/index.html","headers":{"User-Agent":["curl/8.9.1"],"Accept":["*/*"]},"tls":{"resumed":false,"version":772,"cipher_suite":4865,"proto":"h2","server_name":"test.domain.tld"}},"duration":0.002732825,"status":403,"err_id":"ztg7y85a7","err_trace":"fileserver.(*FileServer).ServeHTTP (staticfiles.go:282)"}
Nov 21 10:57:04 scw-nice-cori caddy[483257]: {"level":"debug","ts":1732186624.7450497,"logger":"tls.handshake","msg":"default certificate selection results","identifier":"test.domain.tld","subjects":["test.domain.tld"],"managed":true,"issuer_key":"acme-v02.api.letsencrypt.org-directory","hash":"6c98033f7a175b8f53023703d923f9fd8f5a105cabfb5240a91b205b375c9c19"}
Nov 21 10:57:04 scw-nice-cori caddy[483257]: {"level":"debug","ts":1732186624.745224,"logger":"tls.handshake","msg":"matched certificate in cache","remote_ip":"2.215.191.80","remote_port":"52110","subjects":["test.domain.tld"],"managed":true,"expiration":1739887666,"hash":"6c98033f7a175b8f53023703d923f9fd8f5a105cabfb5240a91b205b375c9c19"}
Nov 21 10:57:05 scw-nice-cori caddy[483257]: {"level":"debug","ts":1732186625.1403737,"logger":"http.handlers.file_server","msg":"sanitized path join","site_root":"/srv/www/vrwyw","request_path":"/","result":"/srv/www/vrwyw"}
Nov 21 10:57:05 scw-nice-cori caddy[483257]: {"level":"debug","ts":1732186625.1423483,"logger":"http.handlers.file_server","msg":"no index file in directory","path":"/srv/www/vrwyw","index_filenames":["index.html","index.txt"]}
Nov 21 10:57:05 scw-nice-cori caddy[483257]: {"level":"debug","ts":1732186625.1429286,"logger":"http.log.error.log0","msg":"{id=4s487ga1r} fileserver.(*FileServer).notFound (staticfiles.go:629): HTTP 404","request":{"remote_ip":"2.215.191.80","remote_port":"52110","client_ip":"2.215.191.80","proto":"HTTP/2.0","method":"HEAD","host":"test.domain.tld","uri":"/","headers":{"User-Agent":["curl/8.9.1"],"Accept":["*/*"]},"tls":{"resumed":false,"version":772,"cipher_suite":4865,"proto":"h2","server_name":"test.domain.tld"}},"duration":0.003613454,"status":404,"err_id":"4s487ga1r","err_trace":"fileserver.(*FileServer).notFound (staticfiles.go:629)"}
Nov 21 10:57:06 scw-nice-cori caddy[483257]: {"level":"debug","ts":1732186626.4166286,"logger":"events","msg":"event","name":"tls_get_certificate","id":"f27c10aa-889c-449e-b415-9899fe31ed11","origin":"tls","data":{"client_hello":{"CipherSuites":[4866,4867,4865,4868,49196,49200,52393,52392,49325,49195,49199,49324,49187,49191,49162,49172,49161,49171,157,49309,156,49308,61,60,53,47,159,52394,49311,158,49310,107,103,57,51,255],"ServerName":"test.domain.tld","SupportedCurves":[29,23,30,25,24,256,257,258,259,260],"SupportedPoints":"AAEC","SignatureSchemes":[1027,1283,1539,2055,2056,2057,2058,2059,2052,2053,2054,1025,1281,1537,771,769],"SupportedProtos":["h2","http/1.1"],"SupportedVersions":[772,771],"RemoteAddr":{"IP":"2.215.191.80","Port":33400,"Zone":""},"LocalAddr":{"IP":"51.158.175.161","Port":443,"Zone":""}}}}
Nov 21 10:57:06 scw-nice-cori caddy[483257]: {"level":"debug","ts":1732186626.4180145,"logger":"tls.handshake","msg":"choosing certificate","identifier":"test.domain.tld","num_choices":1}
Nov 21 10:57:06 scw-nice-cori caddy[483257]: {"level":"debug","ts":1732186626.4181175,"logger":"tls.handshake","msg":"default certificate selection results","identifier":"test.domain.tld","subjects":["test.domain.tld"],"managed":true,"issuer_key":"acme-v02.api.letsencrypt.org-directory","hash":"6c98033f7a175b8f53023703d923f9fd8f5a105cabfb5240a91b205b375c9c19"}
Nov 21 10:57:06 scw-nice-cori caddy[483257]: {"level":"debug","ts":1732186626.4181376,"logger":"tls.handshake","msg":"matched certificate in cache","remote_ip":"2.215.191.80","remote_port":"33400","subjects":["test.domain.tld"],"managed":true,"expiration":1739887666,"hash":"6c98033f7a175b8f53023703d923f9fd8f5a105cabfb5240a91b205b375c9c19"}
Nov 21 10:57:06 scw-nice-cori caddy[483257]: {"level":"debug","ts":1732186626.4511354,"logger":"http.handlers.file_server","msg":"sanitized path join","site_root":"/srv/www/vrwyw","request_path":"/","result":"/srv/www/vrwyw"}
Nov 21 10:57:06 scw-nice-cori caddy[483257]: {"level":"debug","ts":1732186626.452281,"logger":"http.handlers.file_server","msg":"no index file in directory","path":"/srv/www/vrwyw","index_filenames":["index.html","index.txt"]}
Nov 21 10:57:06 scw-nice-cori caddy[483257]: {"level":"debug","ts":1732186626.4526765,"logger":"http.log.error.log0","msg":"{id=1ih97g7vz} fileserver.(*FileServer).notFound (staticfiles.go:629): HTTP 404","request":{"remote_ip":"2.215.191.80","remote_port":"33400","client_ip":"2.215.191.80","proto":"HTTP/2.0","method":"HEAD","host":"test.domain.tld","uri":"/","headers":{"User-Agent":["curl/8.9.1"],"Accept":["*/*"]},"tls":{"resumed":false,"version":772,"cipher_suite":4865,"proto":"h2","server_name":"test.domain.tld"}},"duration":0.001601559,"status":404,"err_id":"1ih97g7vz","err_trace":"fileserver.(*FileServer).notFound (staticfiles.go:629)"}
Nov 21 10:57:49 scw-nice-cori caddy[483257]: {"level":"debug","ts":1732186669.8387926,"logger":"events","msg":"event","name":"tls_get_certificate","id":"24e9b564-b363-4c34-8e47-a41b9d9dc77b","origin":"tls","data":{"client_hello":{"CipherSuites":[4866,4867,4865,4868,49196,49200,52393,52392,49325,49195,49199,49324,49187,49191,49162,49172,49161,49171,157,49309,156,49308,61,60,53,47,159,52394,49311,158,49310,107,103,57,51,255],"ServerName":"test.domain.tld","SupportedCurves":[29,23,30,25,24,256,257,258,259,260],"SupportedPoints":"AAEC","SignatureSchemes":[1027,1283,1539,2055,2056,2057,2058,2059,2052,2053,2054,1025,1281,1537,771,769],"SupportedProtos":["h2","http/1.1"],"SupportedVersions":[772,771],"RemoteAddr":{"IP":"2.215.191.80","Port":61074,"Zone":""},"LocalAddr":{"IP":"51.158.175.161","Port":443,"Zone":""}}}}
Nov 21 10:57:49 scw-nice-cori caddy[483257]: {"level":"debug","ts":1732186669.840775,"logger":"tls.handshake","msg":"choosing certificate","identifier":"test.domain.tld","num_choices":1}
Nov 21 10:57:49 scw-nice-cori caddy[483257]: {"level":"debug","ts":1732186669.8415363,"logger":"tls.handshake","msg":"default certificate selection results","identifier":"test.domain.tld","subjects":["test.domain.tld"],"managed":true,"issuer_key":"acme-v02.api.letsencrypt.org-directory","hash":"6c98033f7a175b8f53023703d923f9fd8f5a105cabfb5240a91b205b375c9c19"}
Nov 21 10:57:49 scw-nice-cori caddy[483257]: {"level":"debug","ts":1732186669.8416667,"logger":"tls.handshake","msg":"matched certificate in cache","remote_ip":"2.215.191.80","remote_port":"61074","subjects":["test.domain.tld"],"managed":true,"expiration":1739887666,"hash":"6c98033f7a175b8f53023703d923f9fd8f5a105cabfb5240a91b205b375c9c19"}
Nov 21 10:57:49 scw-nice-cori caddy[483257]: {"level":"debug","ts":1732186669.8830025,"logger":"http.handlers.file_server","msg":"sanitized path join","site_root":"/srv/www/vrwyw","request_path":"/access.log","result":"/srv/www/vrwyw/access.log"}
Nov 21 10:57:49 scw-nice-cori caddy[483257]: {"level":"debug","ts":1732186669.88359,"logger":"http.handlers.file_server","msg":"opening file","filename":"/srv/www/vrwyw/access.log"}
3. Caddy version:
#> caddy version
v2.7.6
4. How I installed and ran Caddy:
Installed via Fedora package manager: dnf install caddy
a. System environment:
#> cat /etc/system-release
Fedora release 40 (Forty)
#> uname -a
Linux scw-nice-cori 6.11.3-200.fc40.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Oct 10 22:31:19 UTC 2024 x86_64 GNU/Linux
b. Command:
Caddy runs as a service. Service files are the default ones from the fedora package.
systemctl start caddy
c. Service/unit/compose file:
#> cat /etc/systemd/system/multi-user.target.wants/caddy.service
[Unit]
Description=Caddy web server
Documentation=https://caddyserver.com/docs/
After=network.target
[Service]
Type=notify
User=caddy
Group=caddy
ExecStartPre=/usr/bin/caddy validate --config /etc/caddy/Caddyfile
ExecStart=/usr/bin/caddy run --environ --config /etc/caddy/Caddyfile
ExecReload=/usr/bin/caddy reload --config /etc/caddy/Caddyfile
TimeoutStopSec=5s
LimitNOFILE=1048576
LimitNPROC=512
PrivateTmp=true
ProtectHome=true
ProtectSystem=full
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
[Install]
WantedBy=multi-user.target
d. My complete Caddy config:
#> cat /etc/caddy/Caddyfile
{
http_port 80
https_port 443
default_sni domain.tld
email hostmaster@domain.tld
debug
}
localhost {
respond "Caddy server is online."
}
domain.tld {
encode zstd gzip
header {
Content-Type "text/html; charset=utf-8"
Permissions-Policy interest-cohort=()
X-Content-Type-Options nosniff # no media type sniffing
X-Frame-Options DENY # clickjacking protection
Referrer-Policy no-referrer-when-downgrade # no referrer data without HTTPS
X-XSS-Protection "1; mode=block"
}
respond <<HTML
<html>
<head><title>domain.tld</title></head>
<style>html,body{margin:20vh 0;padding:0;display:flex;justify-content:center;align-items:center;background:#121212;color:#a7b2be;}</style>
<body><h1>domain.tld comes soon.</h1></body>
</html>
HTML 200
}
test.domain.tld {
encode zstd gzip
header {
Permissions-Policy interest-cohort=()
X-Content-Type-Options nosniff # no media type sniffing
X-Frame-Options DENY # clickjacking protection
Referrer-Policy no-referrer-when-downgrade # no referrer data without HTTPS
X-XSS-Protection "1; mode=block"
}
log {
output file /srv/www/vrwyw/access.log
level debug
}
# try_files {path} index.html
root * /srv/www/vrwyw
file_server
}
import Caddyfile.d/*.caddyfile
(there are no files in Caddyfile.d/)
5. Links to relevant resources:
I’m using scaleway’s fedora workstation image: