1. The problem I’m having:
I am trying to set up a Caddy server to serve a local directory on my Raspberry Pi over HTTPS using a DuckDNS domain (kev1.duckdns.org). The goal is to allow access to the contents of a directory located at /mnt/external/data/media/newspapers on my external drive via HTTPS.
The Caddy server is running in a Docker container, and I am using the DuckDNS module for DNS challenge verification to obtain an SSL/TLS certificate from Let’s Encrypt.
However, I am facing two issues:
1. SSL certificate verification error when accessing https://kev1.duckdns.org.
2. Directory contents are not visible when visiting https://kev1.duckdns.org.
CLI outputs from my Raspberry:
curl -v http://kev1.duckdns.org
* Trying 115.70.40.36:80...
* Connected to kev1.duckdns.org (115.70.40.36) port 80 (#0)
> GET / HTTP/1.1
> Host: kev1.duckdns.org
> User-Agent: curl/7.88.1
> Accept: */*
>
< HTTP/1.1 302 Found
< Location: https://kev1.duckdns.org/webpages/login.html
< Connection: close
<
* Closing connection 0
and
* Trying 115.70.40.36:443...
* Connected to kev1.duckdns.org (115.70.40.36) port 443 (#0)
* ALPN: offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* CAfile: /etc/ssl/certs/ca-certificates.crt
* CApath: /etc/ssl/certs
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (OUT), TLS alert, unknown CA (560):
* SSL certificate problem: unable to get local issuer certificate
* Closing connection 0
curl: (60) SSL certificate problem: unable to get local issuer certificate
More details here: https://curl.se/docs/sslcerts.html
2. Error messages and/or full log output:
caddy | {"level":"info","ts":1724716025.5288093,"msg":"using config from file","file":"/etc/caddy/Caddyfile"}
caddy | {"level":"info","ts":1724716025.5318816,"msg":"adapted config to JSON","adapter":"caddyfile"}
caddy | {"level":"warn","ts":1724716025.5319395,"msg":"Caddyfile input is not formatted; run 'caddy fmt --overwrite' to fix inconsistencies","adapter":"caddyfile","file":"/etc/caddy/Caddyfile","line":2}
caddy | {"level":"info","ts":1724716025.5346239,"logger":"admin","msg":"admin endpoint started","address":"localhost:2019","enforce_origin":false,"origins":["//localhost:2019","//[::1]:2019","//127.0.0.1:2019"]}
caddy | {"level":"info","ts":1724716025.5352125,"logger":"tls.cache.maintenance","msg":"started background certificate maintenance","cache":"0x40004b6a80"}
caddy | {"level":"info","ts":1724716025.5354228,"logger":"http.auto_https","msg":"server is listening only on the HTTPS port but has no TLS connection policies; adding one to enable TLS","server_name":"srv0","https_port":443}
caddy | {"level":"info","ts":1724716025.535471,"logger":"http.auto_https","msg":"enabling automatic HTTP->HTTPS redirects","server_name":"srv0"}
caddy | {"level":"info","ts":1724716025.5362732,"logger":"http","msg":"enabling HTTP/3 listener","addr":":443"}
caddy | {"level":"info","ts":1724716025.5366695,"msg":"failed to sufficiently increase receive buffer size (was: 208 kiB, wanted: 7168 kiB, got: 416 kiB). See https://github.com/quic-go/quic-go/wiki/UDP-Buffer-Sizes for details."}
caddy | {"level":"info","ts":1724716025.5372162,"logger":"http.log","msg":"server running","name":"srv0","protocols":["h1","h2","h3"]}
caddy | {"level":"info","ts":1724716025.5375028,"logger":"http.log","msg":"server running","name":"remaining_auto_https_redirects","protocols":["h1","h2","h3"]}
caddy | {"level":"info","ts":1724716025.5375445,"logger":"http","msg":"enabling automatic TLS certificate management","domains":["kev1.duckdns.org"]}
caddy | {"level":"info","ts":1724716025.5381725,"msg":"autosaved config (load with --resume flag)","file":"/config/caddy/autosave.json"}
caddy | {"level":"info","ts":1724716025.5382175,"msg":"serving initial configuration"}
caddy | {"level":"info","ts":1724716025.5389495,"logger":"tls.obtain","msg":"acquiring lock","identifier":"kev1.duckdns.org"}
caddy | {"level":"info","ts":1724716025.5463822,"logger":"tls","msg":"cleaning storage unit","storage":"FileStorage:/data/caddy"}
caddy | {"level":"info","ts":1724716025.5479794,"logger":"tls","msg":"finished cleaning storage units"}
caddy | {"level":"info","ts":1724716025.5489483,"logger":"tls.obtain","msg":"lock acquired","identifier":"kev1.duckdns.org"}
caddy | {"level":"info","ts":1724716025.5492709,"logger":"tls.obtain","msg":"obtaining certificate","identifier":"kev1.duckdns.org"}
caddy | {"level":"info","ts":1724716026.4610503,"logger":"tls.issuance.acme","msg":"waiting on internal rate limiter","identifiers":["kev1.duckdns.org"],"ca":"https://acme-v02.api.letsencrypt.org/directory","account":""}
caddy | {"level":"info","ts":1724716026.4611108,"logger":"tls.issuance.acme","msg":"done waiting on internal rate limiter","identifiers":["kev1.duckdns.org"],"ca":"https://acme-v02.api.letsencrypt.org/directory","account":""}
caddy | {"level":"info","ts":1724716026.4611936,"logger":"tls.issuance.acme","msg":"using ACME account","account_id":"https://acme-v02.api.letsencrypt.org/acme/acct/1912538936","account_contact":[]}
caddy | {"level":"info","ts":1724716026.8499134,"logger":"tls.issuance.acme.acme_client","msg":"trying to solve challenge","identifier":"kev1.duckdns.org","challenge_type":"dns-01","ca":"https://acme-v02.api.letsencrypt.org/directory"}
caddy | {"level":"info","ts":1724716032.8179328,"logger":"tls.issuance.acme.acme_client","msg":"authorization finalized","identifier":"kev1.duckdns.org","authz_status":"valid"}
caddy | {"level":"info","ts":1724716032.8179865,"logger":"tls.issuance.acme.acme_client","msg":"validations succeeded; finalizing order","order":"https://acme-v02.api.letsencrypt.org/acme/order/1912538936/299765463756"}
caddy | {"level":"info","ts":1724716033.594002,"logger":"tls.issuance.acme.acme_client","msg":"got renewal info","names":["kev1.duckdns.org"],"window_start":1729811291.3333333,"window_end":1729984091.3333333,"selected_time":1729879771,"recheck_after":1724737633.5939832,"explanation_url":""}
caddy | {"level":"info","ts":1724716033.9575677,"logger":"tls.issuance.acme.acme_client","msg":"got renewal info","names":["kev1.duckdns.org"],"window_start":1729811291.3333333,"window_end":1729984091.3333333,"selected_time":1729895772,"recheck_after":1724737633.9575586,"explanation_url":""}
caddy | {"level":"info","ts":1724716033.9576702,"logger":"tls.issuance.acme.acme_client","msg":"successfully downloaded available certificate chains","count":2,"first_url":"https://acme-v02.api.letsencrypt.org/acme/cert/03fa331ddd7bfde15890e327d053c531445f"}
caddy | {"level":"info","ts":1724716033.959345,"logger":"tls.obtain","msg":"certificate obtained successfully","identifier":"kev1.duckdns.org","issuer":"acme-v02.api.letsencrypt.org-directory"}
caddy | {"level":"info","ts":1724716033.9600403,"logger":"tls.obtain","msg":"releasing lock","identifier":"kev1.duckdns.org"}
3. Caddy version:
4. How I installed and ran Caddy:
With Docker Compose and a custom DuckDNS module:
caddy:
image: serfriz/caddy-duckdns:latest
container_name: caddy
restart: unless-stopped
ports:
- "80:80" # HTTP port
- "443:443" # HTTPS port
volumes:
- ./config/caddy:/config # Mount config directory for Caddy
- ./Caddyfile:/etc/caddy/Caddyfile # Mount your custom Caddyfile
- /mnt/external/data/media/newspapers:/srv # Mount your newspapers folder
environment:
- PUID=1000
- PGID=1000
- TZ=Australia/Sydney
- DUCKDNS_API_TOKEN=b3xxx-xxx-xxx-8e
volumes:
caddy_data:
external: true
caddy_config:
external: true
a. System environment:
PRETTY_NAME="Debian GNU/Linux 12 (bookworm)"
NAME="Debian GNU/Linux"
VERSION_ID="12"
VERSION="12 (bookworm)"
VERSION_CODENAME=bookworm
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"
Architecture:
aarch64
Docker Version:
Docker version 27.1.2, build d01f264
Docker Compose Version:
Docker Compose version v2.20.2
Caddy Version:
v2.8.4 h1:q3pe0wpBj1OcHFZ3n/1nl4V4bxBrYoSoab7rL9BMYNk=
Docker Managed by systemd:
Yes, Docker is managed by systemd.
b. Command:
sudo docker compose up -d
c. Service/unit/compose file:
See above please
d. My complete Caddy config:
kev1.duckdns.org {
tls {
dns duckdns {env.DUCKDNS_API_TOKEN}
}
root * /srv
# Enable file server with directory browsing
file_server browse
# Log access to a specific file
log {
output file /var/log/caddy/access.log
}
}
5. Links to relevant resources:
I’d greatly appreciate if someone could point me in the right direction!