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:

  1. Artifact generation (default). With no registration flags, box deploy generates the files needed to run the box anywhere: a Dockerfile, a docker-compose.yml, a .env.deploy.example, a CI/CD workflow, Railway config-as-code, and an optional terraform/ starting point: all wired from the box’s box config service URLs.
  2. Domain registration (--register-domains). Reads the box.yml deploy 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 a dns.txt file.

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

OptionDescription
--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.
--forceOverwrite existing generated artifacts (otherwise existing files are skipped).

Domain registration

OptionDescription
--register-domainsRegister 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.
--verifySkip registration; check the linked status of each domain instead.
--removeTear 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:

TargetFiles
dockerfileDockerfile: one multi-stage image that builds both the engine and console.
composedocker-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.
terraformcloud-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).
railwayrailway.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/deploy to the control plane with Authorization: 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.txt file (and a legacy nameserver.txt) with the DNS instructions.

Backend URL resolution

The backend origin the domains route to is resolved in this order:

  1. An explicit --backend-url flag.
  2. backendUrl in box.yml.
  3. engineUrl in box.json (set via box 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-urlbackendUrl in box.yml.
  • --frontend-urlfrontendUrl in box.yml, plus the derived host is added to the box.yml domains list (if not already present) and written to storefrontDomain in box.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 (linked plus an optional detail).

Removal (--remove)

  • Skips registration.
  • Sends DELETE /boxes/deploy?name=<name> to the control plane with Authorization: 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 --remove

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:

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: true

See also