deploy.sh: escape the image-build loop vars for the remote string

This commit is contained in:
Frank
2026-08-22 04:04:24 -07:00
parent 1f4766f233
commit dc421efea4
5 changed files with 212 additions and 71 deletions
+59 -43
View File
@@ -1,71 +1,87 @@
# Caddy
Caddy is the reverse proxy for both hosts. It terminates TLS, routes hostnames to containers, and protects the homepage with HTTP basic auth.
Caddy is the single reverse proxy for both hosts. It runs as a container on Dankclaw (192.168.0.143), terminates TLS with real Let's Encrypt certificates, routes hostnames to containers on both hosts, and protects the homepage and sensitive services with HTTP basic auth.
**Hosts:** Dankserver + Dankclaw — **Docs:** https://caddyserver.com/docs
**Docs:** https://caddyserver.com/docs
## Facts (from live inventory + knowledge base)
## Facts (live inventory)
| Item | Value |
|------|-------|
| Image | `docker.io/library/caddy:latest` |
| Config | `/etc/caddy/Caddyfile` (bind mount) |
| Data | `/root/.local/share/caddy` (certs, ACME state) |
| Ports | 80, 443 |
| Existing on Dankserver | systemd `caddy` service (native), config at `/etc/caddy/Caddyfile` — being migrated into this repo |
| Image | `franksdank/caddy-porkbun:latest` (local build, `dankclaw/caddy/Containerfile`) |
| Config | `/home/dank/Containers/caddy/Caddyfile` (bind mount, rendered by deploy) |
| Data | `/home/dank/Containers/caddy/data` (certs) and `.../config` (ACME state) |
| Ports | 80, 443 on 192.168.0.143 |
| TLS | Let's Encrypt, DNS-01 via the Porkbun module (one cert per vhost) |
| Runs on | Dankclaw only — Dankserver has no Caddy |
## Existing Dankserver Caddyfile (live, to migrate)
The Caddyfile in git (`dankclaw/Caddyfile`) carries a `REPLACE_WITH_HASH` placeholder. `scripts/deploy.sh` renders the real basicauth hash from the host `.env` (`CADDY_BASICAUTH_HASH`) into the mounted path before `up`. See [[Deployment Flow]].
The live Caddyfile proxies:
- `plex.franksdank.casa` / `plex.franksdank.cloud` / `plex.dankserver.local` → `localhost:32400` (Plex)
- `books.franksdank.cloud` → `localhost:8083` (Calibre-Web)
- `llms.franksdank.cloud` / `llms.dankserver.local` → `localhost:3000` (OpenWebUI — being moved to Dankclaw)
- `search.dankserver.local` → `localhost:8081` (SearXNG — being moved to Dankclaw)
## The porkbun image
## Hostname Convention
Every service gets a `.dankserver.local` or `.dankclaw.local` hostname so no one has to remember port numbers:
Stock Caddy cannot solve the ACME challenge because the router exposes no inbound port 80/443. The local image adds the `github.com/caddy-dns/porkbun` module, which answers the DNS-01 challenge by creating and deleting a `_acme-challenge` TXT record through the Porkbun API. No inbound port is needed. Rebuild only when Caddy or the module needs an update:
```
romm.dankserver.local
books.dankserver.local
files.dankserver.local
search.dankclaw.local
chat.dankclaw.local
gitea.dankclaw.local
comfyui.dankclaw.local
grafana.dankclaw.local
prometheus.dankclaw.local
podman build -t franksdank/caddy-porkbun:latest -f dankclaw/caddy/Containerfile .
```
## Basic Auth
Generate a bcrypt hash with `caddy hash-password`, then:
The Caddyfile references the credentials through the environment:
```
chat.dankclaw.local {
basicauth {
dank $2a$14$xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
}
reverse_proxy localhost:3000
acme_dns porkbun {
api_key {env.PORKBUN_API_KEY}
api_secret_key {env.PORKBUN_API_SECRET_KEY}
}
```
The homepage uses basic auth too; see [[Homepage]].
compose passes both variables from the host `.env`. Keep the real keys in `.env` only; `.env.example` holds placeholders. The Porkbun account holds only `franksdank.cloud`.
## Homepage
## Vhost map
A static page lists all services with live status (up/down) and a short description plus a link to each service's documentation. Served by Caddy with `file_server` and protected by basic auth.
Every vhost uses the flat `franksdank.cloud` convention. The full list lives in `dankclaw/Caddyfile`. Routing by host:
| Upstream | Reach |
|----------|-------|
| Dankclaw services (compose network) | by container name, e.g. `comfyui:8188` |
| Dankclaw quadlet services | by published LAN port, e.g. `192.168.0.143:3000` (Gitea) |
| Dankserver services | by published LAN port, e.g. `192.168.0.235:8085` (RomM) |
The bare-IP catch-all `:80` 302-redirects to `https://dankclaw.franksdank.cloud/`. The legacy name `dankserver.franksdank.cloud` 302-redirects there too. `plex.franksdank.casa` is the only plain-HTTP vhost; it cannot get a DNS-01 cert because `franksdank.casa` is not in the Porkbun account. The canonical Plex name is `plex.franksdank.cloud`.
## Basic auth
Generate a bcrypt hash, then reference it:
```
chat.franksdank.cloud {
basicauth {
dank $2a$14$xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
}
reverse_proxy 192.168.0.143:3005
}
```
The homepage also uses basic auth; see [[Homepage]].
## Operations
Validate before a reload:
```
caddy validate --config /etc/caddy/Caddyfile --adapter caddyfile
```
Certificates and ACME state live in the caddy data volume. Back it up with the stack. Each vhost owns one certificate; renewals are automatic and also use DNS-01.
## Gotchas
- Caddy auto-provisions Let's Encrypt certs for public domains; `.local` names stay internal (no external DNS).
- Validate before reload: `caddy validate --config /etc/caddy/Caddyfile --adapter caddyfile`.
- Certificates live in the caddy data volume; back it up with the stack.
- A new vhost needs three things: a dnsmasq `addn-hosts` line, a Porkbun A record, and the Caddyfile block. See [[LAN-DNS]].
- The G36 has no NAT loopback, so LAN clients must resolve the name to the LAN IP. That is the dnsmasq role in [[LAN-DNS]].
- Caddy serves HTTPS on 443 and HTTP on 80 (redirects). The router needs no 80/443 port forward for LAN use.
## See Also
- [[Dankserver Stack]]
- [[Dankclaw Stack]]
- [[LAN-DNS]] — how names resolve on the LAN and WAN
- [[Network Architecture]] — topology, access policy
- [[Homepage]]
- Knowledge base: [[Gitea Architecture]] (the existing caddy chain on Dankclaw)
- [[Dankclaw Stack]]