1. The problem I’m having:
I am attempting to run a Jellyfin server on a Ubuntu machine, using Caddy as a reverse proxy/to enable HTTPS support. Issue is that the reverse proxy appears to be working, but traffic is not auto routed to HTTPS like I would expect Caddy to do. Jellyfin by default handles traffic on port 80 (HTTP). I have my router port forwarded from external port 80, to internal port 8096. I have verified the port is actually open, and as stated before, I can access the Jellyfin server through my DNS I have linked with Caddy, but Caddy isn’t using HTTPS. I am using a DNS through DuckDNS. I also have a port forward rule for port 443 (HTTPS) to internal port 8920, but it still appears closed because there is no traffic listening on that port in Jellyfin yet (or maybe I won’t need that at all if Caddy will work).
The more explicit of an explanation, the better. I am fairly new to this stuff, but pick up things quickly.
EDIT: I have a base URL of /jellyfin for the server and I read here: jellyfin(dot)org/docs/general/networking/caddy#subpath (can only have 4 links in a post since this is a new account) that there are additional changes in the Caddyfile
that need to be made, namely adding a redir
and adding the base url to the reverse proxy command, but still no luck. It isn’t serving over HTTPS.
2. Error messages and/or full log output:
-- Boot b3338b53e84c4c5f83544bda582d078c --
Dec 31 17:40:35 connor-OptiPlex-7060 systemd[1]: Starting Caddy...
Dec 31 17:40:35 connor-OptiPlex-7060 caddy[1587]: caddy.HomeDir=/var/lib/caddy
Dec 31 17:40:35 connor-OptiPlex-7060 caddy[1587]: caddy.AppDataDir=/var/lib/caddy/.local/share/caddy
Dec 31 17:40:35 connor-OptiPlex-7060 caddy[1587]: caddy.AppConfigDir=/var/lib/caddy/.config/caddy
Dec 31 17:40:35 connor-OptiPlex-7060 caddy[1587]: caddy.ConfigAutosavePath=/var/lib/caddy/.config/caddy/autosave.json
Dec 31 17:40:35 connor-OptiPlex-7060 caddy[1587]: caddy.Version=v2.7.6 h1:w0NymbG2m9PcvKWsrXO6EEkY9Ru4FJK8uQbYcev1p3A=
Dec 31 17:40:35 connor-OptiPlex-7060 caddy[1587]: runtime.GOOS=linux
Dec 31 17:40:35 connor-OptiPlex-7060 caddy[1587]: runtime.GOARCH=amd64
Dec 31 17:40:35 connor-OptiPlex-7060 caddy[1587]: runtime.Compiler=gc
Dec 31 17:40:35 connor-OptiPlex-7060 caddy[1587]: runtime.NumCPU=6
Dec 31 17:40:35 connor-OptiPlex-7060 caddy[1587]: runtime.GOMAXPROCS=6
Dec 31 17:40:35 connor-OptiPlex-7060 caddy[1587]: runtime.Version=go1.21.4
Dec 31 17:40:35 connor-OptiPlex-7060 caddy[1587]: os.Getwd=/
Dec 31 17:40:35 connor-OptiPlex-7060 caddy[1587]: LANG=en_US.UTF-8
Dec 31 17:40:35 connor-OptiPlex-7060 caddy[1587]: PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin
Dec 31 17:40:35 connor-OptiPlex-7060 caddy[1587]: XDG_DATA_DIRS=/var/lib/flatpak/exports/share:/usr/local/share/:/usr/share/
Dec 31 17:40:35 connor-OptiPlex-7060 caddy[1587]: NOTIFY_SOCKET=/run/systemd/notify
Dec 31 17:40:35 connor-OptiPlex-7060 caddy[1587]: HOME=/var/lib/caddy
Dec 31 17:40:35 connor-OptiPlex-7060 caddy[1587]: LOGNAME=caddy
Dec 31 17:40:35 connor-OptiPlex-7060 caddy[1587]: USER=caddy
Dec 31 17:40:35 connor-OptiPlex-7060 caddy[1587]: INVOCATION_ID=ac3acbb1b746444798a1f22280896553
Dec 31 17:40:35 connor-OptiPlex-7060 caddy[1587]: JOURNAL_STREAM=8:25036
Dec 31 17:40:35 connor-OptiPlex-7060 caddy[1587]: SYSTEMD_EXEC_PID=1587
Dec 31 17:40:35 connor-OptiPlex-7060 caddy[1587]: GOTRACEBACK=none
Dec 31 17:40:35 connor-OptiPlex-7060 caddy[1587]: {"level":"info","ts":1704062435.6391742,"msg":"using provided configuration","config_file":"/etc/caddy/Caddyfile","config_adapter":""}
Dec 31 17:40:35 connor-OptiPlex-7060 caddy[1587]: {"level":"warn","ts":1704062435.6424487,"msg":"Caddyfile input is not formatted; run 'caddy fmt --overwrite' to fix inconsistencies","adapter":"caddyfile","file"
:"/etc/caddy/Caddyfile","line":10}
Dec 31 17:40:35 connor-OptiPlex-7060 caddy[1587]: {"level":"info","ts":1704062435.6440113,"logger":"admin","msg":"admin endpoint started","address":"localhost:2019","enforce_origin":false,"origins":["//[::1]:201
9","//127.0.0.1:2019","//localhost:2019"]}
Dec 31 17:40:35 connor-OptiPlex-7060 caddy[1587]: {"level":"info","ts":1704062435.645218,"logger":"http.auto_https","msg":"server is listening only on the HTTPS port but has no TLS connection policies; adding on
e to enable TLS","server_name":"srv0","https_port":443}
Dec 31 17:40:35 connor-OptiPlex-7060 caddy[1587]: {"level":"info","ts":1704062435.6452408,"logger":"http.auto_https","msg":"enabling automatic HTTP->HTTPS redirects","server_name":"srv0"}
Dec 31 17:40:35 connor-OptiPlex-7060 caddy[1587]: {"level":"info","ts":1704062435.6454442,"logger":"http","msg":"enabling HTTP/3 listener","addr":":443"}
Dec 31 17:40:35 connor-OptiPlex-7060 caddy[1587]: {"level":"info","ts":1704062435.6460683,"msg":"failed to sufficiently increase receive buffer size (was: 208 kiB, wanted: 2048 kiB, got: 416 kiB). See https://gi
thub.com/quic-go/quic-go/wiki/UDP-Buffer-Sizes for details."}
Dec 31 17:40:35 connor-OptiPlex-7060 caddy[1587]: {"level":"info","ts":1704062435.646239,"logger":"tls.cache.maintenance","msg":"started background certificate maintenance","cache":"0xc0004c4400"}
Dec 31 17:40:35 connor-OptiPlex-7060 caddy[1587]: {"level":"info","ts":1704062435.6502075,"logger":"http.log","msg":"server running","name":"srv0","protocols":["h1","h2","h3"]}
Dec 31 17:40:35 connor-OptiPlex-7060 caddy[1587]: {"level":"info","ts":1704062435.6503255,"logger":"http.log","msg":"server running","name":"remaining_auto_https_redirects","protocols":["h1","h2","h3"]}
Dec 31 17:40:35 connor-OptiPlex-7060 caddy[1587]: {"level":"info","ts":1704062435.6503305,"logger":"http","msg":"enabling automatic TLS certificate management","domains":["dz-jellyfin.duckdns.org"]}
Dec 31 17:40:35 connor-OptiPlex-7060 caddy[1587]: {"level":"info","ts":1704062435.6507232,"logger":"tls.obtain","msg":"acquiring lock","identifier":"dz-jellyfin.duckdns.org"}
Dec 31 17:40:35 connor-OptiPlex-7060 caddy[1587]: {"level":"info","ts":1704062435.6520736,"msg":"autosaved config (load with --resume flag)","file":"/var/lib/caddy/.config/caddy/autosave.json"}
Dec 31 17:40:35 connor-OptiPlex-7060 caddy[1587]: {"level":"info","ts":1704062435.6521375,"msg":"serving initial configuration"}
Dec 31 17:40:35 connor-OptiPlex-7060 systemd[1]: Started Caddy.
Dec 31 17:40:35 connor-OptiPlex-7060 caddy[1587]: {"level":"info","ts":1704062435.655744,"logger":"tls.obtain","msg":"lock acquired","identifier":"dz-jellyfin.duckdns.org"}
Dec 31 17:40:35 connor-OptiPlex-7060 caddy[1587]: {"level":"info","ts":1704062435.6558774,"logger":"tls.obtain","msg":"obtaining certificate","identifier":"dz-jellyfin.duckdns.org"}
Dec 31 17:40:35 connor-OptiPlex-7060 caddy[1587]: {"level":"warn","ts":1704062435.659813,"logger":"tls","msg":"storage cleaning happened too recently; skipping for now","storage":"FileStorage:/var/lib/caddy/.loc
al/share/caddy","instance":"f910ed84-ef03-4fbe-8500-86f0fa09942a","try_again":1704148835.6598113,"try_again_in":86399.999999771}
Dec 31 17:40:35 connor-OptiPlex-7060 caddy[1587]: {"level":"info","ts":1704062435.6598668,"logger":"tls","msg":"finished cleaning storage units"}
Dec 31 17:40:35 connor-OptiPlex-7060 caddy[1587]: {"level":"info","ts":1704062435.6637447,"logger":"tls.issuance.acme","msg":"waiting on internal rate limiter","identifiers":["dz-jellyfin.duckdns.org"],"ca":"htt
ps://acme-v02.api.letsencrypt.org/directory","account":""}
Dec 31 17:40:35 connor-OptiPlex-7060 caddy[1587]: {"level":"info","ts":1704062435.6637595,"logger":"tls.issuance.acme","msg":"done waiting on internal rate limiter","identifiers":["dz-jellyfin.duckdns.org"],"ca"
:"https://acme-v02.api.letsencrypt.org/directory","account":""}
Dec 31 17:40:35 connor-OptiPlex-7060 caddy[1587]: {"level":"info","ts":1704062435.698737,"logger":"dynamic_dns","msg":"domain not found in DNS","domain":"jellyfin.dz-jellyfin.duckdns.org"}
Dec 31 17:40:35 connor-OptiPlex-7060 caddy[1587]: {"level":"info","ts":1704062435.6987503,"logger":"dynamic_dns","msg":"domain not found in DNS","domain":"jellyfin.dz-jellyfin.duckdns.org"}
Dec 31 17:40:36 connor-OptiPlex-7060 caddy[1587]: {"level":"warn","ts":1704062436.198032,"logger":"dynamic_dns.ip_sources.simple_http","msg":"no IP found; consider disabling this IP version","type":"IPv6"}
Dec 31 17:40:36 connor-OptiPlex-7060 caddy[1587]: {"level":"info","ts":1704062436.1980567,"logger":"dynamic_dns","msg":"updating DNS record","zone":"dz-jellyfin.duckdns.org","type":"A","name":"jellyfin","value":"<PUBLIC IP>","ttl":0}
Dec 31 17:40:36 connor-OptiPlex-7060 caddy[1587]: {"level":"info","ts":1704062436.3247044,"logger":"dynamic_dns","msg":"finished updating DNS","current_ips":["<PUBLIC IP>"]}
Dec 31 17:40:36 connor-OptiPlex-7060 caddy[1587]: {"level":"info","ts":1704062436.3962328,"logger":"tls.issuance.acme.acme_client","msg":"trying to solve challenge","identifier":"dz-jellyfin.duckdns.org","challenge_type":"dns-01","ca":"https://acme-v02.api.letsencrypt.org/directory"}
Dec 31 17:40:36 connor-OptiPlex-7060 caddy[1587]: {"level":"error","ts":1704062436.4978316,"logger":"tls.issuance.acme.acme_client","msg":"cleaning up solver","identifier":"dz-jellyfin.duckdns.org","challenge_type":"dns-01","error":"no memory of presenting a DNS record for \"_acme-challenge.dz-jellyfin.duckdns.org\" (usually OK if presenting also failed)"}
Dec 31 17:40:36 connor-OptiPlex-7060 caddy[1587]: {"level":"error","ts":1704062436.6204655,"logger":"tls.obtain","msg":"could not get certificate from issuer","identifier":"dz-jellyfin.duckdns.org","issuer":"acme-v02.api.letsencrypt.org-directory","error":"[dz-jellyfin.duckdns.org] solving challenges: presenting for challenge: adding temporary record for zone \"duckdns.org.\": DuckDNS request failed, expected (OK) but got (KO), url: [https://www.duckdns.org/update?domains=dz-jellyfin.duckdns.org&token=&txt=dz5ntqrcbmw2XOyO96DW6LxtV99C-cpoPsY2am2T7wE&verbose=true], body: KO (order=https://acme-v02.api.letsencrypt.org/acme/order/1493309776/233312529576) (ca=https://acme-v02.api.letsencrypt.org/directory)"}
Dec 31 17:40:36 connor-OptiPlex-7060 caddy[1587]: {"level":"info","ts":1704062436.6218135,"logger":"tls.issuance.zerossl","msg":"waiting on internal rate limiter","identifiers":["dz-jellyfin.duckdns.org"],"ca":"https://acme.zerossl.com/v2/DV90","account":"caddy@zerossl.com"}
Dec 31 17:40:36 connor-OptiPlex-7060 caddy[1587]: {"level":"info","ts":1704062436.6218235,"logger":"tls.issuance.zerossl","msg":"done waiting on internal rate limiter","identifiers":["dz-jellyfin.duckdns.org"],"ca":"https://acme.zerossl.com/v2/DV90","account":"caddy@zerossl.com"}
Dec 31 17:40:37 connor-OptiPlex-7060 caddy[1587]: {"level":"info","ts":1704062437.478123,"logger":"tls.issuance.zerossl.acme_client","msg":"trying to solve challenge","identifier":"dz-jellyfin.duckdns.org","challenge_type":"dns-01","ca":"https://acme.zerossl.com/v2/DV90"}
Dec 31 17:40:37 connor-OptiPlex-7060 caddy[1587]: {"level":"error","ts":1704062437.5005999,"logger":"tls.issuance.zerossl.acme_client","msg":"cleaning up solver","identifier":"dz-jellyfin.duckdns.org","challenge_type":"dns-01","error":"no memory of presenting a DNS record for \"_acme-challenge.dz-jellyfin.duckdns.org\" (usually OK if presenting also failed)"}
Dec 31 17:40:37 connor-OptiPlex-7060 caddy[1587]: {"level":"error","ts":1704062437.8178332,"logger":"tls.obtain","msg":"could not get certificate from issuer","identifier":"dz-jellyfin.duckdns.org","issuer":"acme.zerossl.com-v2-DV90","error":"[dz-jellyfin.duckdns.org] solving challenges: presenting for challenge: adding temporary record for zone \"duckdns.org.\": DuckDNS request failed, expected (OK) but got (KO), url: [https://www.duckdns.org/update?domains=dz-jellyfin.duckdns.org&token=&txt=vz4CNBeqIGWUiy0ilNLhGEVTdiC3kfnZER92pv_v-rE&verbose=true], body: KO (order=https://acme.zerossl.com/v2/DV90/order/KtcNQnmWCu2Uwmoe4r1ULA) (ca=https://acme.zerossl.com/v2/DV90)"}
Dec 31 17:40:37 connor-OptiPlex-7060 caddy[1587]: {"level":"error","ts":1704062437.8178804,"logger":"tls.obtain","msg":"will retry","error":"[dz-jellyfin.duckdns.org] Obtain: [dz-jellyfin.duckdns.org] solving challenges: presenting for challenge: adding temporary record for zone \"duckdns.org.\": DuckDNS request failed, expected (OK) but got (KO), url: [https://www.duckdns.org/update?domains=dz-jellyfin.duckdns.org&token=&txt=vz4CNBeqIGWUiy0ilNLhGEVTdiC3kfnZER92pv_v-rE&verbose=true], body: KO (order=https://acme.zerossl.com/v2/DV90/order/KtcNQnmWCu2Uwmoe4r1ULA) (ca=https://acme.zerossl.com/v2/DV90)","attempt":1,"retrying_in":60,"elapsed":2.162124852,"max_duration":2592000}
Dec 31 17:41:37 connor-OptiPlex-7060 caddy[1587]: {"level":"info","ts":1704062497.818448,"logger":"tls.obtain","msg":"obtaining certificate","identifier":"dz-jellyfin.duckdns.org"}
Dec 31 17:41:38 connor-OptiPlex-7060 caddy[1587]: {"level":"info","ts":1704062498.366481,"logger":"tls.issuance.acme.acme_client","msg":"trying to solve challenge","identifier":"dz-jellyfin.duckdns.org","challenge_type":"dns-01","ca":"https://acme-staging-v02.api.letsencrypt.org/directory"}
Dec 31 17:41:38 connor-OptiPlex-7060 caddy[1587]: {"level":"error","ts":1704062498.3888366,"logger":"tls.issuance.acme.acme_client","msg":"cleaning up solver","identifier":"dz-jellyfin.duckdns.org","challenge_type":"dns-01","error":"no memory of presenting a DNS record for \"_acme-challenge.dz-jellyfin.duckdns.org\" (usually OK if presenting also failed)"}
Dec 31 17:41:38 connor-OptiPlex-7060 caddy[1587]: {"level":"error","ts":1704062498.4815755,"logger":"tls.obtain","msg":"could not get certificate from issuer","identifier":"dz-jellyfin.duckdns.org","issuer":"acme-v02.api.letsencrypt.org-directory","error":"[dz-jellyfin.duckdns.org] solving challenges: presenting for challenge: adding temporary record for zone \"duckdns.org.\": DuckDNS request failed, expected (OK) but got (KO), url: [https://www.duckdns.org/update?domains=dz-jellyfin.duckdns.org&token=&txt=UHDNTPSB8aM8BSBxV-ne33zV_Jcd2KwRcvKGN9n2TTU&verbose=true], body: KO (order=https://acme-staging-v02.api.letsencrypt.org/acme/order/130737394/13345863634) (ca=https://acme-staging-v02.api.letsencrypt.org/directory)"}
Dec 31 17:41:38 connor-OptiPlex-7060 caddy[1587]: {"level":"info","ts":1704062498.88112,"logger":"tls.issuance.zerossl.acme_client","msg":"trying to solve challenge","identifier":"dz-jellyfin.duckdns.org","challenge_type":"dns-01","ca":"https://acme.zerossl.com/v2/DV90"}
Dec 31 17:41:38 connor-OptiPlex-7060 caddy[1587]: {"level":"error","ts":1704062498.9032001,"logger":"tls.issuance.zerossl.acme_client","msg":"cleaning up solver","identifier":"dz-jellyfin.duckdns.org","challenge_type":"dns-01","error":"no memory of presenting a DNS record for \"_acme-challenge.dz-jellyfin.duckdns.org\" (usually OK if presenting also failed)"}
Dec 31 17:41:39 connor-OptiPlex-7060 caddy[1587]: {"level":"error","ts":1704062499.018438,"logger":"tls.obtain","msg":"could not get certificate from issuer","identifier":"dz-jellyfin.duckdns.org","issuer":"acme.zerossl.com-v2-DV90","error":"[dz-jellyfin.duckdns.org] solving challenges: presenting for challenge: adding temporary record for zone \"duckdns.org.\": DuckDNS request failed, expected (OK) but got (KO), url: [https://www.duckdns.org/update?domains=dz-jellyfin.duckdns.org&token=&txt=RlWwaSjwIde-ZFoLAgeCjeOTYyeFzC0deFdPkU02wag&verbose=true], body: KO (order=https://acme.zerossl.com/v2/DV90/order/1LJ1ZWnGsZl4Hii2PUlyHQ) (ca=https://acme.zerossl.com/v2/DV90)"}
Dec 31 17:41:39 connor-OptiPlex-7060 caddy[1587]: {"level":"error","ts":1704062499.0184746,"logger":"tls.obtain","msg":"will retry","error":"[dz-jellyfin.duckdns.org] Obtain: [dz-jellyfin.duckdns.org] solving challenges: presenting for challenge: adding temporary record for zone \"duckdns.org.\": DuckDNS request failed, expected (OK) but got (KO), url: [https://www.duckdns.org/update?domains=dz-jellyfin.duckdns.org&token=&txt=RlWwaSjwIde-ZFoLAgeCjeOTYyeFzC0deFdPkU02wag&verbose=true], body: KO (order=https://acme.zerossl.com/v2/DV90/order/1LJ1ZWnGsZl4Hii2PUlyHQ) (ca=https://acme.zerossl.com/v2/DV90)","attempt":2,"retrying_in":120,"elapsed":63.362718937,"max_duration":2592000}
3. Caddy version:
v2.7.6
4. How I installed and ran Caddy:
I installed following the exact instructions here: Install — Caddy Documentation (I quite literally copy/pasted what is there for stable build)
a. System environment:
Ubuntu 22.04.3 LTS
b. Command:
Service runs on startup. I just use caddy stop
and caddy start
to start/stop the service if I am tweaking things. If I am just modifying the Caddyfile
I just use caddy adapt
.
c. Service/unit/compose file:
[Unit]
Description=Caddy
Documentation=https://caddyserver.com/docs/
After=network.target network-online.target
Requires=network-online.target
[Service]
Type=notify
User=caddy
Group=caddy
ExecStart=/usr/bin/caddy run --environ --config /etc/caddy/Caddyfile
ExecReload=/usr/bin/caddy reload --config /etc/caddy/Caddyfile --force
TimeoutStopSec=5s
LimitNOFILE=1048576
LimitNPROC=512
PrivateTmp=true
ProtectSystem=full
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
[Install]
WantedBy=multi-user.target
d. My complete Caddy config:
{
dynamic_dns {
# replace with your DNS provider's plugin name and credentials
provider duckdns {env.DUCKDNS_API_TOKEN}
domains {
# DNS zone first, followed by subdomain if any (I know it's weird)
dz-jellyfin.duckdns.org jellyfin
}
}
}
dz-jellyfin.duckdns.org {
reverse_proxy 127.0.0.1:8096 127.0.0.1:8920
tls {
dns duckdns {env.DUCKDNS_API_TOKEN}
}
}
5. Links to relevant resources:
I was following this tutorial: Access your Jellyfin anywhere with Caddy
I also have these plugins installed using the add-package
command since I don’t have/can’t have a static public IP through my ISP:
GitHub - mholt/caddy-dynamicdns: Caddy app that keeps your DNS records (A/AAAA) pointed at itself.
GitHub - caddy-dns/duckdns: Caddy module: dns.providers.duckdns