Infrastructure
A self-hosted SecureBuild deployment needs a database (PostgreSQL), a worker process that runs the platform, the securebuild-app web UI (Next.js on Node.js), object storage for artifacts and feeds, an OCI registry for images, build capacity, and a public HTTP origin for Alpine packages (APK) plus signing keys. Exact field names live in the configuration reference.
Database
SecureBuild expects a PostgreSQL database. Configure the connection using db_uri (YAML) or DB_URI (environment variable):
db_uri: postgres://postgres:password@localhost:5432/securebuild?sslmode=disable
Run SchemaHero migrations before starting services. SecureBuild uses SchemaHero for declarative schema management. Example migration commands:
schemahero plan \ --driver postgres \ --spec-file db/schema/tables \ --out ./db/plan/plan.yaml \ --uri postgres://postgres:password@localhost:5432/securebuild \ --seed-data schemahero apply \ --driver postgres \ --ddl ./db/plan/plan.yaml \ --uri postgres://postgres:password@localhost:5432/securebuild
Worker
The worker is SecureBuild’s long-running Go backend. It loads settings from SECUREBUILD_CONFIG_SOURCE (see Self-hosted overview), connects to PostgreSQL, and processes the build queue: package and image builds, vulnerability scans, security feeds, and the rest of the pipeline listeners.
SECUREBUILD_CONFIG_SOURCE=/etc/securebuild/securebuild-config.yaml \
worker runsecurebuild-app (web UI)
securebuild-app is the SecureBuild dashboard. It lives under securebuild-app/ in the repository, runs on Node.js, and uses the same PostgreSQL database as the worker.
Build-time variables are the NEXT_PUBLIC_* names: set them when you build the Docker image or run npm run build. Run-time variables (for example DB_URI, HMAC_SECRET, OAuth secrets) are supplied when you start the container or node process—rebuild the image if you change NEXT_PUBLIC_*.
Production image (Docker)
The repo ships securebuild-app/Dockerfile.repldev. It installs dependencies, runs npm run build with your NEXT_PUBLIC_* build args, then packages a slim runtime that starts with node server.js on port 3000 (override with PORT).
docker build -f securebuild-app/Dockerfile.repldev \ --build-arg NEXT_PUBLIC_GITHUB_CLIENT_ID=your_oauth_app_id \ --build-arg NEXT_PUBLIC_GITHUB_REDIRECT_URI=https://app.example.com/auth/github \ --build-arg NEXT_PUBLIC_GITHUB_OAUTH_STATE=your_random_state \ --build-arg NEXT_PUBLIC_APK_REPOSITORY=https://apk.example.com \ -t securebuild-app:local \ securebuild-app
Run the image and pass server-side configuration as environment variables (adjust names and values to match your deployment; see the configuration reference for the full set):
docker run -d --name securebuild-app \ -p 3000:3000 \ -e NODE_ENV=production \ -e PORT=3000 \ -e DB_URI=postgres://postgres:password@db:5432/securebuild \ -e HMAC_SECRET=your_hmac_secret \ -e GITHUB_CLIENT_SECRET=your_oauth_app_secret \ -e PIPELINE_DIR=/path/to/save/pipelines \ -e APP_ORIGIN=https://app.example.com \ securebuild-app:local
Run from a source tree (no Docker)
Use Node.js 24+ (same major as the Dockerfile). From securebuild-app/:
- Export every
NEXT_PUBLIC_*value your deployment needs, thennpm installandnpm run build. - Lay out the standalone output like the Dockerfile: copy
publicinto.next/standalone/publicand.next/staticinto.next/standalone/.next/static. cd .next/standalone, set run-time env vars (DB_URI,HMAC_SECRET, etc.), then runnode server.js.
For day-to-day development only, npm run dev is enough; see the Development environment page.
Object storage (S3-compatible)
SecureBuild uses object storage to publish Alpine vulnerability feeds (secdb) and store build artifacts. The worker publishes compressed, versioned feed files that clients consume to check for known vulnerabilities in Alpine packages. Configure an S3-compatible service (Cloudflare R2, Amazon S3, MinIO, etc.) with endpoint, credentials, and bucket names.
APK repository
SecureBuild builds Alpine packages (APKs) and publishes them into your object storage (the same S3-compatible buckets you configure with r2_*). The APK HTTP proxy serves those packages from object storage: repository index, package blobs, and related paths. During image builds, apko and melange tools use the public base URL apk_repository. The proxy also exposes the signing public key at GET /key/<apk_public_key_name>.
Run the APK HTTP proxy as its own long-running process (same worker binary, separate from worker run):
SECUREBUILD_CONFIG_SOURCE=/etc/securebuild/securebuild-config.yaml \
worker apk-proxyAPK signing keys
The worker signs package indexes with an RSA key. Store the private key in apk_signing_key_data and the public key in apk_public_key_data, each as base64 of the full PEM file (including headers). Set apk_public_key_name to the filename segment clients use in the key URL (for example cve0-signing.rsa.pub). Prefer PKCS#8 for the private key (openssl genpkey).
Generate a key pair
1. Create a 4096-bit RSA private key (PKCS#8 PEM). Keep this file secret and out of version control.
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:4096 -out apk-signing.pem
2. Export the public key as PEM.
openssl pkey -in apk-signing.pem -pubout -out apk-signing.pub.pem
3. Base64-encode each PEM file on a single line (no wrapped lines inside the string you paste into config) and place in config:
openssl enc -base64 -A -in apk-signing.pub.pem -out apk-signing.pub.pem.b64 openssl enc -base64 -A -in apk-signing.pem -out apk-signing.pem.b64
Copy the contents of apk-signing.pub.pem.b64 to apk_public_key_data and apk-signing.pem.b64 to apk_signing_key_data. After decoding apk_public_key_data, the bytes served at /key/<apk_public_key_name> must match the public PEM file exactly.
OCI registry
The OCI registry is an external service you run or subscribe to separately—SecureBuild does not ship a registry. After builds, the worker pushes images and related artifacts to that registry using credentials you supply.
Images are addressed with a single prefix string, registry_image_prefix (host only or host with path segments). Authenticate with registry_username and registry_password (token or password, depending on the registry). Use a dedicated registry credential, not unrelated API tokens.
SecureBuild also includes an oci-proxy service you can deploy in front of your registry. It is read-only for clients: operators and end users can pull through a stable vanity hostname (your branded URL) while pushes still go to the configured registry. See the configuration reference for oci_image_prefix and oci-proxy settings.
Run the OCI proxy as its own long-running process (same worker binary, separate from worker run):
SECUREBUILD_CONFIG_SOURCE=/etc/securebuild/securebuild-config.yaml \
worker oci-proxyWhere builds run
build_backend selects how package and image builds execute:
- local — Builds run on the same machine as the worker (dev use only). If
build_backendis unset and remote VM API settings are empty, the worker defaults here. - static — Builds run over SSH on hosts listed in
static_vms(host, user, port, SSH private key path or inline key).
max_parallel_builds limits concurrent builds per machine (default 1).
