Maestro Helpcenter

Installing & Setting Up Maestro

This page covers installation, initial configuration, networking, upgrades, and data backup. It is the primary reference for anyone setting up a new environment.


Deployment Topologies

Maestro supports two deployment models depending on how many stations you are running.

Single-station (all-in-one)

All services run on one machine. This is the quickest path for evaluation, development, and single-bench labs.

┌──────────────────────────────────────────────┐
│  One machine                             │
│  PostgreSQL · Redis · API · UI · Runners │
└──────────────────────────────────────────────┘

Multi-station (shared infrastructure)

One central server hosts the database and fleet dashboard. Each test station runs its own API, UI, and runners, and connects outbound to the shared database.

┌──────────────────────────────────────────────┐
│  CENTRAL SERVER                          │
│  PostgreSQL · Dashboard · pgAdmin        │
└────────────────┬─────────────────────────────┘
                 │ (network, port 5432)
     ┌───────────┴───────────┐
     │                     │
┌────┴──────────┐  ┌─────────┴──────────┐
│  STATION A   │  │  STATION B       │
│  API · UI    │  │  API · UI        │
│  Runners     │  │  Runners         │
└───────────────┘  └────────────────────┘

Component

Central

Station

PostgreSQL (results DB)

Fleet Dashboard

pgAdmin

Maestro API

Maestro UI

.NET Runner

Python Runner

Redis


Prerequisites

All machines

Requirement

Version

Notes

Docker Engine + Compose V2

24+

docker compose (not docker-compose)

Network access to central server

Port 5432 from stations to central

GitLab Personal Access Token

read_registry + read_repository scopes

Platform-specific Docker setup

Platform

Installation method

Windows 10/11

Install Docker Desktop; enable the WSL 2 backend

Ubuntu / Debian

curl -fsSL <https://get.docker.com> \\| sh && sudo usermod -aG docker $USER

Raspberry Pi (64-bit OS)

Same as Ubuntu/Debian above

Raspberry Pi: The 64-bit Raspberry Pi OS is required. The 32-bit (armhf) image is not supported because .NET 10 requires arm64.

Generating a GitLab Personal Access Token

A GitLab PAT is required to pull Maestro container images from the registry and to access test package repositories.

  1. Log in to your GitLab instance

  2. Go to User Settings → Access Tokens

  3. Create a token with the following scopes: read_registry, read_repository

  4. Copy the token — you will need it during installation


Installing Maestro

Step 1 — Install the Central Server

Run this once on the machine that will host the shared database and dashboard.

Option A — one-line installer (recommended)

Bash
curl -fsSL https://git.esharp.se/testdevelopment/tat/-/raw/main/deploy/install-central.sh | \
  bash -s -- \
    --postgres-password "YOUR_STRONG_PASSWORD" \
    --pgadmin-password  "YOUR_PGADMIN_PASSWORD" \
    --git-token         "glpat-xxxxxxxxxxxx"

Option B — manual setup

Bash
mkdir -p ~/tat-central && cd ~/tat-central

curl -fsSL \
  -H "PRIVATE-TOKEN: glpat-xxxxxxxxxxxx" \
  "https://git.esharp.se/testdevelopment/tat/-/raw/main/deploy/central/docker-compose.central.yml" \
  -o docker-compose.yml

cat > .env <<EOF
POSTGRES_PASSWORD=YOUR_STRONG_PASSWORD
PGADMIN_EMAIL=admin@example.com
PGADMIN_PASSWORD=YOUR_PGADMIN_PASSWORD
EOF

echo "glpat-xxxxxxxxxxxx" | docker login git.esharp.se:5050 -u oauth2 --password-stdin

docker compose pull
docker compose up -d

Verify

Bash
docker compose ps
# postgres (healthy), dashboard (healthy), pgadmin (running)

Service

URL

Fleet Dashboard

<http://<central-ip>>:5002

pgAdmin

<http://<central-ip>>:5088

Note the IP address of this machine — you will need it when installing each station.


Step 2 — Install Each Test Station

Run this on every machine that will execute tests. For a single-station setup, run it on the same machine as Step 1.

Option A — one-line installer (recommended)

Bash
# Linux / macOS / WSL
curl -fsSL https://git.esharp.se/testdevelopment/tat/-/raw/main/deploy/install-station.sh | \
  bash -s -- \
    --postgres-host     "192.168.1.100" \
    --postgres-password "YOUR_STRONG_PASSWORD" \
    --git-token         "glpat-xxxxxxxxxxxx" \
    --station-name      "station-lab-01"

On Windows, run this in Git Bash or WSL:

Bash
curl -fsSL https://git.esharp.se/testdevelopment/tat/-/raw/main/deploy/install-station.sh | \
  bash -s -- \
    --postgres-host     "192.168.1.100" \
    --postgres-password "YOUR_STRONG_PASSWORD" \
    --git-token         "glpat-xxxxxxxxxxxx" \
    --station-name      "station-dev-alice"

Option B — manual setup

Bash
mkdir -p ~/tat-station && cd ~/tat-station

curl -fsSL \
  -H "PRIVATE-TOKEN: glpat-xxxxxxxxxxxx" \
  "https://git.esharp.se/testdevelopment/tat/-/raw/main/deploy/station/docker-compose.station.yml" \
  -o docker-compose.yml

cat > .env <<EOF
POSTGRES_HOST=192.168.1.100
POSTGRES_PORT=5432
POSTGRES_PASSWORD=YOUR_STRONG_PASSWORD
GIT_HOST=git.esharp.se
STATION_NAME=station-lab-01
EOF

echo "glpat-xxxxxxxxxxxx" | docker login git.esharp.se:5050 -u oauth2 --password-stdin

docker compose pull
docker compose up -d

Verify

Bash
docker compose ps
# api (healthy), ui (healthy), dotnet-runner, python-runner, redis (healthy)

Service

URL

Maestro UI

<http://localhost:7001>

Maestro API

<http://localhost:7000>

API Swagger

<http://localhost:7000/swagger>


Step 3 — Enter Your Personal Access Token

The GitLab PAT used during installation authenticates Docker image pulls only. To allow Maestro itself to download and publish test packages, each station operator enters their own PAT through the UI.

  1. Open <http://localhost:7001/station-config>

  2. Scroll to the Package Registry section

  3. Enter your GitLab Personal Access Token

  4. Click Save

The token is stored in the database and is never written to any file or container environment variable.


Database schema

Maestro applies database migrations automatically on first API startup via EF Core. No manual schema setup or SQL scripts are required.


Initial Configuration Checklist

Complete these steps after installation before using Maestro in production.

#

Item

Where

Notes

1

Change default PostgreSQL password

docker-compose.yml + .env

Never use the default in a production environment

2

Change pgAdmin password

.envPGADMIN_PASSWORD

Restrict pgAdmin access to admin browsers

3

Set a unique station name

.envSTATION_NAME

Used to scope configuration and label all results

4

Configure the package registry URL

Station Config UI → Package Registry

Point to your catalog.json Git repository

5

Enter GitLab PAT

Station Config UI → Package Registry

Required for package download and publish

6

Set station-local config values

Station Config UI

COM ports, instrument addresses, fixture IDs

7

Configure DISPLAY_TIMEZONE

.env

e.g. Europe/Stockholm — affects all timestamps in the UI

8

Enable HTTPS

Reverse proxy (nginx / Caddy) or Kestrel TLS

Required before exposing the UI outside the local network

9

Set ASPNETCORE_ENVIRONMENT=Production

Docker environment

Disables developer exception pages

10

Pin image tags

.envIMAGE_TAG=<sha>

Use a commit SHA instead of latest for reproducible deployments

11

Schedule database backups

Cron / task scheduler

See Backing Up and Restoring


Licensing & Access

Maestro is distributed as container images through a private GitLab registry. Access is controlled by your GitLab Personal Access Token — there is no separate license key or activation step.

If your token expires or is revoked, stations will be unable to pull updated images. Existing running containers are not affected until the next upgrade.

To generate or renew a token:

  1. Log in to your GitLab instance

  2. Go to User Settings → Access Tokens

  3. Create or rotate a token with read_registry and read_repository scopes

  4. Re-authenticate each Docker host: echo "<token>" | docker login git.esharp.se:5050 -u oauth2 --password-stdin


Network, Firewall, and Security Requirements

Required open ports (inbound on the central server)

Port

Service

Allowed from

5432

PostgreSQL

All station IPs

5002

Fleet Dashboard

Operator browsers (optional)

5088

pgAdmin

Admin machines only

Stations do not require any inbound ports. All connections are outbound — to the central server (port 5432) and to the GitLab container registry (port 443).

Firewall recommendations

  • Restrict PostgreSQL (5432) to known station IP addresses using firewall rules or a VPN

  • Do not expose pgAdmin (5088) to the open internet

  • Place Maestro API (7000) and UI (7001) behind a reverse proxy with TLS if accessed over untrusted networks

HTTPS setup

For production deployments, terminate TLS at a reverse proxy in front of the Maestro UI and API. A minimal nginx configuration:

nginx
server {
    listen 443 ssl;
    server_name maestro.example.com;

    ssl_certificate     /etc/ssl/certs/maestro.crt;
    ssl_certificate_key /etc/ssl/private/maestro.key;

    location / {
        proxy_pass http://localhost:7001;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
    }
}

SignalR (used for real-time updates) requires WebSocket support. Ensure your proxy forwards Upgrade and Connection headers as shown above.

Secrets management

Secret

Where to store

PostgreSQL password

.env file (restrict file permissions: chmod 600 .env)

pgAdmin password

.env file

GitLab PAT (for Docker)

Used once during install; not persisted

GitLab PAT (for packages)

Stored in the Maestro database via the Station Config UI


Upgrading Maestro

Maestro images are rebuilt on every push to main. Each image is tagged with both latest and the commit SHA.

Update a station

Bash
cd ~/tat-station
docker compose pull
docker compose up -d

This pulls the latest images for your architecture and restarts only containers where the image has changed. Redis data and any mounted volumes are preserved.

Update the central server

Bash
cd ~/tat-central
docker compose pull
docker compose up -d

The PostgreSQL data volume is untouched during upgrades. Only the Dashboard container is replaced.

Pin a specific version

To deploy a specific build rather than latest, set IMAGE_TAG in .env:

Bash
# ~/tat-station/.env  or  ~/tat-central/.env
IMAGE_TAG=abc1234

Then run docker compose pull && docker compose up -d.

Database migrations

EF Core migrations run automatically when the API container starts after an upgrade. Migrations are always forward-only and non-destructive. No manual intervention is required.

If a migration fails at startup (visible in docker compose logs api), do not restart repeatedly. Restore from a backup, investigate the migration error, and contact support.


Backing Up and Restoring Maestro Data

All persistent Maestro state lives in PostgreSQL. Redis is ephemeral (variable bus only) and does not need to be backed up.

What to back up

Data

Storage

Backup method

Test results, measurements, logs

PostgreSQL volume

pg_dump or volume snapshot

Station configuration

PostgreSQL volume

Included in pg_dump

Package lifecycle overrides

PostgreSQL volume

Included in pg_dump

.env files

Host filesystem

Copy to secure storage

Test packages (YAML + code)

Git repositories

Maintained in GitLab

Creating a database backup

Bash
# Dump the entire database to a compressed file
docker exec workflowengine-postgres \
  pg_dump -U postgres testautomation \
  | gzip > maestro-backup-$(date +%Y%m%d-%H%M%S).sql.gz

For scheduled backups, add this to cron (Linux) or Task Scheduler (Windows):

Bash
# /etc/cron.d/maestro-backup  — runs daily at 02:00
0 2 * * * root docker exec workflowengine-postgres \
  pg_dump -U postgres testautomation \
  | gzip > /backups/maestro-$(date +\%Y\%m\%d).sql.gz

Restoring from a backup

Bash
# Stop the API to prevent writes during restore
docker compose stop api ui

# Restore
gunzip -c maestro-backup-20260101-020000.sql.gz | \
  docker exec -i workflowengine-postgres \
  psql -U postgres testautomation

# Restart services
docker compose start api ui

Volume snapshot (alternative)

If your infrastructure supports volume snapshots (e.g., LVM, ZFS, cloud block storage), snapshot the Docker volume directly:

Bash
# Find the volume
docker volume inspect workflowengine-postgres-data

# Take a filesystem-level snapshot via your platform tooling

Volume snapshots are faster than pg_dump for large databases but require the database to be quiesced or the PostgreSQL volume to support consistent snapshots.

Recovery time objectives

Scenario

Recovery approach

Estimated time

Accidental data deletion

Restore from pg_dump

Minutes

Container or host failure

Pull images + restore volume

< 30 minutes

Full station reinstall

Run installer + restore DB

< 1 hour


Environment Variable Reference

Station .env

Variable

Required

Default

Description

POSTGRES_HOST

Central PostgreSQL server IP or hostname

POSTGRES_PORT

5432

PostgreSQL port

POSTGRES_PASSWORD

PostgreSQL password

GIT_HOST

git.esharp.se

GitLab hostname

STATION_NAME

machine hostname

Unique station identifier

DISPLAY_TIMEZONE

UTC

e.g. Europe/Stockholm

IMAGE_TAG

latest

Container image version to deploy

Central server .env

Variable

Required

Default

Description

POSTGRES_PASSWORD

PostgreSQL superuser password

POSTGRES_PORT

5432

Exposed PostgreSQL port

PGADMIN_EMAIL

admin@example.com

pgAdmin login email

PGADMIN_PASSWORD

pgAdmin login password

DISPLAY_TIMEZONE

UTC

Dashboard timezone


Troubleshooting

Station cannot connect to PostgreSQL

Bash
docker run --rm postgres:16-alpine \
  pg_isready -h <central-ip> -p 5432 -U postgres

If this fails, verify that port 5432 is open on the central server's firewall and that POSTGRES_HOST in .env is correct.

Images fail to pull

Bash
# Re-authenticate
echo "glpat-xxx" | docker login git.esharp.se:5050 -u oauth2 --password-stdin

# Confirm the image exists
docker manifest inspect git.esharp.se:5050/testdevelopment/tat/api:latest

Raspberry Pi: "no matching manifest for linux/arm/v7"

You are running the 32-bit Raspberry Pi OS. Switch to the 64-bit version using Raspberry Pi Imager: Choose OS → Raspberry Pi OS (64-bit).

Check service logs

Bash
cd ~/tat-station
docker compose logs api            # API startup and migration logs
docker compose logs dotnet-runner  # .NET runner logs
docker compose logs -f             # Follow all service logs