Deploy
Install with Docker Compose
Install camelAI on a single x86_64 Linux VM and verify builds, notebooks, and database queries.
This guide installs camelAI on an existing Linux VM. The default configuration uses bundled Pomerium, automatic TLS, local persistent volumes, and attached Docker containers for project builds, notebooks, and database queries.
Before you start
Complete the requirements in Self-host camelAI. In particular, install Docker Engine, Docker Compose v2, Git, Node.js 22, and Bun 1.3.14.
Prepare these values:
| Value | Example |
|---|---|
| camelAI hostname | camel.example.com |
| Pomerium authenticate hostname | authenticate.example.com |
| Deployed-app wildcard domain | apps.example.com |
| OIDC issuer URL | https://idp.example.com/application/o/camelai/ |
| OIDC client ID and secret | Values from your identity provider |
| AI provider API key | A supported provider key |
| DNS validation credential | Cloudflare API token or Route 53 access |
Register this callback URL in your OIDC application:
https://authenticate.example.com/oauth2/callbackSee Authentication and Pomerium for TLS, identity-provider, and external-proxy options.
Choose a release
Production installations should use a selfhost-v* release and all seven
digest-pinned camelAI images from that release's selfhost-release.json
manifest. The manifest also pins the Pomerium image tested with the release.
Do not mix images from different releases.
If the camelAI tags page does not
contain a selfhost-v* tag, only the source-build evaluation path below is
available. Do not treat a build from the moving main branch as an immutable
production release.
Download selfhost-release.json from the matching
camelAI GitHub Release. Release
assets are permanent and public; do not depend on the expiring Actions
artifact. For example:
RELEASE=selfhost-vX.Y.Z
curl --fail --location \
--output /secure/path/selfhost-release.json \
"https://github.com/qaml-ai/camelAI/releases/download/${RELEASE}/selfhost-release.json"For a release install, check out the matching tag:
git clone https://github.com/qaml-ai/camelAI.git
cd camelAI
git checkout --detach selfhost-vX.Y.Z
bun install --frozen-lockfile
bun run selfhost:initThe camelAI release images are public and can be pulled from GHCR without a GitHub account or package token.
Set SELFHOST_DEPLOYMENT_MODE=release in .env.selfhost, then copy all eight
digest-pinned image references from the manifest:
SELFHOST_DEPLOYMENT_MODE=release
SELFHOST_APP_IMAGE=ghcr.io/qaml-ai/camelai-selfhost-app@sha256:...
SELFHOST_LOCAL_ARTIFACTS_IMAGE=ghcr.io/qaml-ai/camelai-selfhost-local-artifacts@sha256:...
SELFHOST_PROJECT_BUILD_IMAGE=ghcr.io/qaml-ai/camelai-selfhost-project-build@sha256:...
SELFHOST_ANALYSIS_IMAGE=ghcr.io/qaml-ai/camelai-selfhost-analysis@sha256:...
SELFHOST_DB_QUERY_IMAGE=ghcr.io/qaml-ai/camelai-selfhost-db-query@sha256:...
SELFHOST_CONTAINER_EGRESS_IMAGE=ghcr.io/qaml-ai/camelai-selfhost-container-egress@sha256:...
SELFHOST_CADDY_IMAGE=ghcr.io/qaml-ai/camelai-selfhost-caddy@sha256:...
SELFHOST_POMERIUM_IMAGE=pomerium/pomerium@sha256:...Keep SELFHOST_CONTAINER_EGRESS_IMAGE set to the digest from the same
release manifest. Do not replace it with Cloudflare's stock
cloudflare/proxy-everything image. The camelAI image includes the Docker
bridge bypass required on affected hosts; the stock sidecar can leave
attached runtimes failing with Container failed to start.
If you are evaluating unreleased code, clone a tested commit and keep the
source mode generated by selfhost:init:
git clone https://github.com/qaml-ai/camelAI.git
cd camelAI
git checkout --detach TESTED_COMMIT_SHA
bun install --frozen-lockfile
bun run selfhost:initSource mode builds every image on the VM. It takes longer and needs more free disk space than a release install.
Configure camelAI
Edit .env.selfhost. selfhost:init generated the signing and encryption
secrets already. Do not replace them with shared development values.
Configure the public domains and bundled Pomerium:
SELFHOST_PUBLIC_BASE_URL=https://camel.example.com
SELFHOST_MAIN_HOSTNAME=camel.example.com
LOCAL_APP_VANITY_DOMAIN=apps.example.com
LOCAL_APP_IFRAME_DOMAIN=apps.example.com
SELFHOST_AUTH_MODE=bundled-pomerium
POMERIUM_AUTHENTICATE_URL=https://authenticate.example.com
POMERIUM_AUTHENTICATE_HOSTNAME=authenticate.example.com
POMERIUM_ISSUER=camel.example.com
POMERIUM_AUDIENCE=camel.example.com
POMERIUM_DEFAULT_ORG_NAME=Example Corp
POMERIUM_IDP_PROVIDER=oidc
POMERIUM_IDP_PROVIDER_URL=https://idp.example.com/application/o/camelai/
POMERIUM_IDP_CLIENT_ID=camelai
POMERIUM_IDP_CLIENT_SECRET=replace-with-your-client-secretLOCAL_APP_VANITY_DOMAIN and LOCAL_APP_IFRAME_DOMAIN contain the app base
domain without a leading *.. With the values above, a deployed app is
served at https://APP_NAME.apps.example.com—not at
APP_NAME.camel.example.com or directly at apps.example.com. Create
the *.apps.example.com DNS record and wildcard certificate described below.
Choose one AI provider:
camelAI uses a long-term Bedrock API key through the Bedrock Mantle compatibility endpoint. EC2 instance-profile or IMDS SigV4 model authentication is not supported by this deployment.
SELFHOST_AI_PROVIDER=bedrock
SELFHOST_AI_API_KEY=bedrock-api-key-...
SELFHOST_AI_AWS_REGION=us-east-1SELFHOST_AI_AWS_REGION is the preferred region. If Bedrock reports that a
selected model is unavailable there, camelAI automatically tries the other
supported regions for that model. Authentication and authorization errors
are not retried in another region.
Publish generated apps locally
Self-hosted camelAI publishes generated apps to its local worker registry and
serves them through the local dispatcher on your wildcard app domain. This is
automatic: do not configure CF_API_TOKEN, CF_ACCOUNT_ID, or
CF_DISPATCH_NAMESPACE for app deployment. The Compose stack fixes the latter
two values to the internal self-host mode, so app deployment never calls the
Cloudflare Workers API.
SELFHOST_TLS_CLOUDFLARE_API_TOKEN is unrelated to app deployment. When you
select Cloudflare DNS for automatic TLS, only Caddy uses that scoped token for
ACME DNS validation and certificate renewal. It can be omitted when you use
Route 53, provided certificates, or an existing TLS proxy.
Choose whether deployed apps can use connections
By default, an app deployed from a workspace can receive an env.CONNECTIONS
service binding. The binding lets that app list and call the workspace's
configured connections. Connection credentials stay inside camelAI, but data
returned by a connection can enter the deployed app.
For installations where connections should remain available to the coding
agent but must not be shared with deployed apps, add this to .env.selfhost:
CONNECTIONS_BINDING_ENABLED=falseThis control requires selfhost-v0.1.2 or later. Set it before the first
bun run selfhost:configure and bun run selfhost:up.
When disabled, deployed-app access through CONNECTIONS fails closed. The
connection catalog methods exposed through deployed-app ANALYSIS and
WAREHOUSE bindings also fail closed. Connections remain available to the
camelAI coding agent, js_exec, the Connections settings page, and other
control-plane workflows.
For an existing installation, change the value, run
bun run selfhost:configure, and restart with bun run selfhost:up. Existing
apps are blocked immediately by the runtime check. Redeploy them so their saved
worker configuration no longer contains the binding.
If the agent should build apps against approved internal APIs instead, add deployment-specific instructions with custom agent skills.
Configure TLS and DNS
Caddy is the Compose ingress service. It terminates TLS in automatic and
provided modes, or exposes a private HTTP origin in external mode. Pomerium
remains on the loopback-only 127.0.0.1:5444 upstream. Choose a certificate
mode:
SELFHOST_TLS_MODE=automatic
SELFHOST_TLS_DNS_PROVIDER=cloudflare
SELFHOST_TLS_ACME_EMAIL=platform-ops@example.com
SELFHOST_TLS_CLOUDFLARE_API_TOKEN=...Create a Cloudflare API token with Zone Read and DNS Edit on only this DNS zone. Caddy uses it for ACME DNS validation and automatic renewal, including the deployed-app wildcard.
Create DNS records that point all three host patterns to the VM:
camel.example.com A/AAAA <VM address>
authenticate.example.com A/AAAA <VM address>
*.apps.example.com A/AAAA <VM address>Validate and start
Generate the protected Pomerium configuration and check the host:
bun run selfhost:configure
bun run selfhost:doctorselfhost:doctor checks the CLI versions, Docker daemon, CPU and memory,
Docker socket access, domains, AI provider, authentication settings, Compose
configuration, volumes, local service state, and bidirectional sandbox storage
synchronization when the images are already local. Before first startup it may
report that configured images are not local yet and defer the storage smoke.
Start the stack:
bun run selfhost:upIn source mode, this command builds all seven camelAI images before starting.
Verify the installation
Check readiness:
curl --fail --silent http://127.0.0.1:3001/api/selfhost/health
bun run selfhost:doctorThen execute the storage check and all three attached runtimes:
bun --env-file=.env.selfhost run selfhost:container:smoke:mount
bun --env-file=.env.selfhost run selfhost:container:smoke:project
bun --env-file=.env.selfhost run selfhost:container:smoke:analysis
bun --env-file=.env.selfhost run selfhost:container:smoke:db-queryThese are functional tests. They verify bidirectional local R2/container synchronization, create a real project-build container, run a real Jupyter notebook, and load the database-query drivers, then remove the smoke containers.
Do not grant sandbox containers /dev/fuse, SYS_ADMIN, or an unconfined
AppArmor profile. selfhost-v0.1.4 and later use a FUSE-free synchronization
path for local R2 storage.
Open https://camel.example.com and sign in through your identity provider.
The wildcard app domain should not redirect to Pomerium because published
public apps use a separate unauthenticated proxy route.
The installation is ready when the health endpoint returns HTTP 200,
selfhost:doctor passes, all four runtime smokes pass, and an OIDC user can
open the camelAI control plane.
Continue with Operations to configure backups and learn the verified upgrade process.