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_eventis 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:
| Setting | Value |
|---|---|
| Homepage URL | https://updates.example.com |
| Authorization callback URL | https://updates.example.com/auth/callback |
| Client ID | e.g. Iv1.xxxxxxxxxxxxxxxx |
| Client Secret | generated on the same app |
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.
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.selfhostwith 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
/healthand storage health, and - prepares the single fixed
default-teamon 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.
.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
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.
Cloudflare (optional but recommended)
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.
Nested storage hostnames work, but on Cloudflare Free they need Advanced Certificate Manager (Universal SSL only covers *.example.com). Details: Cloudflare setup.