Deploy hook and Cloudflare
reconciler for Docker Swarm
swarmctl gives CI one endpoint to roll a new image into a running service,
and keeps Cloudflare Tunnel ingress, DNS, and Access apps in sync with the labels on your services.
One POST deploys a service
POST /v1/update/{service}?image=… swaps the image on a running Swarm service and returns the old and new spec versions. Nothing else in the spec is touched.
Ingress from labels
A service that carries cloudflared.tunnel.* labels gets a tunnel ingress entry and a proxied CNAME. No per-service config lives in swarmctl.
Cleans up after itself
Removing a service parks a pending removal; after a delay the reconciler diffs the live tunnel config against running services and drops the orphans.
SSO with one more label
cloudflared.tunnel.access.policy=
Tells you when things die
Container die/restart/crash events become Pushover pushes, deduped per container so a crash loop is one notification a minute, not fifty.
Prometheus and Discord
A /metrics endpoint outside auth for scraping, a Grafana dashboard in the repo, and WARN+ logs mirrored to a Discord webhook.
# deploy a new image from CI
curl -X POST -H "Authorization: Bearer $AUTH_TOKEN" \
"https://swarmctl.example.com/v1/update/web_server?image=ghcr.io/you/web:sha-abc123"# and this is all a service needs to get a hostname
labels:
- "cloudflared.tunnel.enabled=true"
- "cloudflared.tunnel.port=80"
- "cloudflared.tunnel.hostname=app.example.com"