Skip to main content

Install

Install

For a quick try on your laptop without domains or TLS, start with the Local quickstart (./scripts/local-eval/up.sh).

To deploy with your own domains:

  • A GitHub OAuth App for sign-in (a couple of clicks; you pass the ID and secret to the installer)
  • Two domains with DNS pointed at your host
  • Running the install script
  • (Recommended) Fronting storage with Cloudflare

The installer handles the rest: OAuth wiring, Compose stack, TLS certificates, secrets, Postgres, MinIO, and the dashboard.

Machine size

The default Compose install runs Caddy, the API and release worker, Postgres, and MinIO on one host. You need Docker + Docker Compose v2, with ports 80 and 443 open.

  • RAM: 2 GB is enough for typical use. Prefer 4 GB for large or overlapping releases, or a long on-box history of artifacts and metrics.
  • CPU: 1 vCPU is enough for typical use.
  • Disk: tens of GB is fine to start. Object storage grows with retained releases; Postgres grows with device metrics (metric_event is not auto-pruned).

GitHub OAuth App

Dashboard and CLI sign-in use a GitHub OAuth App (cmpatch login signs in through the browser via the dashboard, so no extra app settings are needed for the CLI). Register a new OAuth App (or manage existing ones under OAuth Apps) and use:

SettingValue
Homepage URLhttps://updates.example.com
Authorization callback URLhttps://updates.example.com/auth/callback
Client IDe.g. Iv1.xxxxxxxxxxxxxxxx
Client Secretgenerated on the same app
Bitbucket instead of GitHub

GitHub is not mandatory — Bitbucket Cloud OAuth is a fully supported alternative. Register an OAuth consumer in Bitbucket and pass --bitbucket-oauth-client-id / --bitbucket-oauth-client-secret to the installer (with or without the GitHub flags). At least one provider is required.

info

The first admin's email (--email below) must exactly match the verified primary email on their GitHub (or Bitbucket) account. The default registration mode is invite_only, so the very first sign-in is rejected if it doesn't match.

Run the installer

Clone codemagic-patch onto the host and run the installer:

git clone https://github.com/codemagic-ci-cd/codemagic-patch.git
cd codemagic-patch

scripts/selfhost/install.sh \
--api-domain updates.example.com \
--storage-domain storage.updates.example.com \
--email admin@example.com \
--github-oauth-client-id Iv1.xxxxxxxxxxxxxxxx \
--github-oauth-client-secret <github_client_secret>

The installer:

  • writes .env.selfhost with strong random secrets for Postgres, MinIO, the worker, and OAuth (it refuses to overwrite an existing file),
  • builds the server and Caddy (dashboard) images,
  • starts the Compose stack under project name codemagic-patch-selfhost,
  • waits for Caddy to obtain Let's Encrypt certificates (1–2 min) by polling /health and storage health, and
  • prepares the single fixed default-team on first boot.

When it finishes you'll have:

Dashboard: https://updates.example.com/
API URL: https://updates.example.com (app config: CodemagicPatchApiUrl)
Download base: https://storage.updates.example.com/codemagic-patch (app config: CodemagicPatchDownloadBaseUrl)

Sign in to the dashboard with GitHub, then create apps and deployments (or use the CLI). See Web dashboard.

warning

.env.selfhost holds production secrets. Back it up and never commit or expose it.

Verify

curl -fsS https://updates.example.com/health
curl -fsS https://storage.updates.example.com/minio/health/ready

# Unauthenticated smoke test
scripts/selfhost/smoke.sh

# After you create an API token, run the full publish smoke test
CODEMAGIC_PATCH_TOKEN=cm_pat_xxx scripts/selfhost/smoke.sh
tip

Before you rely on this stack in production, run scripts/selfhost/backup.sh and store a copy off the host. For backups, upgrades, and what to watch next, see Ongoing maintenance. Command reference: Operations.

For production, front the storage domain with Cloudflare CDN so artifacts and manifests are served from the edge and Patch can purge stale manifests after releases. Prepare the zone ID and cache-purge token, install with --cloudflare flags, then finish DNS proxying and Cache Rules after the stack is up. Full walkthrough: Cloudflare setup.

Free Cloudflare plans

Nested storage hostnames work, but on Cloudflare Free they need Advanced Certificate Manager (Universal SSL only covers *.example.com). Details: Cloudflare setup.