143 docs
Self-hosting

Quickstart: single-node

Bring up a production-shaped 143 instance on one Linux host with Docker Compose.

Single-node is the self-hosting quickstart. It is the smallest supported topology that still exercises the production runtime: the API and worker loops run in one MODE=all process, while Postgres, Redis, Caddy, frontend, Chrome, sandbox DNS, and Docker sandboxes run on the same host.

It is not high availability. Use it for small teams, evaluation, and low-volume installs where simple operations matter more than independent app, database, and worker failure domains.

What starts

  • caddy: public TLS reverse proxy for the app and preview wildcard.
  • frontend: Next.js production server.
  • api: Go API plus worker loops in MODE=all.
  • migrate: one-shot database migration job.
  • postgres: local source of truth.
  • redis: local cache, pub-sub, and worker wakeups.
  • chrome: headless browser for preview inspection.
  • sandbox-dns: DNS sidecar for gVisor sandboxes.
  • gvisor-check: preflight for the Docker runsc runtime.

Requirements

  • Linux host with Docker and Docker Compose v2.
  • DNS for DOMAIN and *.preview.DOMAIN pointing at the host.
  • Access to the runtime images in IMAGE_REGISTRY (ghcr.io/assembledhq by default). If those packages are private for your deployment, run docker login ghcr.io on the host or mirror the images and set IMAGE_REGISTRY.
  • Cloudflare DNS API token for the bundled wildcard certificate Caddyfile.
  • gVisor runsc installed and registered with Docker for production sandbox isolation.
  • Backups for Postgres and SINGLE_NODE_DATA_DIR (/var/lib/143 by default).

Start the instance

Check out the 143 repository on the Linux host and choose the release you want to run.
Authenticate to the image registry if required: docker login ghcr.io.
Copy .env.single-node.example to .env.single-node and fill in the required values.
Run sudo deploy/scripts/prepare-single-node.sh, then copy the printed DOCKER_GID into .env.single-node.
Run make single-node-up.
Verify service health before connecting real repositories.
cp .env.single-node.example .env.single-node
$EDITOR .env.single-node
sudo deploy/scripts/prepare-single-node.sh
make single-node-up

The host preparation script creates the Docker networks, sandbox resolver config, sandbox-auth socket directory, preview dependency cache directory, and the data directories under SINGLE_NODE_DATA_DIR. It reads SINGLE_NODE_DATA_DIR from .env.single-node and prints the host Docker socket group id required by DOCKER_GID.

Required env

Fill these groups in .env.single-node:

  • Runtime images: IMAGE_REGISTRY and IMAGE_TAG.
  • Public URLs: DOMAIN, BASE_URL, FRONTEND_URL, CORS_ALLOWED_ORIGINS, and PREVIEW_ORIGIN_TEMPLATE.
  • TLS DNS: CLOUDFLARE_API_TOKEN, unless you replace the bundled Caddy setup.
  • Secrets: DB_PASSWORD, SESSION_SECRET, ENCRYPTION_MASTER_KEY, and CSRF_SIGNING_KEY.
  • GitHub OAuth and GitHub App values from GitHub App setup.
  • At least one provider key for platform LLM features, plus LLM_MODEL and PLATFORM_LLM_MODEL.
  • Worker capacity and sandbox settings: start with WORKER_PROCESS_COUNT=1 and WORKER_MAX_ACTIVE_SANDBOXES=1.
  • Storage: SINGLE_NODE_DATA_DIR defaults to /var/lib/143 and is also the default session-executor bind mount.

Keep SANDBOX_RUNTIME=runsc and SANDBOX_REQUIRE_GVISOR=true for production. Use runc only for trusted local smoke tests.

Verify

Check Compose state:

docker compose --env-file .env.single-node -f docker-compose.single-node.yml ps

Expected state after startup:

  • postgres, redis, sandbox-dns, api, and frontend are healthy.
  • migrate has exited 0.
  • gvisor-check has exited 0.
  • api logs include worker started and starting server.

Check the public frontend route and the API readiness endpoint inside the Compose network:

curl -fsS https://<domain>/healthz
docker compose --env-file .env.single-node -f docker-compose.single-node.yml exec api wget -qO- http://localhost:8080/readyz

Then run a low-risk repository session and confirm that 143 can clone, create a branch, produce a diff, and open a test PR.

GitHub URLs

Use these when creating the OAuth App and GitHub App:

  • OAuth callback: https://<domain>/api/v1/auth/github/callback
  • GitHub App setup URL: https://<domain>/settings/integrations/github/setup
  • Webhook URL: https://<domain>/api/v1/webhooks/github

Preview DNS must route *.preview.<domain> to the same host.

Capacity

The template starts at one worker loop and one active sandbox. Keep that default until you have real host metrics. Postgres, Redis, API traffic, previews, worker jobs, and sandboxed agent runs all compete for one machine's resources.

Scale to separate worker hosts once you need more than a few concurrent sandboxes or need deploys/restarts that do not interrupt all runtime capacity.

Stop or restart

Stop the stack without deleting the Postgres and Redis volumes:

make single-node-down

Start it again:

make single-node-up

Common blockers

  • pull access denied: authenticate to GHCR or set IMAGE_REGISTRY to a registry that contains the 143-server, 143-frontend, and 143-sandbox images.
  • runsc runtime not registered: install gVisor and confirm docker info lists runsc.
  • worker mode requires agent services: check GitHub App values, Docker socket access, sandbox health, and sandbox-auth directory permissions.
  • Preview URLs do not resolve: confirm *.preview.<domain> DNS and PREVIEW_ORIGIN_TEMPLATE.
  • Caddy cannot issue certificates: confirm the Cloudflare token can edit the DNS zone, or replace the bundled Caddy setup with your proxy.

Tradeoffs

  • The bundled Caddyfile assumes Cloudflare for wildcard preview certificates.
  • Local storage under SINGLE_NODE_DATA_DIR must be backed up with Postgres.
  • Multi-node deployments should use S3-compatible snapshot/upload storage instead of local disk.
  • SANDBOX_REQUIRE_DISK_QUOTA defaults to false for storage-driver compatibility; set it to true when Docker can enforce container rootfs size limits.
  • Single-node restarts drain or interrupt all workers and previews on that host.

Backups first

Before routing real repository work through a single-node install, test restoring the Postgres volume, SINGLE_NODE_DATA_DIR, and .env.single-node onto a fresh host.

On this page