Close. You’ve provided the Caddyfile syntax, which is a sort of json-like. However, Caddy can understand json. So the caddy snap uses the json directly.
What this means in practice is that your caddy config value will be a bit more complicated…
dilyn-corner@mnemosyne:~$ snap get -d caddy
{
"config": {
"apps": {
"dynamic_dns": {
"dns_provider": {
"api_key": "xxx",
"api_secret_key": "xxx",
"name": "porkbun"
},
"domains": {
"dilyn.cc": [
"@",
"www"
],
"git.dilyn.cc": [
"@",
"www"
]
},
"ip_sources": [
...
}
My config exposes a gitea instance hosted on the Ubuntu Core device (via the gitea snap) on port 3001 to the outside world at git.dilyn.cc, a subdomain of my domain:
"match": [
{
"host": [
"git.dilyn.cc"
]
}
],
"terminal": true
},
{
"handle": [
{
"handler": "subroute",
"routes": [
{
"handle": [
{
"handler": "reverse_proxy",
"upstreams": [
{
"dial": "localhost:3001"
}
]
}
]
}
]
}
],
Syntactically, this is a mess to generate. My entire config is over 200 lines. But I do have the config set as a default in my gadget snap so I can freely redeploy with no worries.
All of that is to really say: you need to use json in the config value (and the usage guides in the project readme offer a brief example).
But! Caddy makes this easy. If you provide caddy a Caddyfile, it can convert it to json for you:
sudo caddy adapt --config Caddyfile
Caddy can even do the helpful thing for you. Converting your example, I get this:
dilyn-corner@mnemosyne:/var/snap/caddy/common$ sudo caddy adapt --config i
+ id -u
+ [ 0 = 0 ]
+ _caddy=/snap/caddy/671/usr/bin/caddy
+ snapctl get modified
+ [ = true ]
+ cli adapt --config i
+ arg=adapt
+ shift 1
+ /snap/caddy/671/usr/bin/caddy adapt --config i
{"apps":{"http":{"servers":{"srv0":{"listen":[":443"],"routes":[{"match":[{"host":["home-assistant.mydomain.me","home.mydomain.me"]}],"handle":[{"handler":"subroute","routes":[{"handle":[{"handler":"reverse_proxy","upstreams":[{"dial":":444"}]}]}]}],"terminal":true},{"match":[{"host":["nexcloud.mydomain.me"]}],"handle":[{"handler":"subroute","routes":[{"handle":[{"handler":"reverse_proxy","upstreams":[{"dial":":80"},{"dial":"443:80"}]}]}]}],"terminal":true}]}}}}}
2026/05/18 16:24:33.727 WARN caddyfile Caddyfile input is not formatted; run 'caddy fmt --overwrite' to fix inconsistencies {"file": "i", "line": 3}
dilyn-corner@mnemosyne:/var/snap/caddy/common$ sudo caddy fmt --overwrite --config i
+ id -u
+ [ 0 = 0 ]
+ _caddy=/snap/caddy/671/usr/bin/caddy
+ snapctl get modified
+ [ = true ]
+ cli fmt --overwrite --config i
+ arg=fmt
+ shift 1
+ /snap/caddy/671/usr/bin/caddy fmt --overwrite --config i
dilyn-corner@mnemosyne:/var/snap/caddy/common$ cat i
nexcloud.mydomain.me {
reverse_proxy : 443
}
# note here, there is no comma, not json format as asked by the documentation :/
home-assistant.mydomain.me, home.mydomain.me {
reverse_proxy :444
}
dilyn-corner@mnemosyne:/var/snap/caddy/common$ sudo caddy adapt --config i
+ id -u
+ [ 0 = 0 ]
+ _caddy=/snap/caddy/671/usr/bin/caddy
+ snapctl get modified
+ [ = true ]
+ cli adapt --config i
+ arg=adapt
+ shift 1
+ /snap/caddy/671/usr/bin/caddy adapt --config i
{"apps":{"http":{"servers":{"srv0":{"listen":[":443"],"routes":[{"match":[{"host":["home-assistant.mydomain.me","home.mydomain.me"]}],"handle":[{"handler":"subroute","routes":[{"handle":[{"handler":"reverse_proxy","upstreams":[{"dial":":444"}]}]}]}],"terminal":true},{"match":[{"host":["nexcloud.mydomain.me"]}],"handle":[{"handler":"subroute","routes":[{"handle":[{"handler":"reverse_proxy","upstreams":[{"dial":":80"},{"dial":"443:80"}]}]}]}],"terminal":true}]}}}}}
dilyn-corner@mnemosyne:/var/snap/caddy/common$
eta: oh, I see I had already added this suggestion to the Tip at the end of the project README! Nifty. Nice thinking, past Dilyn.