@serve.zone/onebox

Onebox is a self-hosted application platform for a single server. It combines Docker, CoreTraffic routing, a typed web control plane, app templates, platform services, and containerarchive-powered backups into one NodeNext TypeScript package and service.

Issue Reporting and Security

For reporting bugs, issues, or security vulnerabilities, please visit community.foss.global/. This is the central community hub for all issue reporting. Developers who sign and comply with our contribution agreement and go through identification can also get a code.foss.global/ account to submit Pull Requests directly.

What Onebox Does

Onebox turns a Linux host into a small PaaS that can run your own containers and curated app templates without a separate control plane. It is designed for the "one good server" use case: one machine, one local Docker runtime, one web dashboard, one operational surface.

  • Deploys Docker workloads from external images or Onebox App Store templates.
  • Uses the local Docker socket and creates the onebox-network network automatically.
  • Runs workloads as Docker Swarm services when Swarm is active, otherwise as standalone containers.
  • Starts a CoreTraffic-backed reverse proxy for HTTP/S routing and WebSocket traffic.
  • Serves the web UI and TypedRequest/TypedSocket API through OpsServer on port 3000 by default.
  • Reports every App Store-managed service's platform OIDC eligibility through getUsersAndAppRoles.response.platformOidcQualifications, including a stable qualification code/reason, declared roles, and an optional registration view.
  • Shows every App Store-managed service in Access, including the same stable qualification code/reason when platform OIDC is unavailable.
  • Exposes an admin-authenticated read-only MCP endpoint at /mcp for safe service, domain, and platform-service summaries.
  • Stores platform state in a local SmartDB database.
  • Provisions database and object-storage dependencies through one Corestore platform service. Database clients intentionally use the MongoDB wire protocol and standard MONGODB_* connection variables.
  • Tracks domains, Cloudflare DNS records, ACME certificates, service logs, metrics, backup schedules, and app template metadata.
  • Can sync routes and import certificates from an external dcrouter gateway when configured.

Architecture

browser / CLI
    |
    v
OpsServer :3000
  - bundled web UI
  - TypedRequest handlers
  - TypedSocket dashboard events
    |
    v
Onebox coordinator
  - SmartDB repositories
  - Docker manager
  - CoreTraffic route manager
  - DNS and SSL managers
  - platform service providers
  - app store manager
  - backup manager and scheduler
    |
    v
Docker host
  - onebox-network
  - CoreTraffic
  - user services
  - optional platform services

Onebox is the central class. It initializes the database, Docker, CoreTraffic, DNS, SSL, platform services, App Store, backup subsystem, optional external gateway integration, and the web/API server.

Installation

Install the latest released Linux binary:

curl -sSL 'https://code.foss.global/api/v1/repos/serve.zone/onebox/raw/install.sh?ref=main' | sudo bash

The installer downloads onebox-linux-x64 or onebox-linux-arm64 from the latest Gitea release, installs it under /opt/onebox, and links /usr/local/bin/onebox. Use --version vX.Y.Z to pin a release, --install-dir /path to change the target directory, or --source to clone the tag and build the NodeNext package locally.

curl -sSL 'https://code.foss.global/api/v1/repos/serve.zone/onebox/raw/install.sh?ref=main' | sudo bash -s -- --source

For source checkouts, install dependencies and build directly:

pnpm install
pnpm run build
node ./cli.js --help

This repository currently marks the npm package as private; use the installer or a source checkout until public npm release packaging is enabled.

Quick Start

Run a foreground development instance:

onebox server --ephemeral

Open the dashboard:

http://localhost:3000

On the first browser visit, Onebox asks you to create the administrator passkey. Enter the short-lived bootstrap code printed in the local Onebox service logs, then complete the browser passkey prompt. The code authorizes first-time enrollment only; Onebox never accepts a human password.

Production passkeys require a stable HTTPS hostname. While the Onebox coordinator is running, persist it from another terminal with onebox config set adminUiDomain onebox.example.com, then restart Onebox before opening the production UI and enrolling the passkey.

ONEBOX_ADMIN_UI_DOMAIN=onebox.example.com is an alternative only when added to the Onebox systemd service environment; exporting it in an interactive shell does not update the generated unit. After enrollment, the hostname is pinned to the passkey relying party.

If every passkey for the configured administrator is lost, use local host access to reset enrollment:

sudo onebox systemd stop
sudo onebox auth reset-passkeys --confirm
sudo onebox systemd start
sudo onebox systemd logs

The reset invalidates every passkey and session for the configured administrator. It never enables password authentication. The production database defaults to /var/lib/onebox/.nogit/smartdb; use --database-path only for a nonstandard installation.

Deploy a simple service:

onebox service add web --image nginx:latest --domain web.example.com --port 80

For production, install and run the systemd service:

sudo onebox systemd enable
sudo onebox systemd start
sudo onebox systemd logs

The systemd unit runs onebox systemd start-daemon with /var/lib/onebox as its working directory. From source or foreground runs, the default SmartDB path is ./.nogit/smartdb relative to the current working directory.

CLI Reference

onebox <command> [options]

Core commands:

Command Purpose
selftest typed-rpc [--port <port>] Start and stop an isolated server to verify the packaged Typed RPC runtime graph.
server [--ephemeral] [--port <port>] [--monitor] Start the web/API server in the foreground.
service add <name> --image <image> [--domain <domain>] [--port <port>] [--env KEY=VALUE] Deploy a workload.
service list List known services.
service start <name> Start a stopped service.
service stop <name> Stop a running service.
service restart <name> Restart a service.
service remove <name> Remove a service and its route.
service logs <name> Print Docker logs for a service.
service stage-workloadinit-approval <name> --stdin Verify and deliver a new WorkloadInit approval or matching higher-generation revocation through the root-local coordinator.
service resume-workloadinit-approval <name> Resume a pending approval from its encrypted custody record.
service workloadinit-approval-status <name> Inspect current authority and pending delivery without printing the artifact.
appstore list List remote app templates.
appstore config <app-id> [--version <version>] Print app metadata and version config.
appstore install <app-id> --name <name> [--domain <domain>] [--version <version>] [--env KEY=VALUE] [--secrets-stdin] Install an app template. Pass declared secret overrides as one JSON object through stdin; --env accepts only non-secret values.
appstore upgrade <service-name> [--version <version>] Upgrade an App Store-managed service through the forward-only catalog gate.
registry add --url <url> --username <user> --password-stdin Store encrypted external registry credentials without exposing the password in process arguments.
registry remove --url <url> Remove registry credentials.
registry list List configured registries.
dns add <domain> Add a DNS record through the configured DNS manager.
dns sync Sync Cloudflare domains into Onebox.
ssl renew [domain] Renew one certificate or expiring certificates.
ssl list List stored certificates.
ssl force-renew <domain> Force certificate renewal for a domain.
proxy reload Reload routes and certificates into CoreTraffic.
proxy test Check reverse proxy state.
proxy status Print route/certificate counts and ports.
systemd enable Install and enable the systemd unit.
systemd disable Stop, disable, and remove the systemd unit.
systemd start Start Onebox through systemd.
systemd stop Stop Onebox through systemd.
systemd status Show service status.
systemd logs Follow journalctl logs.
config show Show stored settings with secret values masked.
config set <key> <value> Store a non-secret setting.
config set <secret-key> --stdin Store one bounded, single-line secret without placing it in process arguments.
backup create <service-name> Create a containerarchive backup through the running root-local coordinator.
backup list [service-name] List completed backups, optionally for one service.
cloudly-secrets-v2 <phase> <service-name> Inspect or operate the manually gated Cloudly Secrets v2 cutover, including WorkloadInit approval staging through bounded stdin.
auth reset-passkeys --confirm [--database-path <path>] Locally invalidate every passkey for the configured administrator and prepare fresh enrollment.
migration corestore-platform --status Read redacted cutover status without initializing or mutating SmartDB.
migration corestore-platform --approve --checkpoint-reference <reference> [--allow-empty-legacy-mongodb] Offline, resumable cutover from split legacy storage/database services to one Corestore owner.
migration rewind <data-version> Rewind the startup-migration data version, so the steps above it run again on the next boot.
status Print JSON system status.
upgrade Install the latest released package build. Requires root.

App Store upgrades fail closed unless the fresh index, app metadata, and target config agree. Semantic-version targets must be newer than the installed version. Branch and digest-tracked upgrades must use the fresh latest target. Onebox rejects stale operations when the service template or installed version changes before migration or apply.

Service deployment and replacement derive imageDigest from digest-pinned image references, including curated templates without resolver metadata. Explicit digests must be valid SHA256 values and match the pin. Replacing a mutable image or registry location, or forcing a mutable-image pull, clears the previous digest unless a new one is supplied; configuration-only updates preserve it. Failed replacements restore the prior image tuple.

An installed Cloudly WorkloadInit approval file mapping remains reserved after cutover retirement. Generic service updates and App Store upgrades must preserve its exact root-owned 0400 mapping; retiring temporary cutover metadata does not authorize removing or changing that runtime mount.

The legacy nginx command name is still accepted as an alias for proxy, but CoreTraffic is the active proxy backend.

Ongoing WorkloadInit approval ownership

Approval management is independent of the retired Cloudly cutover. Use the service commands above after retirement, with a digest-pinned service and the canonical root-owned 0400 approval mapping. The artifact is accepted only through bounded multiline stdin (500 KiB), never through command arguments or public service metadata.

sudo onebox service workloadinit-approval-status cloudly
sudo onebox service stage-workloadinit-approval cloudly --stdin < /root/workloadinit-approval.json
sudo onebox service resume-workloadinit-approval cloudly

Data migration 0.13.0 imports existing encrypted approval custody as an observed, unaccepted intent. It does not invent prior generations, history, acceptance, or runtime timestamps. Startup holds that workload at zero before routing, verifies the artifact, and performs a controlled runtime replacement. Only successful delivery creates one imported-current-state history event at the artifact's actual generation, explicitly recording that prior history is unavailable. Missing custody, an invalid mapping, or an unstable lifecycle blocks the migration; an unverifiable or revoked-only observation cannot establish the first accepted authority.

The owner atomically records its verified decision, encrypted service secret, and durable hold through SmartData transactions. It recreates the runtime using normal service lifecycle management, proves the exact image, secret mapping, and previous running/stopped state, then atomically appends immutable history, advances current authority, and releases the hold. Generic service mutations and Docker runtime mutation paths cannot bypass a pending hold. After a crash, startup discovers the uniquely owned runtime, repairs uncertain pointers, and proves zero replicas before reconciliation.

Exact accepted replay is a no-op. Any different artifact must advance the authority generation; an explicit revocation must name the current approval digest. A pending accepted operation must finish before another artifact can be staged. Resume after acceptance uses the persisted decision and does not reinterpret a registry outage as revocation. WorkloadInit 1.3 has no approval expiry. Invalid active-shaped artifacts never become revocation authorities.

Corestore platform cutover

Fresh database and object-storage resources are owned by one pinned Corestore service. SmartDB replaces the MongoDB backend while deliberately retaining the MongoDB wire protocol, port 27017, driver compatibility, and MONGODB_* workload variables. Onebox does not run a standalone MongoDB platform service for new deployments.

Legacy split ownership is converted only by the explicit migration in ts_migration/. Before running it, stop Onebox and create a separately stored, verified, restorable full checkpoint of the authoritative Corestore volume. Pass the operator checkpoint identifier unchanged on every retry:

sudo onebox systemd stop
sudo onebox migration corestore-platform --status
sudo onebox migration corestore-platform --approve \
  --checkpoint-reference <verified-checkpoint-reference>
sudo onebox migration corestore-platform --status
sudo onebox systemd start

The migration captures exact platform/resource ownership, fences affected workloads, renames the legacy object-storage owner to Corestore, provisions target resources, converts non-empty legacy databases with the pinned Corestore migration image, atomically replaces resource credentials, and restarts only workloads that were running before the cutover. Each phase is persisted and replay-safe. Database conversion temporarily leases the canonical onebox-mongodb name to the exact captured source container so its persisted replica-set identity remains valid. A stopped canonical-name holder is displaced and retained only when its exact command, networks, data volume, key-file bind, and mount topology prove it is a legacy twin of the captured source; running or unrelated owners fail closed without MongoDB mutation. The migration restores the exact captured recovery name before advancing the phase. Replaying an already-complete migration re-provisions and verifies the canonical credential tuple and reports repaired when persisted credentials or mapped service settings changed. A service held by a pending Cloudly Secrets v2 backup remains stopped; its environment and encrypted secret bundle are reconciled through the exact persisted backup fence without creating or starting a runtime. Other running services are restarted only when credential reconciliation changes their delivered settings. Recovery containers are renamed and retained; the command prints their names so an operator can remove them only after production verification and the agreed recovery window.

An empty legacy database is recorded as a persisted inspection proof and fails closed on the first run. After reviewing that proof, rerun the same command with --allow-empty-legacy-mongodb. This approval skips only databases re-inspected as empty; it does not disable verification for non-empty databases. Normal Onebox startup never performs this infrastructure cutover implicitly.

Startup migrations run through @push.rocks/smartmigration. Each is a step from one data version to the next, evaluated on boot; several run in sequence when an install fast-forwards across releases, and a boot already at the target costs one ledger read. The data version is its own series (0.0.0 upward), not the app version, because it describes how persisted data evolves rather than what was released. Adding a migration therefore means adding a step and moving the oneboxDataVersion constant to that step's toVersion; a release that changes no data changes neither.

The chain is matched strictly rather than bridged to the app version, deliberately. Bridging would stamp the ledger at the app version, and every later step in the 0.x series would then sit below the ledger where the planner can never select it — the migration would silently stop running on upgraded installs while still running on fresh ones.

Where the chain is still reversible, making a migration run again means rewinding past it:

sudo onebox migration rewind 0.6.0

Rewinding reverts every step above the target, not just one, and all of them run again on the next start. The command prints exactly which steps it reverted, and refuses a target that is not below the current data version. A reversible step here is an idempotent repair pass, so reverting one changes no data: it clears that step's completion record. This replaces deleting a …Complete metadata document by hand, which the ledger no longer honours.

A step may also be irreversible, meaning it is registered with no revert handler at all. A rewind whose path crosses one is refused before a single handler runs, so neither the ledger nor the data moves. cloudly-secrets-v2-cutover-retirement (0.11.0 → 0.12.0) is such a step: a retired cutover operation cannot be put back on a live service, and a rewind that reported success without restoring it would leave the ledger disagreeing with the data. Its archive record is the durable artifact instead.

Because that step sits at the top of the chain today, no rewind target below it is reachable: every path from the current data version crosses it. Steps added above 0.12.0 stay rewindable down to 0.12.0. This is deliberate. Forcing one of the earlier repair passes to run again is no longer an operator procedure; those passes are idempotent and already run on every boot that is behind them.

migration corestore-platform --status uses SmartDB's bounded Linux read-only management sidecar while Onebox is stopped. It reads only the exact migration-state string and does not start a database listener, initialize SmartData, run storage migrations, repair storage, or write files. The packaged SmartDB Rust sidecar must be available. Output is limited to the phase, SHA-256 hashes of the checkpoint reference and captured authority, resource/progress/recovery counts, and creation/update timestamps; checkpoint references, service and resource names, owner IDs, database names, and container identities are never emitted.

Cloudly Secrets v2 cutover

The following commands describe the historical cutover and require its unretired operation state. Ongoing approval changes after retirement use service stage-workloadinit-approval, not the cutover coordinator.

The Cloudly Secrets v2 transition is a manual, forward-only App Store cutover. The current exact schema-5 target is App Store version 1.1.6 from @serve.zone/appstore 2.5.0, requires Onebox 7.12.0 or newer, and uses the released multiarch Cloudly 24.1.0 digest sha256:7762dc2660d1392220334a44f361ebf50994af675d97fcf2da5b037e7dc37536. An unreleased checkout, another App Store version, or a mutable image tag is not a valid target. The App Store version declares the target image and application configuration; Onebox owns the secret-file identities for the keyring, authorization, rehearsal receipt, and WorkloadInit approval artifact.

Run each gate through the active root-local Onebox coordinator and inspect status between phases:

sudo onebox cloudly-secrets-v2 status cloudly
sudo onebox cloudly-secrets-v2 begin cloudly --target-version 1.1.6
sudo onebox cloudly-secrets-v2 hold cloudly
sudo onebox cloudly-secrets-v2 backup cloudly
sudo onebox cloudly-secrets-v2 verify-backup cloudly
sudo onebox cloudly-secrets-v2 stage-workloadinit-approval cloudly --stdin \
  < cloudly-workloadinit-approval.json
sudo onebox cloudly-secrets-v2 rehearse cloudly
sudo onebox cloudly-secrets-v2 prepare-keyring cloudly
sudo onebox cloudly-secrets-v2 apply-target cloudly
sudo onebox cloudly-secrets-v2 authorize cloudly
sudo onebox cloudly-secrets-v2 execute cloudly
sudo onebox cloudly-secrets-v2 verify cloudly
sudo onebox cloudly-secrets-v2 verify-restart cloudly
sudo onebox cloudly-secrets-v2 promote cloudly

Onebox 7.12.0 does not advance schema-1, schema-2, or schema-3 operations. Before installing it, use released Onebox 7.11.0 to bring such an operation to schema 4. A schema-1 or schema-2 operation must first complete its existing schema-3 advance and rehearsal path:

sudo onebox cloudly-secrets-v2 status cloudly
sudo onebox cloudly-secrets-v2 advance-target cloudly
sudo onebox cloudly-secrets-v2 status cloudly
sudo onebox cloudly-secrets-v2 rehearse cloudly
sudo onebox cloudly-secrets-v2 status cloudly

That advance pins App Store 2.3.0 and Cloudly 17.1.0, preserves its existing encrypted keyring when present, and appends immutable target, compatibility-fence, backup, keyring, runtime-hold, package, and target-advance evidence. It does not start Cloudly, regenerate an existing keyring, or alter the verified backup.

Still under Onebox 7.11.0, an eligible schema-3 operation against App Store 1.1.4 may move to schema 4 only from its exact backup-verified state with complete backup evidence, a persisted run-rehearsal intent and scratch lineage, and a proven zero-task runtime. Run the explicit supersession and stage the verified active authority, but do not start another rehearsal before upgrading Onebox:

sudo onebox cloudly-secrets-v2 status cloudly
sudo onebox cloudly-secrets-v2 advance-target cloudly
sudo onebox cloudly-secrets-v2 status cloudly
sudo onebox cloudly-secrets-v2 stage-workloadinit-approval cloudly --stdin \
  < cloudly-workloadinit-approval.json
sudo onebox cloudly-secrets-v2 status cloudly

The schema-4 supersession pins the published App Store 2.4.0 index, manifest, config, OCI index, and Cloudly 19.2.0 platform identities in one revision-fenced transition. It retains the complete canonical schema-3 predecessor in an immutable audit, preserves the verified backup and optional encrypted keyring digest, and clears the current run, scratch, and pending intent so predecessor scratch ownership remains historical and inert.

For a clean predecessor, after installing Onebox 7.12.0, move the eligible schema-4 operation to schema 5:

sudo onebox cloudly-secrets-v2 status cloudly
sudo onebox cloudly-secrets-v2 advance-target cloudly
sudo onebox cloudly-secrets-v2 status cloudly

Schema-4 to schema-5 supersession requires the exact backup-verified phase, a stopped zero-task runtime, complete verified backup evidence, active cryptographically reverified WorkloadInit authority matching encrypted storage, and no top-level production keyring checkpoint, authorization, approval, maintenance, production, completion, baseline, staging, or maintenance-container residue. Onebox 7.12.0 accepts only the normal predecessor, which has no current run, scratch, or pending intent.

The recovery path below is not present in Onebox 7.12.0; it requires a subsequent Onebox release containing the rehearsal-retirement implementation. That release also accepts one exact recovery shape for a superseded schema-4 operation: a persisted run-rehearsal intent and matching scratch allocation with complete provision, keyring, restore, digest, and Cloudly prepare checkpoints, but no inspection or later rehearsal checkpoint. advance-target first proves that exact allocation still owns one database, durably changes only the intent to retire-rehearsal-for-target-advance, performs idempotent allocation-fenced cleanup, and durably records exact absence before schema supersession. Startup and graceful shutdown may resume only cleanup after that retirement intent is durable; neither lifecycle path authorizes retirement or advances to schema 5.

The final schema transition atomically pins the published App Store 2.5.0 index, manifest, config, OCI index, and Cloudly 24.1.0 platform identities while preserving the complete schema-4 predecessor, including any retired rehearsal lineage, verified backup, authority history, and optional encrypted keyring digest in immutable schema-5 audit evidence. It does not start Cloudly, regenerate an existing keyring, clean any other predecessor resource, or alter the verified backup. Any other predecessor shape fails closed.

stage-workloadinit-approval accepts one active or revoked v1 artifact only through the root-local control socket and bounded multiline stdin. @serve.zone/workloadinit is the sole parser and verifier. Onebox persists a durable intent, performs a generation-fenced encrypted reserved-secret CAS with digest readback, then checkpoints immutable authority history. The target receives the artifact only at /run/secrets/cloudly-workloadinit-approval.json, owned by root with mode 0400; it is excluded from environment and maintenance-container metadata. The initial authority must be active and is staged while schema 4 or schema 5 remains held at backup-verified. Rehearsal remains blocked until that checkpoint exists.

After promotion, an authority update or matching revocation must use a strictly higher generation. Onebox recreates the promoted runtime with the new Docker secret, restores its prior running or stopped state, verifies the exact read-only mapping, and only then advances the authority checkpoint. If replacement is interrupted, startup scales the pending runtime to zero; rerunning the exact same staging command resumes from the persisted intent and secret digest. Generic service-secret APIs cannot add, change, or remove the reserved approval key.

If backup remains pending because Corestore credentials require canonical migration repair, first require status to show phase held, pending intent create-backup, and zero desired, active, and running tasks. Then stop the sole Onebox coordinator and replay the original Corestore migration from the systemd working directory with the same verified checkpoint reference used for the first migration:

cd /var/lib/onebox
sudo onebox systemd stop
sudo onebox migration corestore-platform --status
sudo onebox migration corestore-platform --approve \
  --checkpoint-reference <original-verified-checkpoint-reference>
sudo onebox systemd start
sudo onebox cloudly-secrets-v2 status cloudly
sudo onebox cloudly-secrets-v2 backup cloudly

Do not continue if the offline replay fails, if Onebox does not restart cleanly, or if the post-start cutover status and zero-runtime proof changed. The repair does not start the held Cloudly workload and the final backup command resumes the existing create-backup intent rather than creating a second cutover operation.

Before verify-backup, an existing installation must likewise replay the original Corestore migration so the persisted Corestore owner adopts the current Onebox-pinned image that provides canonical database digests and allocation-fenced scratch databases. Stop the sole Onebox coordinator, require migration corestore-platform --status to show the expected persisted migration phase and hashes, and rerun migration corestore-platform --approve with the original verified checkpoint reference. The replay accepts only known prior Corestore image digests, proves the old container stopped, persists the new immutable image before deployment, and leaves a held Cloudly workload stopped. After restarting Onebox, require the same cutover operation ID, phase, pending intent, backup evidence, and zero-runtime proof before rerunning verify-backup.

authorize records the explicit operator approval. execute separately mints the short-lived, single-run production authorization while the service is proven quiescent. Rehearsal and production authorizations are mounted only into their operation-owned maintenance containers and are removed after use; they are never delivered to the hosted Cloudly runtime. The encrypted rehearsal receipt exists only until it binds production preparation and is then removed. Onebox exposes plaintext maintenance material on the host only through operation-owned mode-0600 staging. The hosted target receives the encrypted-bundle keyring and verified WorkloadInit approval at their dedicated root-owned mode-0400 paths.

begin derives the historical source from the owned immutable Docker runtime and never pulls a mutable source tag. If a prior Onebox defect replaced a stopped runtime's digest reference with a tag, recovery requires --source-image code.foss.global/serve.zone/cloudly@sha256:<digest>. Onebox accepts that input only while the persisted service is stopped and the Swarm runtime has zero desired replicas and no active tasks. It verifies the exact local image, proves that every filtered task belongs to the exact service and is terminal, and pins the existing stopped service through Docker's version fence before persisting the cutover. The full recovery transition is serialized against Onebox service lifecycle mutations. If the persisted-service CAS fails after the runtime pin, the runtime remains stopped at the verified digest, but the operator must inspect the current service record before retrying begin; no cutover is claimed until that original snapshot is persisted successfully.

Every non-promoted operation is held at zero during Onebox startup before routes, gateway export, platform-secret reconciliation, App Store upgrades, or background work can reactivate it. A command interrupted with a persisted pending intent can be rerun for that phase. Maintenance attempts use deterministic identities so a completed result can be adopted after a lost response; Onebox persists terminal ownership before parsing output, records explicit completed zero-blocker proof, and removes the candidate only after proving its exact receipt and absence. Failed verification restores and proves the zero-runtime hold. Startup after restart-verified returns the operation to verified, requiring restart verification to run again before promotion.

A pending prepare-keyring replay reuses and validates the already encrypted Onebox-owned keyring instead of generating or replacing it. A fresh preparation fails closed if the reserved key already exists. Legacy non-inspect CUTOVER_BLOCKED failures display only validated blocker codes and include the total count when the bounded blocker list is truncated; references and malformed evidence are not echoed.

diagnose is available only after a rehearsal stops at the prepared scratch inspection checkpoint. It cannot persist a cutover transition or advance the rehearsal:

sudo onebox cloudly-secrets-v2 status cloudly
sudo onebox cloudly-secrets-v2 diagnose cloudly
sudo onebox cloudly-secrets-v2 status cloudly

Schemas 3 and 4 inspect with the released Cloudly 24.0.0 diagnostic image at exact multiarch digest sha256:26841e9b24444b16d5333ab922ae532e16029026b5aafd7f430c5ff844e4e54c. Schema 5 inspects with the exact Cloudly 24.1.0 target digest sha256:7762dc2660d1392220334a44f361ebf50994af675d97fcf2da5b037e7dc37536; both diagnostic releases emit schema 8. Schema-3 maintenance remains pinned to Cloudly 17.1.0, schema-4 maintenance and hosted target use Cloudly 19.2.0, and schema-5 maintenance and hosted target use Cloudly 24.1.0. Diagnosis also requires the persisted and running Corestore service to prove the exact released 6.3.1 image at digest sha256:bfe71fb356f412979fc829da49599ef6a5de32c46225bd5ef79d2d7393174848; Onebox does not upgrade that service implicitly. Corestore issues one fixed 12-minute read grant bound to the persisted scratch allocation, and Onebox sends its MongoDB URI only over attached stdin to a non-restarting, auto-removing diagnostic container.

Onebox journals the grant and container identities before issuance, retains the journal until revocation and container absence both succeed, and reconciles retained journals before normal startup or another diagnosis continues. Cleanup replay accepts only exact diagnostic-image/Corestore-image tuples emitted by released Onebox versions; it preserves the recorded tuple for digest verification, uses the current exact Corestore runtime for grant revocation, and never executes a historical diagnostic image. Unknown or historically unshipped mixed tuples fail closed. A coordinator-wide lock serializes issuance, reconciliation, and shutdown cleanup; reconciliation attempts every valid journal even when siblings are malformed or fail, and capacity is checked before any new journal is written. Docker attach and wait transports are cancelled at the lifecycle deadline, lost-create adoption must match the complete inspected execution identity, and Corestore control errors are read through the same 16 KiB bound as private grant responses.

Onebox accepts only diagnostics schema 8, validates each finite code/reason pair, the complete blocker aggregates, and every finite diagnostic facet name and count. Facets must be unique, sorted, and bounded; Onebox rejects references, unknown fields, malformed output, unapproved reasons or facets, and invalid counts without echoing their values. Schema 8 retains schema 7's exact 64-facet and ten-predicate contracts plus the nullable raw deployment-settlement mismatch site. It also validates the privacy-safe settlement projection: exact envelope counts for operations, services, images, releases, rollout operations, route claims, and resource claims; aggregate invalid service-envelope counts; and the projected classifier result. Projection counts and classifier fields are exact, source documents are bounded at 2,000, operations at 500, and projection presence must agree with the settlement-evaluated facet. Existing schema-3 candidate reasons remain accepted. Every occurrence remains a blocker: projected evidence refines operator review but does not authorize retirement, settlement, rewriting, target changes, rehearsal continuation, or cutover execution. Run rehearse again only after the reported blockers have exact approved corrections. If a correction changed production itself, the completed rehearsal no longer describes it and cannot be reused: every artifact it produced is bound to the surface it rehearsed, the receipt's inventory digests above all, so prepare-keyring fails closed with AUTHORIZATION_MISMATCH forever. Retire it with sudo onebox cloudly-secrets-v2 retire-rehearsal cloudly, which returns the operation to held so a fresh backup becomes the new baseline. It requires a rehearsal whose scratch database is already proven absent, and refuses once the production keyring, production prepare, or production settlement has consumed the rehearsal. It re-proves the scratch database absent live before discarding the allocation reference, and records the retired rehearsalId, backupId, snapshot digest and absence proof in retiredRehearsals so the retired artifacts stay nameable afterwards. The discarded run id, scratch state, and rehearsal-derived secrets are not kept; the encrypted keyring is.

Upgrading an existing Corestore owner to this diagnostic runtime is an explicit offline replay, not a startup action. First prove every Corestore consumer quiescent, stop the sole Onebox coordinator, stop and prove the exact Corestore container stopped, then create and independently verify a fresh full-volume checkpoint outside the authoritative Docker volume. This fresh pre-upgrade checkpoint is recovery evidence; the replay command must still receive the original checkpoint reference already captured in the persisted migration state:

cd /var/lib/onebox
sudo onebox migration corestore-platform --status
sudo onebox migration corestore-platform --approve \
  --checkpoint-reference <original-verified-checkpoint-reference>
sudo onebox migration corestore-platform --status

The replay accepts only exact known prior images, including 6.3.0, durably selects 6.3.1, and keeps stopped Cloudly workloads stopped. Corestore 6.3.1 contains SmartDB 5.5.2, which pushes a leading aggregation match into the storage scan so filtered counts do not materialize unrelated documents. The 6.3.06.3.1 update changes the query path, not the storage format, but still requires the stopped-state checkpoint and explicit replay above. When upgrading from pre-SmartDB-5 releases such as Corestore 5.2.1, inspect every managed database before replay: SmartDB 5 reserves the physical system.views namespace and rejects noncanonical collections under that name. That earlier storage transition is one-way. After an interrupted start, retry the selected 6.3.1 runtime; restore the fresh checkpoint before selecting an older runtime, and never point a pre-SmartDB-5 runtime at storage already opened by SmartDB 5.

verify-backup performs full archive-integrity verification and validates the exact Corestore backup receipt. rehearse then provisions an expected-absent pinned Corestore scratch database, persists its allocation identity before restore, validates the restore response, and compares Corestore's bounded canonical source and restored content digests plus every scan counter. The same persisted rehearsal and allocation identity fences provisioning, restore, digest and status checks, and cleanup; completion requires a fenced absence proof. This proof streams the database scan without using the size-limited portable export payload. The scratch proof covers the selected database only; it does not prove restoration of application object-storage resources. The authenticated Onebox full-backup restore workflow remains responsible for restoring and verifying every supported resource represented by the backup. Named object-storage bindings and requests are currently unsupported by that workflow and make backup creation fail closed.

For schema-5 operations rehearse also settles Cloudly's legacy deployment operations before the source inspection. Onebox mints a fenced source settlement authority (a 32-byte HMAC key handed to Cloudly only inside private request files), then runs the pinned Cloudly 25.1.0 settlement image through secrets-v2 settlement-stdio --request-file --response-file with the operation directory mounted at /run/onebox-cutover: settlement-plan against the scratch database, settlement-request, settlement-scratch-check, and settlement-scratch-apply. Every authenticated artifact (plan, request bundle, scratch receipt) is verified in-process against the authority key with the @serve.zone/interfaces runtime contracts before it is persisted as an encrypted service secret with a digest checkpoint; a lost apply response is resolved through settlement-scratch-resolve, and only a committed receipt is adopted. Production is settled at the start of prepare-keyring, under that step's own operation fence and before Cloudly reads production at all: Onebox mints the production authority bound to the rehearsed plan, request bundle, and scratch receipt, then runs settlement-production-authorize, settlement-production-check, and settlement-production-apply against the production database. This mirrors the rehearsal, which settles the scratch before inspecting it, so production executes the same sequence that was rehearsed. It has to happen here rather than later: both the production prepare and the inspect that follows it bind production to the rehearsed baseline, and that baseline is post-settlement, so an unsettled production can never match it. execute repeats the call as an idempotent backstop for an operation that somehow reached execution unsettled, and a completed settlement short-circuits. Both authority handoffs are removed after the production receipt is persisted. Settlement authorities live 12 hours (the interfaces contract caps them at 24), so prepare-keyring must follow rehearse within that window; an expired source authority fails closed with a re-rehearsal requirement.

Once a cutover reaches promoted and carries no pending intent, it is finished and its state is history rather than live configuration. The startup migration cloudly-secrets-v2-cutover-retirement takes it off the service document: it writes one CloudlySecretsV2CutoverArchive record per service — which service moved, the App Store version and pinned image it came from and went to, and when the cutover was opened, settled and promoted — and then removes cloudlySecretsV2Cutover under the same operation-id/revision/phase fence every other service write uses. The step is all-or-nothing: a cutover anywhere that is not promoted, or that still carries a pending intent, aborts it and leaves every service untouched. The archive record has its own shape and version and carries no fence, evidence or lineage structure, so it stays readable without the cutover implementation.

Rollback mode is exclusively full-restore-only. Once begin has persisted the cutover, there is no cancel command and no old-image rollback command. Recovery must use the authenticated Onebox full-backup restore workflow; replacing the image or metadata manually is not a supported rollback. Promotion is available only after the target starts successfully, reports a verified-completed rollback-fenced status, and passes a second restart without authorization.

Configuration Notes

Useful settings include:

Setting Purpose
adminUiDomain Exact HTTPS hostname used as the WebAuthn relying-party ID.
serverIP IP address used for DNS records.
cloudflareToken Cloudflare API token. cloudflareAPIKey is accepted as a legacy alias.
cloudflareZoneId Cloudflare zone identifier.
acmeEmail ACME account email for certificate issuance.
httpPort OpsServer/web UI port. Defaults to 3000.
metricsInterval Metrics collection interval in milliseconds.
backupPassword Secret passphrase for encrypted backup repositories.
dcrouterGatewayUrl Optional external dcrouter API endpoint.
dcrouterGatewayApiToken Optional external dcrouter API token.
dcrouterGatewayClientId Optional stable external gateway client identity used for route ownership.
dcrouterTargetHost Optional target host advertised to dcrouter.
dcrouterTargetPort Optional target port advertised to dcrouter.

Example:

onebox config set serverIP 203.0.113.10
onebox config set acmeEmail ops@example.com
onebox config set cloudflareToken --stdin
onebox config set cloudflareZoneId zone-id

For the stdin form, enter or pipe one secret line and then close stdin.

External registry credentials remain encrypted in Onebox and are decrypted only for the exact Docker image-pull request that needs them. Onebox does not persist them through docker login.

App Store

The App Store manager fetches metadata from serve.zone/appstore through @serve.zone/appstore and caches it briefly. Templates can declare public, secret, and generated environment inputs, container arguments, file-mounted secrets, and platform requirements. Installing an app can automatically provision Corestore database/object-storage, ClickHouse, Valkey, or MariaDB resources.

Service secrets and provisioned platform credentials are encrypted at rest. The browser seals each declared secret to Onebox's active X25519 recipient with install-specific authenticated context before the TypedRequest call. The root CLI accepts secrets only through bounded stdin over its mode-0600 local control socket; the daemon seals them before constructing the install request. Generated values are created inside Onebox. Plaintext install secrets never enter the public environment, browser request cache, process arguments, or persisted App Store metadata. Environment secrets work with standalone Docker containers and Swarm services. File-delivered secrets stay out of the environment and are mounted through Docker secrets, so Onebox rejects them when the host is not using Swarm mode.

Hosted apps authenticate to Onebox with signed, audience-scoped RS256 machine JWTs stored in the encrypted service-secret bundle. Onebox verifies both the signature and the exact currently active token, rotates legacy random tokens and near-expiry JWTs, and reconciles changed identities through the normal service update path. Bootstrap actions use typed message/setup-route variants and revision-fenced atomic transitions; concurrent lifecycle changes fail closed.

Named storage contracts

App Store versions can declare template-local storageClasses and stable storageRequests for filesystem and objectStorage resources. These declarations contain portable requirements only. Provider names, host paths, network shares, mount options, and authentication details remain Onebox operator configuration and never enter an app manifest.

Onebox normalizes every install through @serve.zone/appstore, negotiates the declared storage feature IDs, selects a compatible operator class deterministically, and persists the canonical resolved binding on the service. Filesystem requests become service-owned Docker volumes. Each object-storage request receives its own bucket, endpoint, and scoped credential material through the Corestore v2 binding API; multiple named bindings use disjoint environment keys and encrypted service-secret storage.

Legacy volumes and platformRequirements.s3: true declarations are normalized for new installs. Existing pre-binding services remain on their legacy resources during compatible upgrades. Adding or changing an explicit named request requires a storage migration instead of silently replacing data.

The current fulfillment adapter advertises only local/backup filesystem classes and the standard managed object-storage policy with environment delivery. Capacity requests, secret-file object delivery, hard quotas, snapshots, versioning, non-local filesystem targets, and Kerberos-authenticated NFS remain unadvertised and fail closed. Onebox does not fall back to local storage when a requested capability or mapped class is unavailable. Reclaim policy is honored as retain or delete during rollback and service removal.

Backups export and restore opted-in filesystem volume data by mount path while preserving the portable storage specification, together with supported legacy platform resources. Named object-storage bindings and requests remain unsupported; backup creation fails closed when either is present.

onebox appstore list
onebox appstore config cloudly
onebox appstore install cloudly --name cloudly --domain cloudly.example.com

Backups

Backups are built around @serve.zone/containerarchive. Onebox exports service configuration, encrypted service-secret ciphertext, platform resource metadata, supported platform data, and optionally Docker images into a content-addressed archive repository. Platform data is streamed as a fixed, bounded set of deterministic logical tar items rather than one archive item per file. Restore derives large-item limits from authenticated snapshot metadata and validates tar paths, entry types, sizes, and symlink boundaries before importing data.

S3-compatible resources store object bodies under SHA-256 identifiers and retain exact object keys in a validated versioned manifest, so an object key is never interpreted as a filesystem path. Host-side export of a Corestore-owned bucket requires the canonical internal endpoint http://onebox-corestore:9000, the exact onebox-corestore container identity, and its loopback-published S3 port. Stale onebox-smartstorage credentials, malformed Corestore endpoints, and missing host publications fail closed and require the explicit Corestore migration replay above; Onebox does not add a host alias or persist a loopback endpoint into workload credentials. Compatibility readers remain isolated for earlier untagged file-item snapshots and .tar.enc backups; new backups write only the logical-item format. Legacy .tar.enc restores migrate plaintext control and platform credentials into the current representation.

Image-inclusive backups always resolve the active Docker image ID and export by that immutable ID. A canonical digest or mutable tag is retained only while it resolves to the active image; an absent or moved mutable tag is discarded in favor of the verified image ID, while a conflicting immutable digest fails closed. Restore verifies the archived image ID before changing service state, never reassigns a mutable tag, and never replaces archived content with a registry pull.

Encrypted service-secret bundles can be decrypted only with the same credential-encryption key. Set the same 32-byte, base64-encoded ONEBOX_ENCRYPTION_KEY on another host before restoring there; without an explicit key, Onebox derives one from the hostname and /etc/machine-id, so ciphertext is portable only to a host with the same machine identity.

Backup and schedule operations are primarily exposed through the OpsServer/web UI handlers. Root operators can also run onebox backup create <service-name> and onebox backup list [service-name]; both commands execute inside the sole coordinator through the root-only Unix control socket. Backup creation is serialized per service across CLI, UI, and scheduled callers.

Development

Requirements:

  • Node.js for the application runtime.
  • pnpm for package scripts.
  • Docker for any runtime path that initializes Onebox fully.

Common tasks:

pnpm run watch
pnpm run build
pnpm test
node ./cli.ts.js server --ephemeral --monitor

Source map:

Path Purpose
cli.js Built CLI entry point.
cli.ts.js Source CLI entry point for development.
ts/cli.ts CLI router and command help.
ts/classes/onebox.ts Main coordinator.
ts/classes/docker.ts Docker client, networks, containers, and Swarm services.
ts/classes/coretraffic.ts CoreTraffic Docker service and Admin API manager.
ts/classes/reverseproxy.ts CoreTraffic route and certificate bridge.
ts/classes/platform-services/ Local platform service providers.
ts/classes/appstore.ts Remote App Store catalog and upgrade logic.
ts_migration/cloudly-secrets-v2-cutover.ts Persisted, phase-gated Cloudly Secrets v2 cutover coordinator.
ts_migration/cloudly-secrets-v2-cutover-retirement.ts Archives a completed Cloudly Secrets v2 cutover and removes it from the service document.
ts/classes/workloadinit-approvals.ts Ongoing approval verification, runtime delivery, startup holds, and recovery.
ts/database/workloadinit-approvals.ts Transactional approval owner, encrypted custody, and immutable history.
ts_migration/workloadinit-approval-ownership.ts Imports existing approval custody without fabricating historical acceptance.
ts/classes/storage-manager.ts Portable storage capability negotiation, class selection, binding fulfillment, and lifecycle.
ts/classes/backup-manager.ts Backup and restore orchestration.
ts/opsserver/ Web UI server and TypedRequest handlers.
ts/database/ SmartDB repositories.
ts_migration/ Versioned persisted-data and infrastructure migrations.
ts_web/ Dashboard source.

This repository contains open-source code licensed under the MIT License. A copy of the license can be found in license.md.

Please note: The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.

Trademarks

This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH or third parties, and are not included within the scope of the MIT license granted herein.

Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines or the guidelines of the respective third-party owners, and any usage must be approved in writing. Third-party trademarks used herein are the property of their respective owners and used only in a descriptive manner, e.g. for an implementation of an API or similar.

Company Information

Task Venture Capital GmbH
Registered at District Court Bremen HRB 35230 HB, Germany

For any legal inquiries or further information, please contact us via email at hello@task.vc.

By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.

S
Description
a single server quick hosting tool
Readme
55 MiB
Onebox v8.3.3
Latest
2026-09-05 00:19:25 +00:00
Languages
TypeScript 99.7%
Shell 0.3%