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 inMODE=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 Dockerrunscruntime.
Requirements
- Linux host with Docker and Docker Compose v2.
- DNS for
DOMAINand*.preview.DOMAINpointing at the host. - Access to the runtime images in
IMAGE_REGISTRY(ghcr.io/assembledhqby default). If those packages are private for your deployment, rundocker login ghcr.ioon the host or mirror the images and setIMAGE_REGISTRY. - Cloudflare DNS API token for the bundled wildcard certificate Caddyfile.
- gVisor
runscinstalled and registered with Docker for production sandbox isolation. - Backups for Postgres and
SINGLE_NODE_DATA_DIR(/var/lib/143by default).
Start the instance
docker login ghcr.io..env.single-node.example to .env.single-node and fill in the required values.sudo deploy/scripts/prepare-single-node.sh, then copy the printed DOCKER_GID into .env.single-node.make single-node-up.cp .env.single-node.example .env.single-node
$EDITOR .env.single-node
sudo deploy/scripts/prepare-single-node.sh
make single-node-upThe 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_REGISTRYandIMAGE_TAG. - Public URLs:
DOMAIN,BASE_URL,FRONTEND_URL,CORS_ALLOWED_ORIGINS, andPREVIEW_ORIGIN_TEMPLATE. - TLS DNS:
CLOUDFLARE_API_TOKEN, unless you replace the bundled Caddy setup. - Secrets:
DB_PASSWORD,SESSION_SECRET,ENCRYPTION_MASTER_KEY, andCSRF_SIGNING_KEY. - GitHub OAuth and GitHub App values from GitHub App setup.
- At least one provider key for platform LLM features, plus
LLM_MODELandPLATFORM_LLM_MODEL. - Worker capacity and sandbox settings: start with
WORKER_PROCESS_COUNT=1andWORKER_MAX_ACTIVE_SANDBOXES=1. - Storage:
SINGLE_NODE_DATA_DIRdefaults to/var/lib/143and 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 psExpected state after startup:
postgres,redis,sandbox-dns,api, andfrontendare healthy.migratehas exited0.gvisor-checkhas exited0.apilogs includeworker startedandstarting 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/readyzThen 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-downStart it again:
make single-node-upCommon blockers
pull access denied: authenticate to GHCR or setIMAGE_REGISTRYto a registry that contains the143-server,143-frontend, and143-sandboximages.runsc runtime not registered: install gVisor and confirmdocker infolistsrunsc.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 andPREVIEW_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_DIRmust be backed up with Postgres. - Multi-node deployments should use S3-compatible snapshot/upload storage instead of local disk.
SANDBOX_REQUIRE_DISK_QUOTAdefaults tofalsefor storage-driver compatibility; set it totruewhen 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.