Skip to content

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.json
api_version: onebox.run/v1

ob schema --out onebox.schema.json writes a local copy, and ob init puts the published reference on the first line of a scaffolded project.

BlockWhat it saysFields
appThe application’s name. Every derived name carries it.Top level
environmentsWhere it runs, and the policy that governs deploying there.environments
workloadsThe containers that are yours.workloads
servicesThe supporting services Onebox runs for you.services
deploymentRelease order, retention, migration policy.deployment
proxyWho runs the proxy and what routes.proxy
runtimeEnvironment files and local environment-file checks.runtime
hooksCommands at lifecycle seams.hooks
verificationsWhat must be true for a release to activate.verifications
external_servicesDependencies operated outside Onebox, and how a workload reaches them.external_services
backup_targetsOff-host repositories the proposed protection layer would write to.backup_targets
registries notifications observabilityNamed 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.

A scalar form, once accepted, is accepted permanently. These are contract, not convenience that might be withdrawn.

Written asMeans
image: nginximage: {reference: nginx}
health: /healthzhealth: {http: /healthz}
server: [email protected]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: .}

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).

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.

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.

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@file

The 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.

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.