8.8 KiB
@serve.zone/baseos
BaseOS is the serve.zone runtime layer for devices that should run on balenaOS-derived host systems but enroll only in Cloudly.
The first implementation target is intentionally small: a baserunner container runs on the device, talks to the local Balena Supervisor API when available, reports status to Cloudly, and prepares the update path for Onebox and other BaseOS services.
Goals
- Use balenaOS as the proven host foundation for embedded and edge devices.
- Avoid BalenaCloud enrollment for serve.zone devices.
- Enroll devices directly in Cloudly with a Cloudly join token.
- Let Cloudly track BaseOS nodes, desired releases, rollout state, and update health.
- Let Onebox detect when it is running on BaseOS and delegate self-updates to BaseRunner.
- Keep the first version useful without pretending host OS updates are solved.
Non-Goals For V1
- No BalenaCloud fleet enrollment.
- No openBalena dependency.
- No full Balena API replacement.
- No remote host OS updates until BaseOS has its own signed artifact channel.
- No silent use of Balena trademarks as serve.zone branding.
Runtime Model
balenaOS-derived host
Balena Supervisor
baserunner container
- Cloudly enrollment and heartbeat
- local Supervisor API access
- local BaseOS runtime API for Onebox, later
onebox container, later
- detects BaseOS through BaseRunner
- delegates self-update to BaseRunner
- runs Onebox-managed apps in its own runtime model
The current scaffold implements baserunner; the matching Cloudly registration and heartbeat handlers live in the cloudly repo. Onebox integration is still a later focused change.
Levels
Level 1: App-Layer Updates
Level 1 is the first production target.
BaseOS devices boot a balenaOS-derived image with baserunner preloaded. baserunner enrolls the node in Cloudly, reports Balena Supervisor/device state, and can ask the local Supervisor to check/apply application release updates.
Cloudly responsibilities:
- Store BaseOS node records.
- Issue and validate join tokens.
- Accept BaseRunner heartbeats.
- Track current BaseRunner/Onebox release metadata.
- Publish desired app-layer release state.
BaseRunner responsibilities:
- Persist a node ID and node token in a named volume.
- Report supervisor availability, OS version, supervisor version, release hash, update state, and IP information.
- Receive desired app-layer state from Cloudly heartbeats.
- Call Supervisor API endpoints such as
/ping,/v1/device,/v2/state/status, and/v1/update.
Onebox responsibilities:
- Detect BaseOS via a local BaseRunner API and explicit environment such as
SERVEZONE_RUNTIME=baseos. - Disable direct self-replacement when running on BaseOS.
- Ask BaseRunner to perform BaseOS-safe app-layer updates.
Level 1 does not update the host OS remotely. Host OS updates are manual or deferred.
Level 2: Cloudly-Managed Host OS Releases
Level 2 adds a Cloudly-owned BaseOS update channel.
Cloudly or a central serve.zone update service hosts signed BaseOS host OS artifacts. Devices are still enrolled only in Cloudly.
Artifact layout target:
https://updates.serve.zone/baseos/<device-type>/<version>/manifest.json
https://updates.serve.zone/baseos/<device-type>/<version>/checksums.txt
https://updates.serve.zone/baseos/<device-type>/<version>/license-bundle.tar.gz
registry.serve.zone/baseos/hostapp/<device-type>:<version>
registry.serve.zone/baseos/baserunner:<version>
Cloudly responsibilities:
- Maintain approved BaseOS channels.
- Pin desired host OS versions per node or fleet.
- Verify release signatures before rollout.
- Track staged, applying, succeeded, failed, and rollback-needed states.
BaseRunner responsibilities:
- Verify release manifests and signatures.
- Hold update locks during critical work.
- Coordinate with the host update mechanism where available.
- Report detailed progress and failure logs.
This level requires careful work against balenaOS host update internals and licensing obligations for redistributed images.
Level 3: Cloudly As A Balena-Compatible Backend
Level 3 is the largest option and should only happen if Level 2 is insufficient.
Cloudly would implement enough target-state and artifact APIs for a balenaOS-derived Supervisor to treat Cloudly as its backend. The device config.json would point to Cloudly-controlled endpoints instead of BalenaCloud endpoints.
Target endpoints would include equivalents for:
- API target state.
- Registry pulls.
- Delta service, if implemented.
- VPN or remote access, if required.
- Device diagnostics and logs, if required.
This level is effectively a focused openBalena-like backend inside serve.zone. It is not a first milestone.
Cloudly-Only Enrollment
BaseOS devices should not need BalenaCloud identity.
Enrollment flow:
1. User creates a BaseOS join token in Cloudly.
2. BaseOS image is flashed with BASEOS_CLOUDLY_URL and BASEOS_JOIN_TOKEN.
3. BaseRunner boots and registers against Cloudly.
4. Cloudly returns a node token.
5. BaseRunner stores the node token in /data/baseos/state.json.
6. Future heartbeats use the node token.
Current provisional HTTP endpoints used by this scaffold:
POST /baseos/v1/nodes/registerPOST /baseos/v1/nodes/heartbeat
Cloudly implements these paths through its BaseOS manager. A deployed Cloudly instance must also have baseosJoinToken configured before new nodes can enroll.
Supervisor API Usage
BaseRunner uses Balena Supervisor APIs only when BALENA_SUPERVISOR_ADDRESS and BALENA_SUPERVISOR_API_KEY are provided by the io.balena.features.supervisor-api service label.
Current calls:
GET /pingGET /v1/device?apikey=...GET /v2/state/status?apikey=...GET /v2/version?apikey=...POST /v1/update?apikey=...POST /v1/reboot?apikey=...
The docker-compose.yml enables the supervisor API label for baserunner.
Onebox Integration Plan
Onebox should detect BaseOS through explicit runtime signals, not by guessing from Balena environment variables alone.
Detection signals:
SERVEZONE_RUNTIME=baseosBASEOS_AGENT_URLor equivalent local BaseRunner API URL- successful BaseRunner handshake
Onebox behavior on BaseOS:
- Show BaseOS runtime in system status.
- Route self-update requests to BaseRunner.
- Avoid replacing its own container directly.
- Use update locks around backup/restore and migration operations.
Security
- Join tokens must be one-time or short-lived.
- Node tokens must be long-lived machine tokens scoped to one BaseOS node.
- Host OS release manifests must be signed before Level 2.
- BaseRunner must reject unsigned or untrusted desired host OS updates.
- Supervisor API access is powerful; keep BaseRunner's local API private and minimal.
- Never log join tokens, node tokens, or Supervisor API keys.
Licensing And Branding
balenaOS source components are open source, but trademarks are separate from copyright licenses.
BaseOS must:
- Preserve required upstream notices and license bundles.
- Provide source/license compliance for redistributed GPL/LGPL/Yocto components.
- Avoid presenting BaseOS as official Balena software.
- Replace public-facing branding when redistributing images.
- Use Balena names only where needed to describe compatibility or documented APIs.
Implementation Milestones
Milestone 1: BaseRunner Scaffold
- Deno CLI and daemon structure.
- Supervisor API client.
- Persistent node state.
- Provisional Cloudly register/heartbeat client.
- Balena compose service definition.
Milestone 2: Shared Interfaces
- Add BaseOS node, runtime status, desired state, heartbeat, and registration contracts to
@serve.zone/interfaces. - Add machine role or scoped token model for BaseOS nodes.
Milestone 3: Cloudly BaseOS Manager
- Join token validation through
baseosJoinToken. - Node registration.
- Heartbeat ingestion.
- Desired state storage.
- Admin/UI status views.
Milestone 4: Onebox Runtime Detection
- Add BaseOS runtime manager to Onebox.
- Add status display.
- Route Onebox self-update through BaseRunner when running on BaseOS.
Milestone 5: App Release Updates
- Build and publish BaseRunner release images.
- Add Onebox service image/release metadata.
- Let Cloudly request app-layer updates.
- Report update status and failures.
Milestone 6: Host OS Release Channel
- Build BaseOS host OS images.
- Publish signed manifests and artifacts.
- Add Cloudly release approval and rollout controls.
- Add BaseRunner host update execution and reporting.
Current Commands
deno task check
deno task start
deno task dev
deno task fmt
deno task lint
Run a one-shot status check:
deno run --allow-env --allow-net --allow-read=/data/baseos,. --allow-write=/data/baseos mod.ts status
Inside balenaOS, the baserunner service should be started from docker-compose.yml so the Supervisor API environment variables are injected.