Install
Install
For a quick try on your laptop without domains or TLS, start with the Local quickstart (cmpatch selfhost local-eval).
To deploy with your own domains:
- A server you can reach over SSH
- Two hostnames you can add DNS records for — usually two subdomains of one
domain you already own, such as
updates.example.comandstorage-updates.example.com - A GitHub OAuth App for sign-in (a couple of clicks; the installer walks you through it)
- For production, a CDN in front of storage — Cloudflare or CloudFront; strongly recommended, the installer offers it as a step
cmpatch selfhost install handles the rest: it checks the server, offers to
install Docker, git, and curl if they are missing, walks you through DNS and
the OAuth app, and then runs the installer over SSH — OAuth wiring, Compose
stack, TLS certificates, secrets, Postgres, MinIO, and the dashboard. The
Docker bootstrap covers the distributions Docker's own install script supports
(Ubuntu, Debian, Fedora, RHEL, CentOS, Rocky, and their derivatives) plus
Amazon Linux 2023; on anything else, install Docker Engine with the Compose
plugin yourself and run the command again.
Choose storage
The default install stores artifacts in MinIO on the same host. You can choose Cloudflare R2, Amazon S3, or Google Cloud Storage instead. The installer can create those buckets or walk you through the console.
External storage uses two buckets: one public for downloads, one private for
_internal/ objects. Unattended flags, and how to reuse buckets after a failed
setup, are in the
CLI command reference.
Adapter env vars are in Infrastructure adapters.
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 go through a GitHub OAuth App. You do not need to create it in advance: the installer opens a pre-filled registration form at the right moment and checks the credentials with GitHub before it builds anything. Bitbucket Cloud OAuth is a supported alternative for on-server installs (see below).
The administrator's email 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
Install the CLI on your own machine (Node.js >=20) and run:
npm install -g @codemagic/patch-cli
cmpatch selfhost install
The command asks for everything it needs — the server, the two hostnames, the administrator email, the GitHub OAuth app — and waits at each step until it checks out, so there is nothing to prepare in advance. Building the images takes around twenty minutes on a cold cache. If the server is not reachable over SSH, see Troubleshooting.
You can also start from the app: cmpatch init in a React Native project
offers to install a server, signs you in, and links the project in one run.
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 to create the administrator account, then
connect your machine with cmpatch login and create apps and deployments (or
use the dashboard). See Web dashboard.
.env.selfhost on the server holds production secrets. Back it up and never commit or expose it.
On-server installs
Every answer has a flag, so the same install runs unattended. An unattended run skips the interactive DNS step, so add the two records and let them resolve first — otherwise the install fails when the server cannot obtain its certificates:
# the secret travels in the environment, never in a command line
export GITHUB_OAUTH_CLIENT_SECRET=<github_client_secret>
cmpatch selfhost install ubuntu@203.0.113.7 \
--non-interactive \
--api-domain updates.example.com \
--storage-domain storage-updates.example.com \
--email admin@example.com \
--github-oauth-client-id Iv1.xxxxxxxxxxxxxxxx \
--install-docker
The CLI is a wrapper around a script in the repository; you can run that script on the host directly instead. You then add the DNS records yourself, register the OAuth App by hand, and run the checks the guided installer would run for you — machine size, open ports, DNS, the OAuth pair:
| OAuth App setting | Value |
|---|---|
| Homepage URL | https://updates.example.com |
| Authorization callback URL | https://updates.example.com/auth/callback |
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>
To sign in with Bitbucket Cloud instead of (or as well as) GitHub, pass
--bitbucket-oauth-client-id / --bitbucket-oauth-client-secret; at least one
provider is required.
To run this same stack on your own machine over plain HTTP — a laptop
evaluation with real OAuth sign-in but no certificate, DNS, or open ports —
add --allow-http to the script. It serves the machine it runs on alone: the
server is http://localhost, downloads are http://localhost:9110, the OAuth
callback is http://localhost/auth/callback, and the app must allow cleartext
traffic to those URLs. Any other hostname or IP is refused with the flag,
because a server other machines reach needs the HTTPS install; for the same
reason cmpatch selfhost install, which installs over ssh, does not take it.
See the
full guide
for what changes.
Either way, the installer writes .env.selfhost with strong random secrets
(it refuses to overwrite an existing file), builds the server and Caddy images,
starts the Compose stack under project name codemagic-patch-selfhost, waits
for Caddy to obtain Let's Encrypt certificates (a --allow-http install
instead waits for the sites to answer over plain HTTP), and prepares the
single fixed default-team on first boot.
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 cmpatch selfhost backup --download and keep the copy somewhere other than the server. For backups, upgrades, and what to watch next, see Ongoing maintenance. Command reference: Operations.
CDN delivery
A CDN is optional for trying Patch, but for production we strongly recommend
one: without it every device downloads straight from the single storage host,
which absorbs all traffic and has no edge cache. Front the storage domain with
a CDN so artifacts and manifests are served from the edge and Patch can purge
stale manifests after releases.
cmpatch selfhost install offers this as a step: it lists Cloudflare when your
download domain is already on a Cloudflare account, and CloudFront always.
The guided steps cover token creation, the DNS proxy switch, the cache rule,
and — for CloudFront — the AWS Console walkthrough and the final DNS cutover,
including the checks that must pass before it. The reference walkthroughs are
Cloudflare setup and
CloudFront setup. The guided installer configures the
bundled Postgres/MinIO topology. CloudFront can also front external S3/GCS
storage, but that topology starts with the direct install.sh path in
Infrastructure adapters, then follows the
external-storage track in the CloudFront guide.
Prefer a sibling storage hostname (storage-updates.example.com rather than storage.updates.example.com): nested hostnames work, but on Cloudflare Free they need Advanced Certificate Manager (Universal SSL only covers *.example.com). Details: Cloudflare setup.