Skip to content

The image and its commands

When you host SpeculaPro yourself, you receive one container image: ghcr.io/spalce/speculapro, for linux/amd64 and linux/arm64. Inside it is one program, speculapro, with the web app, the database migrations and the API documentation built in. You don’t receive the source code and you don’t build anything: SpeculaPro’s source repository is private.

Each release is signed and comes with a software bill of materials. Verify it before you deploy, and deploy it by its digest.

There are two packaged ways, and both start from the same image:

Use it for Page
Docker Compose One server: smaller institutions, pilots, test installations Docker Compose in production
Helm chart Kubernetes: any size, each role scaled on its own Kubernetes with Helm

Compose and Helm are conveniences, not requirements. The one image carries everything (every role, the web app, the migrations, the command-line tools), so it runs anywhere a container does:

  • Any container runtime: Docker, Podman, containerd, Nomad, a cloud container service.
  • Plain Kubernetes manifests, for example with kustomize, if your platform team doesn’t use Helm.

In every case the recipe is the same: give each container its settings as environment variables (configuration reference), and say which roles it runs with SP_ROLES (or --role). One container with SP_ROLES=all is a complete installation; several containers of the same image with different SP_ROLES split the work, exactly as the Helm chart does. Run migrate up and topics once before the first start and migrate up before each upgrade.

The two packaged ways are the ones SpeculaPro maintains and checks; with your own manifests, the production checklist and the probes in the table below are what to carry over.

The image
Base gcr.io/distroless/static-debian12:nonroot: no shell, no package manager, nothing but the binary and the certificate authorities it needs
User Runs as the unprivileged nonroot user, never as root
Contents One static speculapro binary with the web app, migrations and API docs built in, compiled with Go 1.27.2
Ports 8080 for the API and web app; 9090 for Prometheus metrics, which you keep on your internal network
Default command speculapro run, so with no arguments it starts the roles in SP_ROLES
Probes Liveness GET /healthz. Readiness GET /readyz?role=<roles> on port 8080 for processes serving HTTP, or GET /readyz on the metrics port 9090 for background roles. See Health checks

Run any command by putting it after the image name. Settings come from the environment, never from the image:

Terminal window
IMAGE=ghcr.io/spalce/speculapro@sha256:<digest> # the digest you verified
# Apply migrations (as speculapro_owner), create topics, then start three roles
docker run --rm --env-file .env -e SP_DB_URL=<owner connection> "$IMAGE" migrate up
docker run --rm --env-file .env "$IMAGE" topics
docker run -d --env-file .env -p 8080:8080 "$IMAGE" run --role=api,ingest,decision

A new installation has no workspace and no users, so there is nobody who could sign in and create one in the web app. The first workspace and its first administrator are therefore created from the command line, with speculapro tenant create:

Terminal window
docker run --rm --env-file .env "$IMAGE" tenant create \
--slug acme --name "Acme Pay" --kind psp --country GH --currency GHS \
--admin-email [email protected] --admin-name "Ada Mensah"

It prints the administrator’s temporary password once; it works for 72 hours and must be changed at first sign-in. The packaged ways do this step for you: the Compose first-run script takes the workspace’s details, and the Helm chart has a bootstrap job. Every option of the command is listed under How to create your first workspace.

Command What it does
speculapro run [--role=…] Starts the application. See roles
speculapro migrate up Applies pending database migrations
speculapro migrate down Rolls back the most recent migration
speculapro migrate status Lists every migration and whether it is applied
speculapro topics Creates missing Kafka topics
speculapro tenant create … Creates a workspace and its first administrator. See Quickstart
speculapro tenant reset-password --slug … --email … Issues a new 72-hour temporary password for one person, e.g. when the only administrator can’t sign in. See Quickstart
speculapro tenant offboard --slug … --out <dir> --operator <name> --confirm <slug> [--export-only] Exports a workspace’s reports and filed goAML files with a checksum manifest, records it in the audit log, then deletes the workspace. Run with the schema owner’s SP_DB_URL. See Offboarding a workspace
speculapro keys generate Prints a fresh set of encryption keys. See Encryption keys
speculapro license fingerprint | status | install <file> | usage-report [--from YYYY-MM] [--to YYYY-MM] [--out <file>] Shows the installation fingerprint or the licence state, installs a licence, or writes a signed usage report. See Licensing
speculapro packs verify <bundle> Checks a signed rule-pack bundle and shows what it contains, without installing it
speculapro packs install <bundle> --workspace <slug> --as <email> [--force] Installs a signed rule-pack bundle in a workspace. See Signed rule-pack updates
speculapro healthcheck [--url …] Exits with 0 if the URL (default http://127.0.0.1:9090/readyz, the metrics port’s readiness check for background roles) answers with a 2xx status. For container health checks, since the image has no curl; processes serving HTTP pass --url http://127.0.0.1:8080/readyz?role=…
speculapro version Prints the version and commit

Every command reads its settings from environment variables. See the configuration reference.

Format Status
Container image ghcr.io/spalce/speculapro, for linux/amd64 and linux/arm64, signed, with an SBOM. Published by the release process below on every version tag; no release has been published yet
Docker Compose for production Available: the compose/production deployment files. See Docker Compose in production
Helm chart for Kubernetes Available: packaged with each release, versioned to match. See Kubernetes with Helm

A release is made by pushing a version tag such as v1.2.3. The release process then, with no manual steps:

  1. builds the image for linux/amd64 and linux/arm64 and publishes it to ghcr.io/spalce/speculapro, with build provenance;
  2. produces a software bill of materials (SBOM) in SPDX format, with syft;
  3. signs the image and attaches the SBOM as a signed attestation, with cosign, keylessly: the signature is tied to the release workflow’s identity and recorded in the public Sigstore transparency log;
  4. packages the Helm chart, versioned to match;
  5. publishes a GitHub release with the SBOM, the chart, an offline bundle of the signed image and the image digest.

How to check all of this before you deploy: Verifying releases. This process is in place but hasn’t published a release yet.