Skip to content

Deployment

There are two ways to run the SCF Controls Platform. This page covers both, then walks through a self-hosted install end to end.

Managed SaaSSelf-hosted (open source)
You runNothing — we host itDocker Compose on your own host
AuthGoogle Sign-InAPI key (single-tenant) or Google OAuth
Evidence storageManaged cloud storageBundled MinIO (or your own AWS S3 / Azure Blob)
SCF cataloguePre-loadedYou import your own licensed SCF workbook
TenancyMulti-tenant, isolatedSingle-tenant per deployment
Best forTeams who want zero opsAir-gapped, on-prem, or evaluation installs
LicenceCommercial subscriptionSoftware under AGPL-3.0

The rest of this page is the self-hosted install.


The self-hosted stack is Docker-only: Postgres, the FastAPI backend, a Celery worker, the React frontend, a Redis broker, and a bundled MinIO object store all come up from a single docker compose up. No cloud account is required for a working evaluation.

  • Docker Engine 24+ and the Docker Compose v2 plugin (docker compose, not the legacy docker-compose).
  • Roughly 4 GB RAM and 5 GB disk free for the full stack.
  • Your SCF Excel workbook (.xlsx). The platform ships the importer, not SCF’s licensed content — see The SCF catalogue below.
  1. Clone and create your environment file. Every variable the stack needs has a documented default in .env.example:

    Terminal window
    git clone <your-clone-url> scf-controls-platform
    cd scf-controls-platform
    cp .env.example .env

    The shipped defaults boot the stack for local evaluation. Change every value marked REQUIRED (DB_PASSWORD, API_KEY) before exposing it to a network. See Configuration for the full variable reference.

  2. Start the stack:

    Terminal window
    docker compose up -d

    The backend runs database migrations (Alembic) automatically on first boot. You do not need to load the catalogue before starting — the next step does it from the browser.

  3. Import your SCF catalogue from the browser (one-time). Open the app at http://localhost:5173 and sign in with the API key from your .env. On a fresh install the app detects the empty catalogue and shows a catalogue onboarding screen — upload your SCF .xlsx and it is extracted and seeded live, no shell step required. The importer auto-detects the SCF version from the workbook’s sheet names. When it finishes, your workspace loads.

ServiceURL / portPurpose
Frontendhttp://localhost:5173Web UI
Backend APIhttp://localhost:8000FastAPI
MinIO (S3 API)http://localhost:9000Evidence object store
MinIO consolehttp://localhost:9001Bucket admin (optional)
Postgreslocalhost:5432Database

The SCF catalogue (bring your own workbook)

Section titled “The SCF catalogue (bring your own workbook)”

The platform separates the SCF reference catalogue (controls, evidence requests, assessment objectives, framework mappings) from your application data (scoped controls, evidence, risks). The catalogue is read-only reference data you import once.

You have two ways to load it:

  1. In-app upload (default) — bring the stack up, open the app, and upload the workbook from the onboarding screen the app shows on a fresh install. Gated to single-tenant deployments (OSS_SINGLE_TENANT) and platform admins.
  2. CLI importer (headless) — run docker compose --profile init run --rm catalog-importer before first boot, reading ./catalog-source/scf.xlsx (override with SCF_XLSX). Useful for scripted or air-gapped installs.

The importer is version-agnostic: it detects SCF <year>.<n> from the sheet names, so 2025.4, 2026.x, and future releases import with no code change. Set CATALOG_VERSION in .env to match the workbook you imported so the /version endpoint reports it correctly.


By default the stack uses the bundled MinIO container (S3-compatible), so evidence uploads work out of the box with no cloud account. You can point it at real cloud storage instead.

No action needed. docker-compose.yml ships a minio service and a one-shot minio-init that creates the evidence bucket on first boot. The relevant defaults in .env:

Terminal window
AWS_ENDPOINT_URL=http://minio:9000 # internal endpoint (backend/worker)
EVIDENCE_PUBLIC_ENDPOINT=http://localhost:9000 # browser-facing presigned URLs
EVIDENCE_BUCKET=evidence
MINIO_ROOT_USER=minioadmin
MINIO_ROOT_PASSWORD=changeme-minio-password # change for anything beyond local eval

A self-hosted deployment is single-tenant: one organisation, with the master API_KEY acting as its admin. This is controlled by OSS_SINGLE_TENANT:

Terminal window
OSS_SINGLE_TENANT=1

The stack also ships ENVIRONMENT=production by default so a default deploy is safe. Only set ENVIRONMENT=development on a trusted local machine — it enables verbose error detail and backend auto-reload, and must never be used on a network-exposed host.


Pull the latest images/code, then bring the stack back up — migrations run automatically on boot:

Terminal window
git pull
docker compose pull
docker compose up -d

Database schema changes are handled by Alembic during backend startup; the catalogue is re-seeded from the JSON already present. You do not need to re-run the importer unless you are loading a new SCF workbook version.


The hosted SaaS runs on AWS (ECS, RDS, CloudFront, S3) provisioned with Terraform. That path is for the platform operator and is not part of the open-source self-hosted release. Self-hosters should use the Docker Compose stack above.


See Troubleshooting for the full list. The most common first-deploy issues:

SymptomCauseFix
App loads but everything is emptyCatalogue not imported yetUpload your SCF workbook from the onboarding screen the app shows, or run the headless importer
docker compose up warns about unset variables.env missingcp .env.example .env first
Evidence upload failsStorage misconfiguredCheck the AWS_* / EVIDENCE_* block matches your chosen backend
500 on first write / risk register won’t loadPre-OSS_SINGLE_TENANT buildsUpdate to a current release and set OSS_SINGLE_TENANT=1