Docker & Caddy¶
Everything-in-Docker stack on pwa-host¶
flowchart TB
Net((:80/:443)) --> Caddy[fatbot-caddy<br/>caddy:alpine]
Caddy -->|host.docker.internal:3030| Web[fruitplug-web-dev]
Caddy -->|host.docker.internal:3040| Docs[fruitplug-docs]
Caddy -->|host.docker.internal:8000| FB[fatbot-dashboard]
Caddy -->|host.docker.internal:8001| FBD[fatbot-docs]
Caddy -->|host.docker.internal:8050| FBF[footballdesk-app]
One Caddy, multiple apps, one cert manager.
Caddyfile¶
Bind-mounted into the fatbot-caddy container at /etc/caddy/Caddyfile from:
Current contents:
fatbot.ai, www.fatbot.ai {
reverse_proxy host.docker.internal:8000
}
docs.fatbot.ai {
reverse_proxy host.docker.internal:8001
}
football.fatbot.ai {
reverse_proxy host.docker.internal:8050
}
dev.fruitplug.co.uk {
reverse_proxy host.docker.internal:3030
}
docs.fruitplug.co.uk {
reverse_proxy host.docker.internal:3040
}
Editing + reloading¶
# Edit
notepad C:\Users\User\Desktop\Caddy\Caddyfile
# Validate (always first!)
MSYS_NO_PATHCONV=1 docker exec fatbot-caddy \
caddy validate --config /etc/caddy/Caddyfile --adapter caddyfile
# Hot reload (zero-downtime)
MSYS_NO_PATHCONV=1 docker exec fatbot-caddy \
caddy reload --config /etc/caddy/Caddyfile --adapter caddyfile
MSYS_NO_PATHCONV
Git Bash on Windows rewrites /etc/caddy/... into C:\Program Files\Git\etc\caddy\.... Always prefix docker exec with MSYS_NO_PATHCONV=1.
Containers we manage¶
fruitplug-web-dev (the PWA)¶
docker ps --filter name=fruitplug-web-dev
docker logs -f fruitplug-web-dev
docker restart fruitplug-web-dev
# rebuild image after package.json changes
docker build -f infra/dev.Dockerfile -t fruitplug-web:dev .
# then restart the container — see infra/docker-compose.prod.yml for the
# canonical `docker run` flags including bind mounts + env vars
Image: fruitplug-web:dev (built from infra/dev.Dockerfile). Bind-mounts the entire apps/web directory + packages/ for hot reload with webpack polling (WATCHPACK_POLLING=true, poll: 800 in next.config.ts).
fruitplug-docs (this wiki)¶
Image: fruitplug-docs:local (built from docs/Dockerfile). Runs mkdocs serve --livereload with /docs bind-mounted from the host, so edits to .md files auto-reload the browser.
Backups¶
The Caddyfile gets a timestamped backup before every edit by convention:
Existing backups:
TLS¶
Caddy auto-issues Let's Encrypt certs as soon as DNS propagates for a new domain. If you add a block for a new subdomain:
- Create the DNS A-record pointing to
147.12.227.117 - Add the Caddy block + validate + reload
- First HTTPS request triggers cert issuance (usually < 10 s)
curl -sI https://<new>.fruitplug.co.ukreturns 200
If Caddy's ACME retry stalls after DNS propagation (it caches failures), restart the container to force a fresh attempt: