Project file
onebox.run/v1 is the contract for one application on one host. It goes in
ob.yml at the root of your repository. ob.yaml is accepted automatically
when ob.yml is absent, and -c accepts either spelling or any explicit path.
Only api_version and environments are required — plus at least one workload,
from a workloads block or the top-level shorthand.
Start with the schema reference so your editor can help while you type:
# yaml-language-server: $schema=https://raw.githubusercontent.com/labstack/onebox/main/docs/onebox.run-v1.schema.jsonapi_version: onebox.run/v1ob schema --out onebox.schema.json writes a local copy, and ob init puts the
published reference on the first line of a scaffolded project.
The block map
Section titled “The block map”| Block | What it says | Fields |
|---|---|---|
app | The application’s name. Every derived name carries it. | Top level |
environments | Where it runs, and the policy that governs deploying there. | environments |
workloads | The containers that are yours. | workloads |
services | The supporting services Onebox runs for you. | services |
deployment | Release order, retention, migration policy. | deployment |
proxy | Who runs the proxy and what routes. | proxy |
runtime | Environment files and local environment-file checks. | runtime |
hooks | Commands at lifecycle seams. | hooks |
verifications | What must be true for a release to activate. | verifications |
external_services | Dependencies operated outside Onebox, and how a workload reaches them. | external_services |
backup_targets | Off-host repositories the proposed protection layer would write to. | backup_targets |
registries notifications observability | Named maps. | registries · notifications · observability |
external_services and backup_targets are published in the JSON Schema and
accepted by ob validate, but the lifecycle behind them is not shipped:
declaring a backup target creates no repository and no schedule, and an external
service’s health probe never runs. See
Shipped vs proposed.
Any mapping also accepts x- keys. They are carried nowhere and never change the
generated runtime.
Shorthand
Section titled “Shorthand”A scalar form, once accepted, is accepted permanently. These are contract, not convenience that might be withdrawn.
| Written as | Means |
|---|---|
image: nginx | image: {reference: nginx} |
health: /healthz | health: {http: /healthz} |
server: root@203.0.113.10 | server: {user: root, host: 203.0.113.10} |
needs: [postgres] | needs: [{name: postgres}] |
services: {postgres: 17} | services: {postgres: {version: 17}} |
env_files: [.env] | env_files: [{file: .env}] |
hooks: {post_deploy: "echo hi"} | hooks: {post_deploy: {run: "echo hi"}} |
build: . | build: {context: .} |
Top-level workload shorthand
Section titled “Top-level workload shorthand”A single-workload project may write the workload’s own fields at the top level
instead of a workloads block: build, image, compose, domain, port,
health, routes.
Mixing the two is shorthand_and_workloads — it would be ambiguous which
workload the top-level fields describe. Shorthand also needs app to attach the
workload to (app_required).
Environment values: two rules
Section titled “Environment values: two rules”Which list a workload resolves. Exactly one, from the most specific declaration present — override, then workload, then environment, then project. Lists replace rather than extend.
What wins inside the container. Lowest first: a compose: workload’s own
env_file; the resolved env_files entries in order; managed-service connection
files; the service’s environment.
Full explanation, including why level four outranks the rest: Handle secrets.
What Onebox generates
Section titled “What Onebox generates”Names — application containers are uniformly numbered:
shop-web-1, shop-web-2, and shop-postgres-1. The managed proxy is
onebox-proxy. Persistent and provider names include ob_shop_postgres,
ob_shop_postgres_data, ob_shop (the service network), and ob-ingress.
These are contract: once a volume exists its name cannot change without moving
data. A foreign resource already holding a derived name is refused, not adopted.
Layout — /var/lib/ob/<app>/releases/<id>, plus current, journal, and
services. Configurable per environment with base_path.
The proxy — if anything is routed, Onebox runs Traefik and writes its static
configuration. Declare proxy.config to own that configuration instead.
Route middleware
Section titled “Route middleware”Attach dynamic proxy middleware to the exact route that needs it with an ordered, provider-qualified reference:
proxy: {config: traefik}
workloads: web: image: ghcr.io/acme/shop:1.4.0 routes: - domain: shop.example.com path: /admin port: 8080 middlewares: - admin-auth@file - secure-headers@fileThe definitions belong to the provider named by the suffix. For example,
admin-auth@file names http.middlewares.admin-auth in the dynamic Traefik
configuration supplied through proxy.config; that configuration must enable
the file provider. A Onebox-managed proxy therefore requires proxy.config
when a route names middleware. With proxy.managed: false, the operator-owned
proxy provides the referenced resources instead. Onebox preserves list order
when it attaches the chain to the generated router. HTTP and TCP routes both
support middleware references; the referenced middleware must match the
route’s protocol.
Evolution
Section titled “Evolution”api_version: onebox.run/v1 is stable. Within it:
- A field is added, never repurposed.
- A scalar form once accepted is accepted permanently.
- A default may be added; an existing default’s value does not change.
- A constraint is not tightened against a project that already loads.
The JSON Schema published by ob schema is generated from the same declarations
the loader enforces and is checked against the conformance corpus.