box deploy
Generate the box’s deployment artifacts: or register its public domains with the control plane’s storefront resolver.
box deploy [options]Synopsis
box deploy has two modes:
- Artifact generation (default). With no registration flags,
box deploygenerates the files needed to run the box anywhere: aDockerfile, adocker-compose.yml, a.env.deploy.example, a CI/CD workflow, Railway config-as-code, and an optionalterraform/starting point: all wired from the box’sbox configservice URLs. - Domain registration (
--register-domains). Reads thebox.ymldeploy manifest and registers its domains with the control plane so the shared storefront render knows which backend owns each public host. Prints per-domain routing and DNS instructions and writes adns.txtfile.
Registration mode also runs when you pass any of --verify, --remove,
--backend-url, --frontend-url, or --dashboard-url (those flags imply
--register-domains).
Options
Artifact generation
| Option | Description |
|---|---|
--pipe <targets> | Artifacts to generate: a comma/space list of dockerfile, compose, github, terraform, railway, or all. Defaults to the box’s deployPipe setting, else dockerfile, compose, github, railway. |
--force | Overwrite existing generated artifacts (otherwise existing files are skipped). |
Domain registration
| Option | Description |
|---|---|
--register-domains | Register this box’s box.yml domains with the control plane. |
--backend-url <url> | Backend (engine) URL to route the domains to. Overrides box.yml. Implies --register-domains. |
--frontend-url <url> | Storefront URL to route the domains to. Overrides box.yml. Implies --register-domains. |
--dashboard-url <origin> | Origin of the box dashboard allowed to embed the storefront preview. Overrides box.yml. Implies --register-domains. |
--verify | Skip registration; check the linked status of each domain instead. |
--remove | Tear down routing: deregister this box’s domains from the storefront resolver. |
Flag values override the corresponding fields in box.yml. Trailing slashes are
trimmed from all URL values. --verify and --remove are mutually exclusive
with each other and with registration.
Behavior
Artifact generation (default)
Generates the selected artifacts from the box’s box config
service URLs and writes them to the box root:
| Target | Files |
|---|---|
dockerfile | Dockerfile: one multi-stage image that builds both the engine and console. |
compose | docker-compose.yml (postgres + engine + console), .env.deploy.example, and a Caddyfile when public domains are configured (auto-HTTPS reverse proxy). |
github | .github/workflows/deploy.yml: build + optional deploy CI/CD. |
terraform | cloud-init.yaml (any-VPS server configuration), terraform/main.tf, and per-provider examples (terraform/digitalocean.tf.example, terraform/hetzner.tf.example, terraform/aws.tf.example). |
railway | railway.json (engine service) and railway.console.json (console service): Railway config-as-code. Both build from the shared Dockerfile and override the start command per service; point each Railway service’s Config-as-code Path at the matching file. |
Existing files are skipped unless --force is passed. After writing, the
command prints the next steps (cp .env.deploy.example .env, docker compose up -d --build, then box deploy --register-domains once the host is live).
Set the default target set once with
box config --deploy-pipe <targets> so plain
box deploy always generates the artifacts you want. --pipe overrides it
for a single run.
Registration (--register-domains)
- Sends
POST /boxes/deployto the control plane withAuthorization: Bearer <licenseKey>and a payload of{ name, backendUrl, frontendUrl?, dashboardUrl?, domains }. - Prints per-domain routing and the DNS records you must create.
- Writes a
dns.txtfile (and a legacynameserver.txt) with the DNS instructions.
Backend URL resolution
The backend origin the domains route to is resolved in this order:
- An explicit
--backend-urlflag. backendUrlinbox.yml.engineUrlinbox.json(set viabox config --engine-url).
The last keeps a single source of truth for the engine’s public origin: whatever
the box’s own console talks to is also what the control plane resolves the
storefront to. When the backend defaults from engineUrl, the command prints
backend defaulted from box config engineUrl → <url>. If none of the three is
set, registration fails with a clear error.
Persisted flags
After a successful registration, the flags you explicitly passed are written back into your config so later deploys don’t need them again:
--backend-url→backendUrlinbox.yml.--frontend-url→frontendUrlinbox.yml, plus the derived host is added to thebox.ymldomainslist (if not already present) and written tostorefrontDomaininbox.json.
Only flags you actually passed are persisted: omitting a flag never erases an
existing box.yml value. The YAML document model is used to update box.yml,
so your comments and formatting are preserved. The CLI prints which fields it
updated (for example, box.yml updated (backendUrl, frontendUrl)).
Consolidated DNS records
When several hosts share the same DNS target (for example, acme-bank.example
and *.acme-bank.example pointing at one CNAME value), the records are grouped
by type + value + ttl and printed once with every name that points at them,
instead of repeating the same target per host. The same consolidation is
applied to the dns.txt file and to the offered nameservers.
Verification (--verify)
- Skips registration.
- Calls
GET /boxes/deploy/status?name=<name>with the bearer license key. - Reports the linked status of each domain (
linkedplus an optionaldetail).
Removal (--remove)
- Skips registration.
- Sends
DELETE /boxes/deploy?name=<name>to the control plane withAuthorization: Bearer <licenseKey>. - The control plane detaches each registered host from the platform provider and
clears its resolver mapping, so those hosts stop routing to this box. The
response is
{ removed?: string[] }: the list of deregistered hosts. - Prints each deregistered host, then a summary
(
Removed: N domain(s) no longer route to this box.). - If no domains were registered, it warns
No domains were registered for this box; nothing to remove.and exits.
--remove only tears down storefront routing on the control plane. The DNS
records you created at your registrar are not touched: you can delete them
yourself once removal succeeds.
Registration requires an authenticated box and a backend URL. Provide
--backend-url, set backendUrl in box.yml, or set engineUrl via
box config --engine-url: otherwise the command cannot register your domains.
Examples
# Generate deploy artifacts (default set: Dockerfile, compose, GitHub Actions)
box deploy
# Generate a specific set, overwriting existing files
box deploy --pipe dockerfile,compose,terraform --force
# Register domains: backend URL defaults from `box config --engine-url`
box deploy --register-domains
# Register with an explicit backend, plus frontend and dashboard origins
box deploy \
--backend-url https://api.acme-bank.example \
--frontend-url https://shop.acme-bank.example \
--dashboard-url https://admin.acme-bank.example
# Verify DNS / linkage after records propagate
box deploy --verify
# Tear down routing: deregister this box's domains from the resolver
box deploy --removeRelated configuration
Service URLs and the default artifact set come from
box.json (via
box config); the domains and public URLs registration
uses come from box.yml:
backendUrl: https://api.acme-bank.example
frontendUrl: https://shop.acme-bank.example
dashboardUrl: https://admin.acme-bank.example
domains:
- host: acme-bank.example
primary: true
- host: '*.acme-bank.example'
wildcard: trueSee also
- Live Box upgrades: update, rebuild, migrate, verify, and roll back a running Box.
box config: set the service URLs and default deploy pipe.box.ymlschema.- Concepts → DNS & routing.
- Control plane endpoints.