6.7 KiB
matomo-bootstrap
Headless bootstrap tooling for Matomo. Automates first-time installation and API token provisioning for fresh Matomo instances.
Features
- 🚀 Fully headless Matomo installation
- Drives the official Matomo web installer using Playwright
- Automatically skips the installer if Matomo is already installed
- 🔐 API token provisioning
- Creates an app-specific token via an authenticated Matomo session
- Compatible with Matomo 5.3.x Docker images
- 🧪 E2E-tested
- Docker-based end-to-end tests included
- ❄️ First-class Nix support
- Flake-based packaging and pinned
flake.lock - Uses
nixpkgsbrowsers viaplaywright-driver(no Playwright downloads)
- Flake-based packaging and pinned
- 🧼 Token-only stdout contract
- stdout contains only the token (safe for scripting)
- Logs go to stderr
Requirements
- A running Matomo instance (e.g. via Docker)
- For fresh installs:
- Chromium (provided by Playwright or by the Playwright base container image)
Installation
Nix (recommended)
Run directly from the repository:
nix run github:kevinveenbirkenbach/matomo-bootstrap
In Nix mode, browsers are provided via nixpkgs (playwright-driver) and Playwright downloads are disabled.
Python / pip
Requires Python ≥ 3.10:
pip install matomo-bootstrap
python -m playwright install chromium
Docker image (GHCR)
Pull the prebuilt image:
docker pull ghcr.io/kevinveenbirkenbach/matomo-bootstrap:stable
# or:
docker pull ghcr.io/kevinveenbirkenbach/matomo-bootstrap:latest
Usage
CLI
matomo-bootstrap \
--base-url http://127.0.0.1:8080 \
--admin-user administrator \
--admin-password 'AdminSecret123!' \
--admin-email administrator@example.org \
--token-description my-ci-token
On success, the command prints only the token to stdout:
6c7a8c2b0e9e4a3c8e1d0c4e8a6b9f21
Environment variables
All options can be provided via environment variables:
export MATOMO_URL=http://127.0.0.1:8080
export MATOMO_ADMIN_USER=administrator
export MATOMO_ADMIN_PASSWORD='AdminSecret123!'
export MATOMO_ADMIN_EMAIL=administrator@example.org
export MATOMO_TOKEN_DESCRIPTION=my-ci-token
matomo-bootstrap
Debug mode
Enable verbose logs (stderr only):
matomo-bootstrap --debug
Docker Compose integration (one-shot bootstrap)
Why “one-shot”?
The bootstrap container is meant to:
- Run once,
- Print the token to stdout,
- Exit with code
0.
You should not start it automatically on every docker compose up.
Instead, start Matomo normally, then run the bootstrap via docker compose run.
The cleanest Compose pattern is to put bootstrap behind a profile.
Example docker-compose.yml (recommended: profiles)
services:
db:
image: mariadb:11
container_name: matomo-db
restart: unless-stopped
environment:
MARIADB_DATABASE: matomo
MARIADB_USER: matomo
MARIADB_PASSWORD: matomo_pw
MARIADB_ROOT_PASSWORD: root_pw
volumes:
- mariadb_data:/var/lib/mysql
healthcheck:
test: ["CMD-SHELL", "mariadb-admin ping -uroot -proot_pw --silent"]
interval: 5s
timeout: 3s
retries: 60
matomo:
image: matomo:5.3.2
container_name: matomo
restart: unless-stopped
depends_on:
db:
condition: service_healthy
ports:
- "${MATOMO_PORT:-8080}:80"
environment:
MATOMO_DATABASE_HOST: db
MATOMO_DATABASE_ADAPTER: mysql
MATOMO_DATABASE_USERNAME: matomo
MATOMO_DATABASE_PASSWORD: matomo_pw
MATOMO_DATABASE_DBNAME: matomo
volumes:
- matomo_data:/var/www/html
healthcheck:
test: ["CMD-SHELL", "wget -qO- http://127.0.0.1/ >/dev/null || exit 1"]
interval: 10s
timeout: 5s
retries: 60
bootstrap:
# This prevents automatic startup during a normal `docker compose up`
profiles: ["bootstrap"]
# Option A: use the published image (recommended)
image: ghcr.io/kevinveenbirkenbach/matomo-bootstrap:1.0.1
# Option B: build locally from the repository checkout
# build:
# context: .
# dockerfile: Dockerfile
# image: matomo-bootstrap:local
container_name: matomo-bootstrap
depends_on:
matomo:
condition: service_started
environment:
# inside the compose network, Matomo is reachable via the service name
MATOMO_URL: "http://matomo"
MATOMO_ADMIN_USER: "administrator"
MATOMO_ADMIN_PASSWORD: "AdminSecret123!"
MATOMO_ADMIN_EMAIL: "administrator@example.org"
MATOMO_TOKEN_DESCRIPTION: "docker-compose-bootstrap"
# Values used by the recorded installer flow
MATOMO_SITE_NAME: "Matomo (docker-compose)"
MATOMO_SITE_URL: "http://127.0.0.1:${MATOMO_PORT:-8080}"
MATOMO_TIMEZONE: "Germany - Berlin"
# Optional stability knobs
MATOMO_TIMEOUT: "30"
MATOMO_PLAYWRIGHT_HEADLESS: "1"
MATOMO_PLAYWRIGHT_NAV_TIMEOUT_MS: "60000"
MATOMO_PLAYWRIGHT_SLOWMO_MS: "0"
restart: "no"
volumes:
mariadb_data:
matomo_data:
Commands
Start DB + Matomo without bootstrap:
docker compose up -d db matomo
Run bootstrap once (prints token to stdout):
docker compose --profile bootstrap run --rm bootstrap
Re-run bootstrap (creates a new token by default):
docker compose --profile bootstrap run --rm bootstrap
Idempotency / avoiding new tokens on every run
By default, UsersManager.createAppSpecificTokenAuth creates a new token each time.
If you want strictly idempotent runs in automation, you can provide an existing token and make the bootstrap return it instead of creating a new one:
export MATOMO_BOOTSTRAP_TOKEN_AUTH="0123456789abcdef..."
matomo-bootstrap
This is useful for CI re-runs or configuration management tools.
How it works
-
Reachability check
- waits until Matomo responds via HTTP (any status is considered “reachable”)
-
Installation (if needed)
- uses a recorded Playwright flow to complete the Matomo web installer
-
Authentication
- logs in using Matomo’s
Login.logmecontroller (cookie session)
- logs in using Matomo’s
-
Token creation
- calls
UsersManager.createAppSpecificTokenAuth
- calls
-
Output
- prints the token to stdout (token-only contract)
End-to-end tests
Run the full E2E cycle locally:
make e2e
This will:
- Start Matomo + MariaDB via Docker
- Install Matomo headlessly
- Create an API token
- Validate the token via the Matomo API
- Tear everything down again
Author
Kevin Veen-Birkenbach https://www.veen.world/
License
MIT — see LICENSE