Configuration
sandboxod, zoned and the all-in-one dev.ts each read one JSON file given with
--config <file>. Keys are snake_case and unknown keys are errors. Every key
not marked required has a default, so a minimal sandboxod config is:
{
"token": { "_env": "SANDBOXO_TOKEN" },
"signing_secret": { "_file": "/run/keys/sandboxo-signing" },
"blobs": { "backend": "fs" }
}
Errors name keys in camelCase (build.timeoutMs for build.timeout_ms).
Relative paths resolve against the working directory.
Secrets
Keys marked secret take a plain string or a placeholder, the same ones obice uses:
{ "_env": "NAME" }-
the value of the environment variable
NAME. { "_file": "/path" }-
the content of the file, without trailing newlines.
A missing variable or an unreadable file fails startup. Secret keys:
sandboxod's token, signing_secret, the values of zone_tokens and
kv.url, zoned's token, and in both blobs.access_key_id,
blobs.secret_access_key and the values of every headers in telemetry.
Environment
Only the Nix profiles come from the environment, and binaries from PATH. The
zoned and sandboxo packages set both in their wrappers; the dev shell has
them for deno run. zoned and dev.ts fail at startup when one is missing.
| Variable | Meaning |
|---|---|
|
required, Nix profile of build and runtime sandboxes |
|
required, Nix profile of generic sandboxes (e2b, Deno Sandbox) |
zoned needs on PATH: sbx-runsc (sbx-gvisor), pasta (passt),
mkfs.erofs (erofs-utils), iron-proxy for sandbox egress policies, obice
for the zone's tunnels (its envoy comes from obice's own PATH), btrfs,
unshare and nsenter.
sandboxod
| Key | Default | Meaning |
|---|---|---|
|
required, secret |
admin token for the API, the UI and |
|
required, secret |
signs UI query links and upload links, see Observability |
|
required |
blob storage, see State directory |
|
Redis on |
record storage, see State directory |
|
none |
Loki, Mimir, Tempo and OTLP, see Observability |
|
|
state directory, see State directory |
|
|
deployment id ( |
|
|
apps are served on |
|
|
https port of the routers, used in app and sandbox URLs |
|
|
API and UI, also where zones register and routers fetch their routes |
|
|
unix socket of the egress listener of the router on this host, sandboxod reaches the zones through it |
|
|
|
|
|
default region for new sandboxes, volumes and apps |
|
|
zone name to secret, written into the zone records at startup, see Zones |
|
|
longest lifetime of a generic sandbox |
|
|
e2b template build timeout |
|
|
SSH gateway, |
|
|
SSH gateway listen address |
|
|
host the SSH commands name |
|
|
in-flight requests per replica above which an app scales up, see Scaling |
|
|
how long the load has to stay low before a replica is removed |
|
|
build timeout of apps that set none |
|
|
largest build timeout an app may set, at least |
|
|
build memory limit of apps that set none, |
|
|
largest build memory limit an app may set |
|
|
cron jobs a revision may register, more fail the build |
|
|
a cron run that takes longer fails and its instance is replaced |
|
|
runs kept per cron job |
|
|
bare repository cache for git deploys |
|
|
git fetch timeout |
|
|
limits of one upload or git tree |
|
|
blob garbage collection interval ( |
|
none |
multi-tenant mode with users and organizations from an OpenID provider (pykrete), see OpenID Connect |
OpenID Connect
With oidc set, users log in through the provider and every organization they
belong to there is a tenant: its members share its apps, sandboxes, volumes,
snapshots and templates. API keys are minted, listed and revoked through the
provider's backend API (a Clerk-compatible subset) and checked with RFC 7662
introspection. telemetry.tenant must be app, and redirect_base must
not be under domain (apps would receive the session cookie).
| Key | Default | Meaning |
|---|---|---|
|
required |
issuer URL; discovery must report the same issuer |
|
required, secret |
confidential client; the secret is also the backend API key. The client needs "Backend API" (set by the client owner) and "All organizations" (first-party, set by a pykrete admin), otherwise every organization has to enable the client and only users who authorized it are visible |
|
|
or |
|
required |
public origin of the UI; the redirect URI is |
|
|
backend API base URL |
|
|
provider organization id that owns records created before multi-tenancy (and in single-org mode); it cannot change once set |
|
|
requested scopes |
|
|
lifetime of a UI login |
|
|
how long API key checks and organization memberships are cached, so how late a revoked key or a removed member is noticed |
|
|
also offer the admin token form on |
|
none |
links to the provider's organization page ( |
zoned
| Key | Default | Meaning |
|---|---|---|
|
required |
zone name, a DNS label of at most 32 characters |
|
required, secret |
zone token, see Zones |
|
required |
blob storage, the same as sandboxod's, see State directory |
|
none |
where logs, traces, metrics and usage are pushed, see Observability |
|
|
region of the zone |
|
|
must match sandboxod's |
|
|
zone API listen address, only the zone's envoy connects |
|
the listen address |
zone URL reported to sandboxod |
|
sandboxod API listener |
|
|
|
zone state directory, see State directory |
|
|
GC roots and private store of the profiles |
|
|
warm runtime sandboxes per network flavor |
|
|
warm build sandboxes |
|
|
builds the zone runs at once |
|
|
build memory limit of apps that set none, |
|
|
added to the app's limit for the build sandbox's cgroup |
|
none |
|
|
|
cgroup parents of build, runtime and generic sandboxes: a path, |
|
|
how long a replica may take to start |
|
|
idle replicas stop after this long without requests |
|
|
how long a replica that is scaled down or replaced finishes its requests |
|
|
warm generic sandboxes |
|
|
generic sandboxes the zone runs at once |
dev.ts
dev.ts starts sandboxod and its zones in one process. Its config has three
keys:
sandboxod-
a sandboxod config.
zoned-
zoned keys shared by every zone, except the ones
dev.tssets itself:name,region,token,org,hostname,port,url,control,state,blobsandtelemetry. zones-
[{"name", "region"?}], default<region>1and<region>2of sandboxod's region.
Every zone gets a random token, a free loopback port, sandboxod's org,
telemetry and blob storage (fs blobs in <state>/blobs), its state in
<state>/zones/<name>/ and gc_root_dir <state>/nix unless set. The dev
shell exports SANDBOXO_DEV_CONFIG (and SANDBOXO_DEV_UI_CONFIG with
ui: development), generated from flake.nix, which points at the
process-compose backends and reads the token from SANDBOXO_TOKEN:
SANDBOXO_TOKEN=secret deno task dev
NixOS
services.sandboxod.settings and services.zoned.settings are written to the
config file. The modules set the keys their options cover (domain, name,
ports, state directory, ...), the tokens as _file placeholders on systemd
credentials, and for the local Redis and Garage of services.sandboxod
kv and blobs with _env placeholders. Secrets for other placeholders go
in environmentFiles:
services.zoned = {
enable = true;
name = "ord1";
tokenFile = "/run/keys/zone-ord1";
controlUrl = "http://10.0.0.1:8001";
settings = {
pool.none = 4;
blobs = {
backend = "s3";
endpoint = "http://10.0.0.1:3900";
access_key_id._env = "SANDBOXO_S3_ACCESS_KEY_ID";
secret_access_key._env = "SANDBOXO_S3_SECRET_ACCESS_KEY";
};
};
environmentFiles = [ "/run/keys/zone-s3.env" ];
};