1. Caddy version (caddy version
):
2.2.1
2. How I run Caddy:
a. System environment:
OS: Ubuntu 20.04.1 LTS
Docker: 19.03.8
Docker Compose: 1.23.2
b. Command:
docker-compose build # sometimes
docker-compose up -d
c. Service/unit/compose file:
Caddy
---
version: "3.4"
services:
caddy:
build: .
env_file:
- .env
container_name: caddy
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- caddy_data:/data
ports:
- 80:80
- 443:443
restart: unless-stopped
volumes:
caddy_data: {}
Ubooquity
---
version: "3.4"
services:
ubooquity:
image: ghcr.io/linuxserver/ubooquity
container_name: ubooquity
environment:
- PUID=992 # ubooquity
- PGID=995 # media
- TZ=America/New_York
- UMASK_SET=002
- MAXMEM=2048
volumes:
- /data/config/ubooquity:/config
- /data/media:/data/media
ports:
- 2202:2202
- 2203:2203
networks:
- caddy
labels:
caddy: comics.chrisrees.dev
caddy.1_reverse_proxy: "{{upstreams 2202}}"
caddy.2_reverse_proxy: "/admin {{upstreams 2203}}"
caddy.tls.dns: "cloudflare {env.CLOUDFLARE_API_KEY}"
restart: unless-stopped
networks:
caddy:
external:
name: caddy_default
d. My complete Caddyfile or JSON config:
alone-in-a-room.com {
reverse_proxy 172.18.0.10:9099
tls {
dns cloudflare {env.CLOUDFLARE_API_KEY}
}
}
chrisrees.dev {
reverse_proxy 172.18.0.11:9100
tls {
dns cloudflare {env.CLOUDFLARE_API_KEY}
}
}
comics.chrisrees.dev {
reverse_proxy 172.18.0.12:2202
reverse_proxy /admin 172.18.0.12:2203
tls {
dns cloudflare {env.CLOUDFLARE_API_KEY}
}
}
lidarr.chrisrees.dev {
reverse_proxy 172.18.0.2:8686
tls {
dns cloudflare {env.CLOUDFLARE_API_KEY}
}
}
mylar.chrisrees.dev {
reverse_proxy 172.18.0.5:8090
tls {
dns cloudflare {env.CLOUDFLARE_API_KEY}
}
}
plex.chrisrees.dev {
reverse_proxy 172.18.0.7:32400
tls {
dns cloudflare {env.CLOUDFLARE_API_KEY}
}
}
radarr.chrisrees.dev {
reverse_proxy 172.18.0.6:7878
tls {
dns cloudflare {env.CLOUDFLARE_API_KEY}
}
}
sabnzbd.chrisrees.dev {
reverse_proxy 172.18.0.4:8080
tls {
dns cloudflare {env.CLOUDFLARE_API_KEY}
}
}
sonarr.chrisrees.dev {
reverse_proxy 172.18.0.8:8989
tls {
dns cloudflare {env.CLOUDFLARE_API_KEY}
}
}
sync.chrisrees.dev {
reverse_proxy /* 172.18.0.9:8384
tls {
dns cloudflare {env.CLOUDFLARE_API_KEY}
}
}
{
"apps": {
"http": {
"servers": {
"srv0": {
"listen": [
":443"
],
"routes": [
{
"match": [
{
"host": [
"sabnzbd.chrisrees.dev"
]
}
],
"handle": [
{
"handler": "subroute",
"routes": [
{
"handle": [
{
"handler": "reverse_proxy",
"upstreams": [
{
"dial": "172.18.0.4:8080"
}
]
}
]
}
]
}
],
"terminal": true
},
{
"match": [
{
"host": [
"comics.chrisrees.dev"
]
}
],
"handle": [
{
"handler": "subroute",
"routes": [
{
"handle": [
{
"handler": "reverse_proxy",
"upstreams": [
{
"dial": "172.18.0.12:2203"
}
]
}
],
"match": [
{
"path": [
"/admin"
]
}
]
},
{
"handle": [
{
"handler": "reverse_proxy",
"upstreams": [
{
"dial": "172.18.0.12:2202"
}
]
}
]
}
]
}
],
"terminal": true
},
{
"match": [
{
"host": [
"lidarr.chrisrees.dev"
]
}
],
"handle": [
{
"handler": "subroute",
"routes": [
{
"handle": [
{
"handler": "reverse_proxy",
"upstreams": [
{
"dial": "172.18.0.2:8686"
}
]
}
]
}
]
}
],
"terminal": true
},
{
"match": [
{
"host": [
"radarr.chrisrees.dev"
]
}
],
"handle": [
{
"handler": "subroute",
"routes": [
{
"handle": [
{
"handler": "reverse_proxy",
"upstreams": [
{
"dial": "172.18.0.6:7878"
}
]
}
]
}
]
}
],
"terminal": true
},
{
"match": [
{
"host": [
"sonarr.chrisrees.dev"
]
}
],
"handle": [
{
"handler": "subroute",
"routes": [
{
"handle": [
{
"handler": "reverse_proxy",
"upstreams": [
{
"dial": "172.18.0.8:8989"
}
]
}
]
}
]
}
],
"terminal": true
},
{
"match": [
{
"host": [
"alone-in-a-room.com"
]
}
],
"handle": [
{
"handler": "subroute",
"routes": [
{
"handle": [
{
"handler": "reverse_proxy",
"upstreams": [
{
"dial": "172.18.0.10:9099"
}
]
}
]
}
]
}
],
"terminal": true
},
{
"match": [
{
"host": [
"mylar.chrisrees.dev"
]
}
],
"handle": [
{
"handler": "subroute",
"routes": [
{
"handle": [
{
"handler": "reverse_proxy",
"upstreams": [
{
"dial": "172.18.0.5:8090"
}
]
}
]
}
]
}
],
"terminal": true
},
{
"match": [
{
"host": [
"plex.chrisrees.dev"
]
}
],
"handle": [
{
"handler": "subroute",
"routes": [
{
"handle": [
{
"handler": "reverse_proxy",
"upstreams": [
{
"dial": "172.18.0.7:32400"
}
]
}
]
}
]
}
],
"terminal": true
},
{
"match": [
{
"host": [
"sync.chrisrees.dev"
]
}
],
"handle": [
{
"handler": "subroute",
"routes": [
{
"handle": [
{
"handler": "reverse_proxy",
"upstreams": [
{
"dial": "172.18.0.9:8384"
}
]
}
],
"match": [
{
"path": [
"/*"
]
}
]
}
]
}
],
"terminal": true
},
{
"match": [
{
"host": [
"chrisrees.dev"
]
}
],
"handle": [
{
"handler": "subroute",
"routes": [
{
"handle": [
{
"handler": "reverse_proxy",
"upstreams": [
{
"dial": "172.18.0.11:9100"
}
]
}
]
}
]
}
],
"terminal": true
}
]
}
}
},
"tls": {
"automation": {
"policies": [
{
"subjects": [
"sabnzbd.chrisrees.dev",
"comics.chrisrees.dev",
"lidarr.chrisrees.dev",
"radarr.chrisrees.dev",
"sonarr.chrisrees.dev",
"alone-in-a-room.com",
"mylar.chrisrees.dev",
"plex.chrisrees.dev",
"sync.chrisrees.dev",
"chrisrees.dev"
],
"issuer": {
"challenges": {
"dns": {
"provider": {
"api_token": "<TOKEN>",
"name": "cloudflare"
}
}
},
"module": "acme"
}
}
]
}
}
}
}
3. The problem I’m having:
I’m specifically focusing on migrating my Ubooquity app to Caddy at the moment. It requires two ports: 2202 and 2203. The first is for the main app, the second is for the admin interface. I’ve tackled this in Nginx by having two location
blocks, one at /
and one at /admin
, both proxying to ports 2202
and 2203
respectively.
With Caddy, my current config mostly works. However, the Admin interface seems to be broken. It claims it’s not connected to the server and all of the minified JS files are claiming syntax errors. I assume this has to do with my config somehow.
The JS files are all at URLs similar to: https://comics.chrisrees.dev/admin-res/sha256-min.js
with only the name of the file being different
4. Error messages and/or full log output:
2020/12/29 01:25:05 [INFO] Sending configuration to localhost
{"level":"info","ts":1609205105.3465497,"logger":"admin.api","msg":"received request","method":"POST","host":"localhost:2019","uri":"/load","remote_addr":"127.0.0.1:45832","headers":{"Accept-Encoding":["gzip"],"Content-Length":["2211"],"Content-Type":["application/json"],"User-Agent":["Go-http-client/1.1"]}}
{"level":"info","ts":1609205105.3475356,"logger":"admin","msg":"admin endpoint started","address":"tcp/localhost:2019","enforce_origin":false,"origins":["localhost:2019","[::1]:2019","127.0.0.1:2019"]}
{"level":"info","ts":1609205105.3479464,"logger":"tls.cache.maintenance","msg":"started background certificate maintenance","cache":"0xc00068a000"}
{"level":"info","ts":1609205105.3481648,"logger":"http","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}
{"level":"info","ts":1609205105.348195,"logger":"http","msg":"enabling automatic HTTP->HTTPS redirects","server_name":"srv0"}
{"level":"info","ts":1609205105.3489304,"logger":"http","msg":"enabling automatic TLS certificate management","domains":["sonarr.chrisrees.dev","alone-in-a-room.com","plex.chrisrees.dev","sabnzbd.chrisrees.dev","radarr.chrisrees.dev","mylar.chrisrees.dev","lidarr.chrisrees.dev","sync.chrisrees.dev","chrisrees.dev"]}
2020/12/29 01:25:09 [INFO] Skipping default Caddyfile because no path is set
[INFO] Skipping configs because swarm is not available
[INFO] Skipping services because swarm is not available
2020/12/29 01:25:09 [INFO] New Caddyfile:
alone-in-a-room.com {
reverse_proxy 172.18.0.10:9099
tls {
dns cloudflare {env.CLOUDFLARE_API_KEY}
}
}
chrisrees.dev {
reverse_proxy 172.18.0.11:9100
tls {
dns cloudflare {env.CLOUDFLARE_API_KEY}
}
}
comics.chrisrees.dev {
reverse_proxy 172.18.0.12:2202
reverse_proxy /admin 172.18.0.12:2203
tls {
dns cloudflare {env.CLOUDFLARE_API_KEY}
}
}
lidarr.chrisrees.dev {
reverse_proxy 172.18.0.2:8686
tls {
dns cloudflare {env.CLOUDFLARE_API_KEY}
}
}
mylar.chrisrees.dev {
reverse_proxy 172.18.0.5:8090
tls {
dns cloudflare {env.CLOUDFLARE_API_KEY}
}
}
plex.chrisrees.dev {
reverse_proxy 172.18.0.7:32400
tls {
dns cloudflare {env.CLOUDFLARE_API_KEY}
}
}
radarr.chrisrees.dev {
reverse_proxy 172.18.0.6:7878
tls {
dns cloudflare {env.CLOUDFLARE_API_KEY}
}
}
sabnzbd.chrisrees.dev {
reverse_proxy 172.18.0.4:8080
tls {
dns cloudflare {env.CLOUDFLARE_API_KEY}
}
}
sonarr.chrisrees.dev {
reverse_proxy 172.18.0.8:8989
tls {
dns cloudflare {env.CLOUDFLARE_API_KEY}
}
}
sync.chrisrees.dev {
reverse_proxy /* 172.18.0.9:8384
tls {
dns cloudflare {env.CLOUDFLARE_API_KEY}
}
}
2020/12/29 01:25:09 [INFO] New Config JSON:
{"apps":{"http":{"servers":{"srv0":{"listen":[":443"],"routes":[{"match":[{"host":["sabnzbd.chrisrees.dev"]}],"handle":[{"handler":"subroute","routes":[{"handle":[{"handler":"reverse_proxy","upstreams":[{"dial":"172.18.0.4:8080"}]}]}]}],"terminal":true},{"match":[{"host":["comics.chrisrees.dev"]}],"handle":[{"handler":"subroute","routes":[{"handle":[{"handler":"reverse_proxy","upstreams":[{"dial":"172.18.0.12:2203"}]}],"match":[{"path":["/admin"]}]},{"handle":[{"handler":"reverse_proxy","upstreams":[{"dial":"172.18.0.12:2202"}]}]}]}],"terminal":true},{"match":[{"host":["lidarr.chrisrees.dev"]}],"handle":[{"handler":"subroute","routes":[{"handle":[{"handler":"reverse_proxy","upstreams":[{"dial":"172.18.0.2:8686"}]}]}]}],"terminal":true},{"match":[{"host":["radarr.chrisrees.dev"]}],"handle":[{"handler":"subroute","routes":[{"handle":[{"handler":"reverse_proxy","upstreams":[{"dial":"172.18.0.6:7878"}]}]}]}],"terminal":true},{"match":[{"host":["sonarr.chrisrees.dev"]}],"handle":[{"handler":"subroute","routes":[{"handle":[{"handler":"reverse_proxy","upstreams":[{"dial":"172.18.0.8:8989"}]}]}]}],"terminal":true},{"match":[{"host":["alone-in-a-room.com"]}],"handle":[{"handler":"subroute","routes":[{"handle":[{"handler":"reverse_proxy","upstreams":[{"dial":"172.18.0.10:9099"}]}]}]}],"terminal":true},{"match":[{"host":["mylar.chrisrees.dev"]}],"handle":[{"handler":"subroute","routes":[{"handle":[{"handler":"reverse_proxy","upstreams":[{"dial":"172.18.0.5:8090"}]}]}]}],"terminal":true},{"match":[{"host":["plex.chrisrees.dev"]}],"handle":[{"handler":"subroute","routes":[{"handle":[{"handler":"reverse_proxy","upstreams":[{"dial":"172.18.0.7:32400"}]}]}]}],"terminal":true},{"match":[{"host":["sync.chrisrees.dev"]}],"handle":[{"handler":"subroute","routes":[{"handle":[{"handler":"reverse_proxy","upstreams":[{"dial":"172.18.0.9:8384"}]}],"match":[{"path":["/*"]}]}]}],"terminal":true},{"match":[{"host":["chrisrees.dev"]}],"handle":[{"handler":"subroute","routes":[{"handle":[{"handler":"reverse_proxy","upstreams":[{"dial":"172.18.0.11:9100"}]}]}]}],"terminal":true}]}}},"tls":{"automation":{"policies":[{"subjects":["sabnzbd.chrisrees.dev","comics.chrisrees.dev","lidarr.chrisrees.dev","radarr.chrisrees.dev","sonarr.chrisrees.dev","alone-in-a-room.com","mylar.chrisrees.dev","plex.chrisrees.dev","sync.chrisrees.dev","chrisrees.dev"],"issuer":{"challenges":{"dns":{"provider":{"api_token":"<TOKEN>","name":"cloudflare"}}},"module":"acme"}}]}}}}
{"level":"error","ts":1609205115.347783,"logger":"admin","msg":"stopping current admin endpoint","error":"shutting down admin server: context deadline exceeded"}
{"level":"info","ts":1609205153.353808,"logger":"tls.cache.maintenance","msg":"stopped background certificate maintenance","cache":"0xc000264230"}
{"level":"info","ts":1609205153.3541718,"msg":"autosaved config","file":"/config/caddy/autosave.json"}
{"level":"info","ts":1609205153.354194,"logger":"admin.api","msg":"load complete"}
2020/12/29 01:25:53 [INFO] Successfully configured localhost
2020/12/29 01:26:10 [INFO] Sending configuration to localhost
{"level":"info","ts":1609205170.237307,"logger":"admin.api","msg":"received request","method":"POST","host":"localhost:2019","uri":"/load","remote_addr":"127.0.0.1:45874","headers":{"Accept-Encoding":["gzip"],"Content-Length":["2537"],"Content-Type":["application/json"],"User-Agent":["Go-http-client/1.1"]}}
{"level":"info","ts":1609205170.238182,"logger":"admin","msg":"admin endpoint started","address":"tcp/localhost:2019","enforce_origin":false,"origins":["localhost:2019","[::1]:2019","127.0.0.1:2019"]}
{"level":"info","ts":1609205170.2384763,"logger":"tls.cache.maintenance","msg":"started background certificate maintenance","cache":"0xc0001687e0"}
{"level":"info","ts":1609205170.2386327,"logger":"http","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}
{"level":"info","ts":1609205170.2386732,"logger":"http","msg":"enabling automatic HTTP->HTTPS redirects","server_name":"srv0"}
{"level":"info","ts":1609205170.2393384,"logger":"http","msg":"enabling automatic TLS certificate management","domains":["plex.chrisrees.dev","sabnzbd.chrisrees.dev","comics.chrisrees.dev","sonarr.chrisrees.dev","alone-in-a-room.com","mylar.chrisrees.dev","sync.chrisrees.dev","chrisrees.dev","lidarr.chrisrees.dev","radarr.chrisrees.dev"]}
{"level":"error","ts":1609205170.2440968,"logger":"http.handlers.reverse_proxy","msg":"aborting with incomplete response","error":"context canceled"}
{"level":"info","ts":1609205173.2439537,"logger":"tls.cache.maintenance","msg":"stopped background certificate maintenance","cache":"0xc00068a000"}
{"level":"info","ts":1609205173.244141,"msg":"autosaved config","file":"/config/caddy/autosave.json"}
{"level":"info","ts":1609205173.244153,"logger":"admin.api","msg":"load complete"}
2020/12/29 01:26:13 [INFO] Successfully configured localhost
{"level":"info","ts":1609205173.7384157,"logger":"admin","msg":"stopped previous server"}
5. What I already tried:
comics.chrisrees.dev {
reverse_proxy 172.18.0.12:2202
reverse_proxy /admin 172.18.0.12:2203
tls {
dns cloudflare {env.CLOUDFLARE_API_KEY}
}
}
comics.chrisrees.dev {
reverse_proxy /* 172.18.0.12:2202
reverse_proxy /admin 172.18.0.12:2203
tls {
dns cloudflare {env.CLOUDFLARE_API_KEY}
}
}
comics.chrisrees.dev {
reverse_proxy /* 172.18.0.12:2202
reverse_proxy /admin* 172.18.0.12:2203
tls {
dns cloudflare {env.CLOUDFLARE_API_KEY}
}
}
comics.chrisrees.dev {
reverse_proxy /* 172.18.0.12:2202
reverse_proxy @admin 172.18.0.12:2203
@admin {
path /admin /admin/*
}
tls {
dns cloudflare {env.CLOUDFLARE_API_KEY}
}
}
I’ve also tried putting the /admin
rules first for all of these options except for the @admin
attempt. I figured Caddy likely stopped at the first rule it matched and that might be causing issues.