Install
From an empty Docker host to a working coachd: Garmin data in, an agent connected, and your passkey enrolled. Just looking? Try it with demo data first, without a Garmin key.
deploy/compose.yaml runs coachd with Tailscale (the private lane), Grafana Alloy, VictoriaMetrics and VictoriaLogs. coachd publishes one port, its public listener on 127.0.0.1:8080: a Cloudflare Tunnel (cloudflared on the host) or a reverse proxy on the host forwards your hostname to it. Run every command in these pages from deploy/.
Get the stack files
git clone https://github.com/stefiix92/coachd.git
cd coachd/deploy
cp .env.example .envSet COACHD_TIMEZONE in .env. Tokens never go in .env: they are secret files. Every setting is in the configuration reference.
Encrypt the data disk
The coachd-data volume holds health data, raw Garmin JSON and FIT files, and token hashes. It must be on an encrypted disk: put Docker’s data root (or just this volume) on LUKS. coachd does not manage disk encryption.
Get the image
The signed release image, or your own build: Get the image.
Create the secrets
The Garmin key, the Tailscale auth key and the ntfy token: Secrets.
Add your Garmin key
Open the public lane
Pick one:
- Cloudflare Access: Cloudflare does the login and MFA, and signs in the AI apps.
- Built-in auth: coachd does it with your passkey and its own OAuth 2.1 server. No Cloudflare account needed.
Open the private lane
Tailscale, for agents on your own devices.
Enrol your passkey
Enrol a passkey. It approves every workout.