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.
Choose your deployment model
Section titled “Choose your deployment model”| Managed SaaS | Self-hosted (open source) | |
|---|---|---|
| You run | Nothing — we host it | Docker Compose on your own host |
| Auth | Google Sign-In | API key (single-tenant) or Google OAuth |
| Evidence storage | Managed cloud storage | Bundled MinIO (or your own AWS S3 / Azure Blob) |
| SCF catalogue | Pre-loaded | You import your own licensed SCF workbook |
| Tenancy | Multi-tenant, isolated | Single-tenant per deployment |
| Best for | Teams who want zero ops | Air-gapped, on-prem, or evaluation installs |
| Licence | Commercial subscription | Software under AGPL-3.0 |
The rest of this page is the self-hosted install.
Self-hosted with Docker Compose
Section titled “Self-hosted with Docker Compose”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.
Prerequisites
Section titled “Prerequisites”- Docker Engine 24+ and the Docker Compose v2 plugin (
docker compose, not the legacydocker-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.
Quick start
Section titled “Quick start”-
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-platformcd scf-controls-platformcp .env.example .envThe 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. -
Start the stack:
Terminal window docker compose up -dThe 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.
-
Import your SCF catalogue from the browser (one-time). Open the app at
http://localhost:5173and 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.xlsxand 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.
Service ports
Section titled “Service ports”| Service | URL / port | Purpose |
|---|---|---|
| Frontend | http://localhost:5173 | Web UI |
| Backend API | http://localhost:8000 | FastAPI |
| MinIO (S3 API) | http://localhost:9000 | Evidence object store |
| MinIO console | http://localhost:9001 | Bucket admin (optional) |
| Postgres | localhost:5432 | Database |
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:
- 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. - CLI importer (headless) — run
docker compose --profile init run --rm catalog-importerbefore first boot, reading./catalog-source/scf.xlsx(override withSCF_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.
Evidence storage
Section titled “Evidence storage”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:
AWS_ENDPOINT_URL=http://minio:9000 # internal endpoint (backend/worker)EVIDENCE_PUBLIC_ENDPOINT=http://localhost:9000 # browser-facing presigned URLsEVIDENCE_BUCKET=evidenceMINIO_ROOT_USER=minioadminMINIO_ROOT_PASSWORD=changeme-minio-password # change for anything beyond local evalUse a real S3 bucket by setting real credentials and blanking the MinIO endpoints (empty = talk to AWS S3 directly):
EVIDENCE_BUCKET=your-real-bucketAWS_ACCESS_KEY_ID=AKIA...AWS_SECRET_ACCESS_KEY=...AWS_DEFAULT_REGION=eu-west-1AWS_ENDPOINT_URL= # leave blankEVIDENCE_PUBLIC_ENDPOINT= # leave blankSet the two Azure values — they take priority over the S3 path:
AZURE_STORAGE_ACCOUNT_NAME=youraccountAZURE_STORAGE_ACCOUNT_KEY=...EVIDENCE_CONTAINER=evidenceSingle-tenant mode and security defaults
Section titled “Single-tenant mode and security defaults”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:
OSS_SINGLE_TENANT=1The 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.
Upgrading
Section titled “Upgrading”Pull the latest images/code, then bring the stack back up — migrations run automatically on boot:
git pulldocker compose pulldocker compose up -dDatabase 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.
Managed cloud (AWS) — reference
Section titled “Managed cloud (AWS) — reference”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.
Troubleshooting
Section titled “Troubleshooting”See Troubleshooting for the full list. The most common first-deploy issues:
| Symptom | Cause | Fix |
|---|---|---|
| App loads but everything is empty | Catalogue not imported yet | Upload your SCF workbook from the onboarding screen the app shows, or run the headless importer |
docker compose up warns about unset variables | .env missing | cp .env.example .env first |
| Evidence upload fails | Storage misconfigured | Check the AWS_* / EVIDENCE_* block matches your chosen backend |
| 500 on first write / risk register won’t load | Pre-OSS_SINGLE_TENANT builds | Update to a current release and set OSS_SINGLE_TENANT=1 |