Skip to content

Payroll Engine Container Setup

This document describes how to set up and run the Payroll Engine stack using Docker.

Setup Variants

The repository includes two Docker Compose files for different use cases:

File Use case Requirement
docker-compose.ghcr.yml End users — pulls pre-built images from ghcr.io Docker
docker-compose.yml Developers — builds images from local source code All source repositories present

The Payroll Console can be run as a Docker container for automation and testing (see Running the Payroll Console below).

Prerequisites

  • Docker (includes Docker Compose)

The images are public on the GitHub Container Registry (ghcr.io) — no login or access token is required.

Image Platforms
ghcr.io/payroll-engine/payrollengine.backend linux/amd64, linux/arm64
ghcr.io/payroll-engine/payrollengine.webapp linux/amd64, linux/arm64
ghcr.io/payroll-engine/payrollengine.payrollconsole linux/amd64, linux/arm64
ghcr.io/payroll-engine/payrollengine.mcp.server linux/amd64, linux/arm64

The SQL Server image (mcr.microsoft.com/mssql/server) is available for linux/amd64 only. On arm64 hosts (e.g. Apple Silicon) it runs under emulation; the Payroll Engine images run natively.

Getting Started

The stack runs five services: SQL Server, two one-time setup containers (sql-copy extracts the database scripts, db-init creates or migrates the database), the Backend API, and the Web Application. The Payroll Console can be added for automation and testing.

1. Clone the Repository

The repository includes both a developer compose file (docker-compose.yml) and a ready-to-use file for pre-built images:

git clone https://github.com/Payroll-Engine/PayrollEngine.git
cd PayrollEngine

2. Environment Configuration

Create a file named .env in the repository root to set the database password:

# PayrollEngine Docker Stack Configuration
DB_PASSWORD=PayrollStrongPass789

Use alphanumeric characters only — special characters like !, @, # can cause authentication failures that appear as misleading "sqlcmd not found" errors.

The .env file is excluded from version control (.gitignore) and must be created manually — this is intentional to avoid storing passwords in the repository.

3. Docker Compose File

The repository includes docker-compose.ghcr.yml — a ready-to-use compose file that pulls pre-built images from ghcr.io. The docker-compose.yml is for local development builds and requires all source repositories to be present.

The sql-copy service extracts the database scripts from the Backend image into a shared volume. The db-init service then decides automatically: - New installation: Creates the database and runs ModelCreate.sql - Existing database: Runs ModelUpdate.sql (skips if already at target version)

As a safety net, the Backend verifies the database schema version on startup and refuses to start if the schema is older than the minimum version it supports.

4. Start the Stack

That's it. Steps 1–2 are all that's needed before starting the stack.

docker compose -f docker-compose.ghcr.yml up -d

This will pull the pre-built images from ghcr.io and start all services. On the first run, the database initialization takes approximately 30 seconds.

5. Accessing the Applications

Once the stack is running:

Service URL
Web Application http://localhost:8081
Backend API http://localhost:5001
Swagger UI http://localhost:5001/swagger
SQL Server localhost:1433 (user: sa, password: from .env)

Verify the SQL Server connection:

docker exec payroll-db /opt/mssql-tools18/bin/sqlcmd \
  -S localhost -U sa -P "YourPassword" -C -Q "SELECT @@VERSION"

Use the Payroll Console container to install examples and execute tests against the running Backend.

6. Stopping the Stack

Stop and remove the containers:

docker compose -f docker-compose.ghcr.yml down

Stop and also remove the database volume (all data):

docker compose -f docker-compose.ghcr.yml down -v

Using a Specific Version

By default, docker-compose.ghcr.yml uses the :latest tag. To pin a specific release version, replace the image tags:

  sql-copy:
    image: ghcr.io/payroll-engine/payrollengine.backend:1.1.0
    # ...
  backend-api:
    image: ghcr.io/payroll-engine/payrollengine.backend:1.1.0
    # ...
  webapp:
    image: ghcr.io/payroll-engine/payrollengine.webapp:1.1.0
    # ...

Pin sql-copy and backend-api to the same version — sql-copy provides the database scripts that match the Backend.

Available image tags are listed on the Releases page.

Updating to a New Version

  1. Update the image tags in docker-compose.ghcr.yml (or use :latest)
  2. Pull the new images and restart:
    docker compose -f docker-compose.ghcr.yml pull
    docker compose -f docker-compose.ghcr.yml up -d
    

The db-init service handles database migrations automatically. If the new Backend image includes a schema update, ModelUpdate.sql is executed before the Backend starts. If the database is already at the target version, the script does nothing.

If the Backend detects an unsupported schema version on startup, it will log an error and stop. Check the Release Notes for breaking changes.

Running the Backend Container Standalone

The Backend image contains no database and no connection string. Starting it without configuration — for example via Run in Docker Desktop — fails with:

STARTUP EXCEPTION: Missing database connection string.

To run the Backend against an existing database, pass the connection string as environment variable:

docker run -d --name payroll-backend -p 5001:8080 \
  -e ASPNETCORE_URLS="http://+:8080" \
  -e PayrollServerConfiguration__EnableSwagger="true" \
  -e ConnectionStrings__PayrollDatabaseConnection="Server=host.docker.internal;Database=PayrollEngine;User Id=sa;Password=...;TrustServerCertificate=True;" \
  ghcr.io/payroll-engine/payrollengine.backend:latest

For MySQL or PostgreSQL, additionally set the provider (see below):

  -e PayrollServerConfiguration__DbProvider="MySql" \

The database must already exist with the Payroll Engine schema. Use docker-compose.ghcr.yml for a complete setup including database initialization.

Running the Payroll Console

The Payroll Console is available as a Docker image for automation, testing, and data import tasks:

docker run --rm --network payroll-engine_default \
  -e PayrollApiConnection="BaseUrl=http://backend-api:8080; Port=8080;" \
  ghcr.io/payroll-engine/payrollengine.payrollconsole:latest \
  PayrollTest --testFile Tests/Test.All.pecmd

Alternative Databases

Besides SQL Server, the Backend supports MySQL 8.0+ (since v1.0, preview) and PostgreSQL 14+ (since v1.1). The provider is selected with PayrollServerConfiguration:DbProvider:

Provider DbProvider Connection string
SQL Server SqlServer (default) Server=localhost;Database=PayrollEngine;User Id=sa;Password=...;TrustServerCertificate=True;
MySQL MySql Server=localhost;Port=3306;Database=PayrollEngine;User=root;Password=...;CharSet=utf8mb4;
PostgreSQL Postgres Host=localhost;Port=5432;Database=PayrollEngine;Username=payroll;Password=...;

Backend Configuration

Set the database provider in appsettings.json:

"PayrollServerConfiguration": {
  "DbProvider": "MySql"
},
"ConnectionStrings": {
  "PayrollDatabaseConnection": "Server=localhost;Port=3306;Database=PayrollEngine;User=root;Password=...;CharSet=utf8mb4;"
}

In a container, use the environment variables PayrollServerConfiguration__DbProvider and ConnectionStrings__PayrollDatabaseConnection instead.

Docker Setup

Ready-to-use database containers with automatic schema initialization are included in the Backend repository:

Database Folder Instructions
MySQL Database/docker-mysql/ Database/docker-mysql/README.md — create and update scenario
PostgreSQL Database/docker-pg/ Database/docker-pg/README.md

These start the database only — run the Backend locally or as a standalone container against it.

Limitations

  • MySQL and PostgreSQL are not covered by the standard Docker stack (docker-compose.ghcr.yml)
  • The db-init container currently targets SQL Server only
  • PostgreSQL has no update script in v1.1 — databases are created with Create-Model.pg.sql
  • MySQL support is a preview feature; full production validation is ongoing

Next Steps