Call Baxter deployment with Caddy and Docker Compose¶
Scope¶
The infra/ layout is the minimal Call Baxter deployment:
call-baxterruntime;tg-agent-cliprojection support;- Caddy HTTPS ingress;
- no bundled WordPress plugin, MariaDB, or WordPress service.
Use the full docker/ layout and Deploy → Telegram to WordPress with Docker for the complete bridge example.
Goal¶
Keep Call Baxter off the public TCP surface and expose only a narrow Telegram webhook path through Caddy.
Runtime layout¶
Telegram
-> https://PUBLIC_DOMAIN${TELEGRAM_WEBHOOK_PATH}
-> Caddy
-> unix:///srv/run/cb.sock
-> Call Baxter daemon
-> Telegram plugin persistence + event emission
-> tg-agent-cli projection database at /srv/data/tg.db
Bound host paths¶
Why this split¶
- Telegram webhook delivery requires a publicly reachable HTTPS endpoint.
- Caddy terminates TLS and reverse-proxies only the configured webhook and health paths.
- Call Baxter listens on a shared Unix socket rather than a public host port.
- The proxy checks
X-Telegram-Bot-Api-Secret-Tokenbefore forwarding a webhook payload. - Polling and webhook ingestion both normalize through the same Telegram plugin event path.
Configure the minimal stack¶
Edit .env and set:
TGCLI_BOT_TOKEN=123456:replace-me
PUBLIC_DOMAIN=bot.example.org
ACME_EMAIL=ops@example.org
TELEGRAM_WEBHOOK_PATH=/webhooks/telegram/main
TELEGRAM_WEBHOOK_SECRET=replace-with-long-random-token
TELEGRAM_POLL_ENABLED=false
Prepare writable bind mounts:
mkdir -p run data caddy_data caddy_config
sudo chown -R 10001:10001 run data caddy_data caddy_config
Validate and start:
docker compose config --quiet
docker compose up -d --build
docker compose ps
docker compose logs --tail=150 call-baxter caddy
Register the Telegram webhook¶
Load the env file:
Register the public URL:
curl --fail-with-body --silent --show-error \
--request POST \
"https://api.telegram.org/bot${TGCLI_BOT_TOKEN}/setWebhook" \
--data-urlencode "url=https://${PUBLIC_DOMAIN}${TELEGRAM_WEBHOOK_PATH}" \
--data-urlencode "secret_token=${TELEGRAM_WEBHOOK_SECRET}"
Inspect the result:
curl --fail-with-body --silent --show-error \
"https://api.telegram.org/bot${TGCLI_BOT_TOKEN}/getWebhookInfo"
Operational checks¶
curl --fail --silent --show-error "https://${PUBLIC_DOMAIN}/healthz"
docker compose exec call-baxter \
cb --config-file /srv/config/call-baxter.yml \
--daemon-url http+unix:///srv/run/cb.sock \
health
docker compose exec call-baxter \
tg --database-url /srv/data/tg.db messages list
Upstream references¶
- Telegram Bot API: https://core.telegram.org/bots/api
- Telegram webhook guide: https://core.telegram.org/bots/webhooks
- Caddy reverse proxy: https://caddyserver.com/docs/caddyfile/directives/reverse_proxy
- Docker Compose environment variables: https://docs.docker.com/compose/how-tos/environment-variables/