-
Notifications
You must be signed in to change notification settings - Fork 0
Docker
StatsServiceBook is available as a pre-built Docker image on Docker Hub at
jraczek/statsservicebook.
The image bundles all three data-source pipelines (Strava API, Strava scrape
mode, HealthSync/Google Drive) under crond + lighttpd on Alpine Linux.
Mount your config file, start the container, and the pages are live on port 80.
- Docker ≥ 20 or Podman ≥ 4
- One filled-in config file (see Configuration below)
- Credentials for your chosen data source (Strava API / scrape / HealthSync)
Copy the template for your data source from the docker/ directory:
# Strava API or scrape mode:
cp docker/strava-my-activities.conf.example my-activities.conf
# HealthSync / Google Drive:
cp docker/healthsync-activities.conf.example healthsync.conf
# Club leaderboard (optional, in addition to my-activities):
cp docker/strava-leaderboard.conf.example leaderboard.confEdit the file you copied. The minimum required fields are:
| Source | Required fields |
|---|---|
| Strava API |
STRAVA_CLIENT_ID, STRAVA_CLIENT_SECRET, STRAVA_REFRESH_TOKEN
|
| Strava scrape |
STRAVA_MY_SOURCE=scrape, STRAVA_SESSION_COOKIE
|
| HealthSync |
GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, GOOGLE_REFRESH_TOKEN, DRIVE_FOLDER_ID
|
All path variables (STRAVA_MY_STATE_DIR, HEALTHSYNC_STATE_DIR, etc.) are
pre-set to /data/... in the Docker templates — do not change them unless you
know what you are doing.
# Edit docker-compose.yml — uncomment the config volume line that matches your
# data source, then:
docker compose up -d
# Watch startup logs:
docker compose logs -fOpen http://localhost/strava/me/ once the first run completes.
docker run -d --name statsservicebook \
-p 80:80 \
-v "$(pwd)/my-activities.conf:/etc/strava-my-activities.conf:ro" \
-v statsservicebook_data:/data \
-e TZ=Europe/Warsaw \
-e RUN_ON_START=1 \
jraczek/statsservicebook:latestEach data source is enabled by mounting its config file into the container. Only the files you mount are activated — unmounted sources are silently ignored.
| Mount path | Template | Purpose |
|---|---|---|
/etc/strava-my-activities.conf |
docker/strava-my-activities.conf.example |
My Activities (Strava API or scrape) |
/etc/strava-leaderboard.conf |
docker/strava-leaderboard.conf.example |
Club leaderboard |
/etc/healthsync-activities.conf |
docker/healthsync-activities.conf.example |
HealthSync / Google Drive |
You can mount more than one config file — all enabled sources run in cron and
on RUN_ON_START.
| Variable | Default | Description |
|---|---|---|
TZ |
(UTC) | Timezone for cron scheduling and log timestamps |
RUN_ON_START |
0 |
Set to 1 to run all enabled scripts once at container start |
CRON_LEADERBOARD |
50 23 * * * |
Cron schedule for strava-leaderboard
|
CRON_MY_ACTIVITIES |
55 23 * * * |
Cron schedule for strava-my-activities
|
CRON_HEALTHSYNC |
55 23 * * * |
Cron schedule for healthsync-activities
|
The container writes all state (OAuth token cache, activity NDJSON store,
per-activity detail JSON, bike-service data) to /data. Mount this as a
named volume or host directory so data survives container restarts:
volumes:
- statsservicebook_data:/data # named volume (docker compose)
# or:
- /opt/statsservicebook:/data # host directoryThe web output (/www/strava/) is regenerated on every cron run from the
state in /data — it does not need to be persisted separately.
The repo includes a ready-to-use docker-compose.yml. Uncomment the volume
lines for the data sources you use:
services:
statsservicebook:
image: jraczek/statsservicebook:latest
ports:
- "80:80"
environment:
TZ: Europe/Warsaw
RUN_ON_START: "1"
volumes:
- statsservicebook_data:/data
- ./my-activities.conf:/etc/strava-my-activities.conf:ro
# - ./leaderboard.conf:/etc/strava-leaderboard.conf:ro
# - ./healthsync.conf:/etc/healthsync-activities.conf:ro
restart: unless-stopped
volumes:
statsservicebook_data:# Run a single script now (inside the running container):
docker exec statsservicebook strava-my-activities
docker exec statsservicebook healthsync-activities
docker exec statsservicebook strava-leaderboard# Container startup + first-run output:
docker logs statsservicebook
# Cron job output (written by entrypoint to /var/log/ inside container):
docker exec statsservicebook tail -f /var/log/strava-my-activities.log
docker exec statsservicebook tail -f /var/log/healthsync-activities.log
docker exec statsservicebook tail -f /var/log/strava-leaderboard.log| Tag | Meaning |
|---|---|
latest |
Latest release from the main branch |
v1.2.3 |
Specific release tag |
1.2 |
Latest patch for a minor version |
Images are built for linux/amd64, linux/arm64, and linux/arm/v7 (Raspberry Pi), so the same tag works on all three architectures.
docker build -t statsservicebook .
docker run -d --name statsservicebook \
-p 80:80 \
-v "$(pwd)/my-activities.conf:/etc/strava-my-activities.conf:ro" \
-v statsservicebook_data:/data \
-e TZ=Europe/Warsaw \
-e RUN_ON_START=1 \
statsservicebookThe GitHub Actions workflow .github/workflows/docker-publish.yml builds and
pushes to Docker Hub automatically:
# Tag the release and push — the workflow handles the rest:
git tag v1.2.3
git push origin v1.2.3Required repository secrets:
-
DOCKERHUB_USERNAME— Docker Hub username (ocaramba) -
DOCKERHUB_TOKEN— Docker Hub access token (generate at hub.docker.com → Account settings → Security)
The workflow also supports manual dispatch from the GitHub Actions UI to push
latest without tagging.
| Aspect | OpenWrt router | Docker |
|---|---|---|
| Web server | uhttpd (built-in) | lighttpd (in image) |
| Scheduler | OpenWrt cron | BusyBox crond (in image) |
| State storage |
/mnt/sda5/... (USB) |
/data volume |
| Port | 80 (served by router) | configurable (-p HOST:80) |
| Config | SSH to /etc/*.conf
|
bind-mount from host |
The shell scripts themselves are identical — the image ships the same POSIX sh scripts that run on the router.