This commit is contained in:
276
README.md
276
README.md
@@ -1,79 +1,68 @@
|
|||||||
# matomo-bootstrap
|
# matomo-bootstrap
|
||||||
[](https://github.com/sponsors/kevinveenbirkenbach) [](https://www.patreon.com/c/kevinveenbirkenbach) [](https://buymeacoffee.com/kevinveenbirkenbach) [](https://s.veen.world/paypaldonate)
|
|
||||||
|
|
||||||
|
|
||||||
Headless bootstrap tooling for **Matomo**
|
|
||||||
Automates **installation** (via recorded Playwright flow) and **API token provisioning** for fresh Matomo instances.
|
|
||||||
|
|
||||||
This tool is designed for **CI, containers, and reproducible environments**, where no interactive browser access is available.
|
|
||||||
|
|
||||||
|
Headless bootstrap tooling for **Matomo**. Automates **first-time installation** and **API token provisioning** for fresh Matomo instances.
|
||||||
---
|
---
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
* 🚀 **Fully headless Matomo installation**
|
- 🚀 **Fully headless Matomo installation**
|
||||||
|
- Drives the official Matomo web installer using **Playwright**
|
||||||
* Drives the official Matomo web installer using **Playwright**
|
- Automatically skips the installer if Matomo is already installed
|
||||||
* Automatically skips installation if Matomo is already installed
|
- 🔐 **API token provisioning**
|
||||||
* 🔐 **API token provisioning**
|
- Creates an **app-specific token** via an authenticated Matomo session
|
||||||
|
- Compatible with **Matomo 5.3.x** Docker images
|
||||||
* Creates an *app-specific token* via authenticated Matomo session
|
- 🧪 **E2E-tested**
|
||||||
* Compatible with Matomo 5.3.x Docker images
|
- Docker-based end-to-end tests included
|
||||||
* 🧪 **E2E-tested**
|
- ❄️ **First-class Nix support**
|
||||||
|
- Flake-based packaging and pinned `flake.lock`
|
||||||
* Docker-based end-to-end tests included
|
- Uses `nixpkgs` browsers via `playwright-driver` (no Playwright downloads)
|
||||||
* ❄️ **First-class Nix support**
|
- 🧼 **Token-only stdout contract**
|
||||||
|
- **stdout contains only the token** (safe for scripting)
|
||||||
* Flake-based packaging
|
- Logs go to **stderr**
|
||||||
* Reproducible CLI and dev environments
|
|
||||||
* 🐍 **Standard Python CLI**
|
|
||||||
|
|
||||||
* Installable via `pip`
|
|
||||||
* Clean stdout (token only), logs on stderr
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
* A running Matomo instance (e.g. Docker)
|
- A running Matomo instance (e.g. via Docker)
|
||||||
* For fresh installs:
|
- For fresh installs:
|
||||||
|
- Chromium (provided by Playwright or by the Playwright base container image)
|
||||||
* Chromium (managed automatically by Playwright)
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
### Using **Nix** (recommended)
|
### Nix (recommended)
|
||||||
|
|
||||||
If you use **Nix** with flakes:
|
Run directly from the repository:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
nix run github:kevinveenbirkenbach/matomo-bootstrap
|
nix run github:kevinveenbirkenbach/matomo-bootstrap
|
||||||
```
|
```
|
||||||
|
|
||||||
Install Playwright’s Chromium browser (one-time):
|
In Nix mode, browsers are provided via `nixpkgs` (`playwright-driver`) and Playwright downloads are disabled.
|
||||||
|
|
||||||
```bash
|
|
||||||
nix run github:kevinveenbirkenbach/matomo-bootstrap#matomo-bootstrap-playwright-install
|
|
||||||
```
|
|
||||||
|
|
||||||
This installs Chromium into the user cache used by Playwright.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Using **Python / pip**
|
### Python / pip
|
||||||
|
|
||||||
Requires **Python ≥ 3.10**
|
Requires **Python ≥ 3.10**:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pip install matomo-bootstrap
|
pip install matomo-bootstrap
|
||||||
|
python -m playwright install chromium
|
||||||
```
|
```
|
||||||
|
|
||||||
Install Chromium for Playwright:
|
---
|
||||||
|
|
||||||
|
### Docker image (GHCR)
|
||||||
|
|
||||||
|
Pull the prebuilt image:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python -m playwright install chromium
|
docker pull ghcr.io/kevinveenbirkenbach/matomo-bootstrap:stable
|
||||||
|
# or:
|
||||||
|
docker pull ghcr.io/kevinveenbirkenbach/matomo-bootstrap:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -86,11 +75,12 @@ python -m playwright install chromium
|
|||||||
matomo-bootstrap \
|
matomo-bootstrap \
|
||||||
--base-url http://127.0.0.1:8080 \
|
--base-url http://127.0.0.1:8080 \
|
||||||
--admin-user administrator \
|
--admin-user administrator \
|
||||||
--admin-password AdminSecret123! \
|
--admin-password 'AdminSecret123!' \
|
||||||
--admin-email administrator@example.org
|
--admin-email administrator@example.org \
|
||||||
|
--token-description my-ci-token
|
||||||
```
|
```
|
||||||
|
|
||||||
On success, the command prints **only the API token** to stdout:
|
On success, the command prints **only the token** to stdout:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
6c7a8c2b0e9e4a3c8e1d0c4e8a6b9f21
|
6c7a8c2b0e9e4a3c8e1d0c4e8a6b9f21
|
||||||
@@ -98,14 +88,14 @@ On success, the command prints **only the API token** to stdout:
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Environment Variables
|
### Environment variables
|
||||||
|
|
||||||
All options can be provided via environment variables:
|
All options can be provided via environment variables:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
export MATOMO_URL=http://127.0.0.1:8080
|
export MATOMO_URL=http://127.0.0.1:8080
|
||||||
export MATOMO_ADMIN_USER=administrator
|
export MATOMO_ADMIN_USER=administrator
|
||||||
export MATOMO_ADMIN_PASSWORD=AdminSecret123!
|
export MATOMO_ADMIN_PASSWORD='AdminSecret123!'
|
||||||
export MATOMO_ADMIN_EMAIL=administrator@example.org
|
export MATOMO_ADMIN_EMAIL=administrator@example.org
|
||||||
export MATOMO_TOKEN_DESCRIPTION=my-ci-token
|
export MATOMO_TOKEN_DESCRIPTION=my-ci-token
|
||||||
|
|
||||||
@@ -114,9 +104,9 @@ matomo-bootstrap
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Debug Mode
|
### Debug mode
|
||||||
|
|
||||||
Enable verbose logs (stderr only):
|
Enable verbose logs (**stderr only**):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
matomo-bootstrap --debug
|
matomo-bootstrap --debug
|
||||||
@@ -124,27 +114,172 @@ matomo-bootstrap --debug
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## How It Works
|
## Docker Compose integration (one-shot bootstrap)
|
||||||
|
|
||||||
1. **Reachability check**
|
### Why “one-shot”?
|
||||||
|
|
||||||
* Waits until Matomo responds over HTTP (any status)
|
The bootstrap container is meant to:
|
||||||
2. **Installation (if needed)**
|
|
||||||
|
|
||||||
* Uses a recorded Playwright flow to complete the Matomo web installer
|
1. Run once,
|
||||||
3. **Authentication**
|
2. Print the token to stdout,
|
||||||
|
3. Exit with code `0`.
|
||||||
|
|
||||||
* Logs in using the `Login.logme` controller
|
You should **not** start it automatically on every `docker compose up`.
|
||||||
4. **Token creation**
|
Instead, start Matomo normally, then run the bootstrap via `docker compose run`.
|
||||||
|
|
||||||
* Calls `UsersManager.createAppSpecificTokenAuth`
|
The cleanest Compose pattern is to put `bootstrap` behind a **profile**.
|
||||||
5. **Output**
|
|
||||||
|
|
||||||
* Prints the token to stdout (safe for scripting)
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## End-to-End Tests
|
### Example `docker-compose.yml` (recommended: `profiles`)
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
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:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose up -d db matomo
|
||||||
|
```
|
||||||
|
|
||||||
|
Run bootstrap once (prints token to stdout):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose --profile bootstrap run --rm bootstrap
|
||||||
|
```
|
||||||
|
|
||||||
|
Re-run bootstrap (creates a new token by default):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
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:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export MATOMO_BOOTSTRAP_TOKEN_AUTH="0123456789abcdef..."
|
||||||
|
matomo-bootstrap
|
||||||
|
```
|
||||||
|
|
||||||
|
> This is useful for CI re-runs or configuration management tools.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## How it works
|
||||||
|
|
||||||
|
1. **Reachability check**
|
||||||
|
|
||||||
|
* waits until Matomo responds via HTTP (any status is considered “reachable”)
|
||||||
|
2. **Installation (if needed)**
|
||||||
|
|
||||||
|
* uses a recorded Playwright flow to complete the Matomo web installer
|
||||||
|
3. **Authentication**
|
||||||
|
|
||||||
|
* logs in using Matomo’s `Login.logme` controller (cookie session)
|
||||||
|
4. **Token creation**
|
||||||
|
|
||||||
|
* calls `UsersManager.createAppSpecificTokenAuth`
|
||||||
|
5. **Output**
|
||||||
|
|
||||||
|
* prints the token to stdout (token-only contract)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## End-to-end tests
|
||||||
|
|
||||||
Run the full E2E cycle locally:
|
Run the full E2E cycle locally:
|
||||||
|
|
||||||
@@ -157,27 +292,18 @@ This will:
|
|||||||
1. Start Matomo + MariaDB via Docker
|
1. Start Matomo + MariaDB via Docker
|
||||||
2. Install Matomo headlessly
|
2. Install Matomo headlessly
|
||||||
3. Create an API token
|
3. Create an API token
|
||||||
4. Validate the token via Matomo API
|
4. Validate the token via the Matomo API
|
||||||
5. Tear everything down again
|
5. Tear everything down again
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Project Status
|
|
||||||
|
|
||||||
* ✔ Stable for CI / automation
|
|
||||||
* ✔ Tested against Matomo 5.3.x Docker images
|
|
||||||
* ⚠ Installer flow is UI-recorded (robust, but may need updates for future Matomo UI changes)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Author
|
## Author
|
||||||
|
|
||||||
**Kevin Veen-Birkenbach**
|
**Kevin Veen-Birkenbach**
|
||||||
🌐 [https://www.veen.world/](https://www.veen.world/)
|
[https://www.veen.world/](https://www.veen.world/)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
MIT License
|
MIT — see [LICENSE](LICENSE)
|
||||||
See [LICENSE](LICENSE)
|
|
||||||
|
|||||||
Reference in New Issue
Block a user