Your first deploy
This is the whole path, once. Every command below either states that it contacts nothing, or is explicit about what it changes.
Before you start
Section titled “Before you start”You need:
- Onebox installed on your machine
- a repository containing the Compose file you already run
- one Linux server reachable over SSH, with Docker Engine, Compose, and Buildx available to that SSH account
- the server’s host key already recorded in
known_hosts
If the server has no public SSH port, name the bastion it is reached through — see Deploy through a jump host.
The first three steps are local and contact nothing. ob bootstrap is the first
command that changes the server. ob preflight then reads the provisioned host
without changing it or contacting a registry; the plan after it is also
read-only.
Deploy once
Section titled “Deploy once”-
Scaffold a project from the Compose file you already have.
Terminal window ob initThis writes
ob.ymland puts the published schema reference on its first line, so your editor offers completion, hover documentation and inline errors that match whatob validatewill say. -
Check the contract. Nothing is contacted.
Terminal window ob validateEvery failure carries a typed code, the path that produced it, and where possible the line and the command that resolves it:
✗ ob: "replicaz" is not a field of this contract (line 10); did you mean "replicas"?at: workloads.web.replicazcode: unknown_field -
Read back what Onebox understood.
Terminal window ob canonicalob previewob canonicalmarks each value with where it came from:# defaultfor one Onebox chose,# shorthandfor a top-level key it moved into a workload,# overridefor one an environment supplied.ob previewprints the Compose runtime it will generate. Read both before the first deploy — the difference between a value someone chose and one that appeared by itself is what a person checking a production configuration needs to see. -
Prepare the host. This contacts and changes the server.
Terminal window ob bootstrap -
Check host readiness. This contacts the server but changes nothing.
Terminal window ob preflightAmong the host, ownership, path, and collision checks, preflight verifies that Docker Buildx can format image-manifest digests. The capability probe reads local help output only, so it does not resolve an image or consume registry quota.
-
Review production without changing it.
Terminal window ob plan --out ob-plan.jsonThe plan is a mode-
0600, digest-protected executable envelope containing the typed operation graph and the exact config, Compose, host-state, image, rendered-Compose and payload bindings. It expires after 15 minutes, and any drift or local payload change requires a new plan.Each long-running workload has its own action in that graph:
retainleaves every healthy replica running when its complete effective runtime is unchanged;rollingorrecreateapplies the workload’s configured strategy when it changed;- an uncertain comparison uses the configured strategy and names the reason, such as a release-staged env file, secret, bind-mounted payload, adopted Compose service, missing legacy revision, replica drift or unhealthy state.
Retention is automatic and adds no configuration or selection flag. A retained workload receives no pull, signal, stop, rename or Compose command.
ob deploy --redeployremains the explicit exception: on a whole-application no-op it performs the fresh roll shown in the sealed plan. -
Record a short-lived local confirmation for that exact plan.
Terminal window ob approve --plan ob-plan.json --out ob-approval.jsonThe confirmation is mode-
0600and digest-bound to the plan, server, inputs, risk, operator label, and expiry. A changed or expired plan needs a new confirmation. It is tamper-evident local ceremony, not authenticated identity. -
Deploy with both artifacts.
Terminal window ob deploy --plan ob-plan.json --approval ob-approval.jsonA successful deploy ends by naming the release that is serving and the one it superseded:
Terminal window staged r-0042rolling shop-web-1 … healthyrolling shop-web-2 … healthyretain shop-worker · runtime unchangedverified checks/url 200 · X-App-Ready: yesserving r-0042 · r-0041 supersededRead the observed state back once more:
Terminal window ob statusStatus exits non-zero if the host diverges from the active release.
What you now have on the host
Section titled “What you now have on the host”Directory/var/lib/onebox/app/
Directoryreleases/
Directory20260808T101500Z/ the release just deployed
- …
Directory20260807T093000Z/ retained for rollback
- …
- current the symlink the runtime follows
- journal append-only operation record
Directoryservices/ supporting services, outside every release
- …
Container and volume names are derived and stable. Workload containers are
shop-web-1 and shop-web-2; the managed database is onebox-postgres and the
host proxy is onebox-proxy. Persistent and provider resources include
onebox_postgres_data, onebox_services for the service network, and onebox-ingress for
the host proxy network. Once a volume exists, its name cannot change without
moving data.
Why plan and local confirmation are separate
Section titled “Why plan and local confirmation are separate”The split creates a deliberate review ceremony and binds the answer to one exact
sealed plan. ob approve records a short-lived local confirmation whose digest
detects modification; it is not authenticated identity or proof that the actor
requesting the change was technically unable to create it. Environments that
need independent authorization require a future external provider, not a local
checksum artifact.
For automation, plan and deploy accept structured output, and ob approve sits
between them:
ob plan --output json --out ob-plan.jsonecho y | ob approve --plan ob-plan.json --out ob-approval.jsonob deploy --output ndjson --plan ob-plan.json --approval ob-approval.jsonob approve always prompts and there is no flag to skip it. A routine plan asks
yes or no; one that touches data — a migration, a destructive job, or an
unknown data effect — asks for the plan’s identity to be typed back: the release
ID for a deploy, the job name for a job run. It reads the answer from stdin
without checking for a terminal, so a pipeline supplies y, or that identity
for the stronger ceremony. Anything else records nothing and exits cancelled.
A JSON deploy buffers ordered operation events and its result into one envelope. NDJSON streams event records and a terminal result or error record. Diagnostics stay on stderr, so the structured stream is never polluted.
If something goes wrong
Section titled “If something goes wrong”ob status # non-zero on divergenceob resume # finish an interrupted deployob abort # revert an interrupted deployob rollback # activate the previous releaseSee Roll back a release.