Role
Caddy is the HTTP entry point for the entire NubleStation stack. It:
- Terminates TLS (with automatic certificate generation via its internal CA)
- Routes
console.{org}.local→ Console container - Routes
api.{org}.local→ API Gateway container - Serves deployed frontend bundles for all app subdomains (
tasks.{org}.local, etc.)
Caddy is the only container that publishes ports 80 and 443 to the host.
Caddyfile
The Caddyfile is generated by the installer from infra/caddy/Caddyfile.template using envsubst:
{
# Use Caddy's internal CA for LAN HTTPS
local_certs
auto_https disable_redirects
}
console.clinic.local {
reverse_proxy console:3000
}
api.clinic.local {
reverse_proxy gateway:3000
}
*.clinic.local {
@app {
not host console.clinic.local
not host api.clinic.local
}
handle @app {
root * /var/nuble/{labels.1}
file_server
}
}
{labels.1} is a Caddy placeholder that extracts the first DNS label from the subdomain. For tasks.clinic.local it yields tasks, so Caddy serves /var/nuble/tasks/.
Static file serving
The Deploy Service writes frontend bundles to /var/nuble/{appname}/ (a Docker volume shared between the Deploy Service container and Caddy). Caddy reads from this volume directly — no reload, no configuration change. A new deployment is live the instant the files are written.
HTTPS on the LAN
Caddy generates TLS certificates using its built-in CA. This avoids the need for a public CA (which requires a public domain and internet access).
One-time device setup: install Caddy’s CA root certificate on each device. The installer prints the certificate path. Browsers trust *.clinic.local HTTPS after this step.
# On the host, export the root certificate
docker exec nublestation-caddy cat /data/caddy/pki/authorities/local/root.crt > caddy-root.crt
# Then import caddy-root.crt into each device's system trust store
# macOS: Keychain Access → File → Import Items → Trust Always
# Windows: mmc → Certificates snap-in → Trusted Root CAs → Import
# Linux: cp caddy-root.crt /usr/local/share/ca-certificates/ && update-ca-certificates
Modifying the Caddyfile
If you need to add custom headers, enable gzip, or adjust timeouts:
- Edit
infra/caddy/Caddyfile(or the template if you plan to re-run the installer) - Validate:
docker exec nublestation-caddy caddy validate --config /etc/caddy/Caddyfile - Reload:
docker exec nublestation-caddy caddy reload --config /etc/caddy/Caddyfile
No restart needed — Caddy reloads its configuration without dropping existing connections.
Logs
docker compose -f infra/docker-compose.yml logs caddy --follow
Caddy logs every request in structured JSON. Filter by subdomain:
docker compose -f infra/docker-compose.yml logs caddy | grep '"request"' | jq '.request.host'