Workspace settings and capacity
A workspace runs every sandbox inside one VM, so the VM's size sets how many sandboxes can run at once. This page explains how the workspace counts its capacity, the workspace policy that caps what a sandbox may ask for, and the domains sandbox ports are published under.
The console shows the same on its Workspace page, where you can also edit the policy and the domains.
Capacity
zbox workspace prints the capacity and what is in use, for example on a workspace with 2 CPU cores and 4 GiB of RAM:
| Resource | Capacity |
|---|---|
| vCPUs | The workspace's CPU cores × cpuOvercommit (8 unless the policy sets another value). |
| Memory | The VM's memory less a reserve for the workspace's own system (coreReserveBytes, 512 MiB unless the policy sets another value). Memory is never overcommitted. |
| Disk | The workspace disk. 1 GiB must stay free (the headroom) for anything new to start. |
zbox workspace --json and GET /api/rest/workspace answer the same numbers in bytes: capacity holds the usable and the total memory, the reserve, the cores, cpuOvercommit, the disk and the headroom. usage holds what is reserved (cpus, memoryBytes), what the sandboxes hold (memoryResidentBytes), the used disk, the running and parked sandboxes, and the builds in progress.
What a sandbox reserves
- A running sandbox reserves its memory size and its vCPUs. The reservation is the size you gave the sandbox, not what it uses: the
residentfigure shows how much memory the sandboxes actually touch. A sandbox reserves the same while it is being created, woken, restored or parked (CREATING,WAKING,RESTORING,PARKING). - A sandbox you remove keeps its reservation while it is
TERMINATING, also when it was parked, and frees it when it isTERMINATED. - A parked sandbox reserves no CPU and no memory, and neither does a
FAILEDone. A parked sandbox keeps its disk and, when parked with memory, a memory image on the workspace disk (park and wake). - A base pull or a base build reserves 512 MiB of memory while it runs, the memory a build may use (build a base). A warm template build reserves the template's size while it builds (warm templates).
- A resize of a running sandbox needs only the growth to fit, because the sandbox already holds its old size (resize a sandbox).
- A disk is a cap, not a reservation. Nothing reserves disk space, every capacity check only wants the headroom free (what uses the disk).
A sandbox can't have more vCPUs than the workspace has cores. vCPUs beyond the cores are shared: the running sandboxes get CPU time in proportion to their vCPUs.
What uses the disk
Everything a workspace stores sits on its disk: bases, templates (with their memory images when warm), what each sandbox writes to its disk, the memory images of sandboxes parked with memory, snapshots, file exports and uploaded archives for 24 hours, and the cache of base builds. A sandbox's disk takes space only for what the sandbox writes. A fork shares its parent's disk and adds only what changes afterwards (fork a sandbox).
The space a sandbox's disk takes only grows. Deleting files inside the sandbox doesn't give it back to the workspace disk: the sandbox's disk doesn't support discard, so fstrim fails. A parked sandbox keeps its whole disk. Only removing the sandbox frees its disk and memory image.
Sandboxes don't reserve disk. Every sandbox sees its disk at its full size even when the workspace has less free space, and the headroom only stops new sandboxes, wakes, forks, restores, snapshots, builds, exports and imports from starting. When the workspace disk does fill up, writes fail with I/O errors in every running sandbox, not just a No space left on device in the one that wrote the most. Keep an eye on the disk line of zbox workspace when sandboxes write a lot.
When the workspace is full
Creating, forking, restoring, waking or resizing a sandbox, taking a snapshot, building a warm template, pulling or building a base, and exporting or importing a sandbox each check the free capacity first. An export or an import also needs room for the archive it writes, on top of the headroom. If something doesn't fit, the request fails with 409 workspaceFull and the CLI exits with code 7:
The error's metadata names the resource (memory, cpu or disk) with requested, free and usable (bytes, or vCPUs for cpu). The workspace never parks or removes sandboxes to make room. To free capacity:
- memory or CPU: park sandboxes you don't need right now, or remove them (park and wake), or give new sandboxes smaller sizes.
- disk: remove sandboxes, snapshots, templates, bases and file exports you no longer need, or park sandboxes with
--no-memoryto drop their memory images (delete bases and templates). Deleting files inside a sandbox doesn't help (what uses the disk). - any: resize the workspace. Disk can only grow.
Workspace policy
The workspace policy sets ceilings for every sandbox and template in the workspace, and the two numbers the capacity is computed from. A new workspace has an empty policy ({}): no ceilings, and the default capacity settings.
| Field | What it does | When not set |
|---|---|---|
allowedNetworkModes | The network modes a sandbox may use, for example ["INTERNET", "AIRGAPPED"]. | All modes |
maxCpus | Most vCPUs per sandbox. | Up to the workspace's cores |
maxMemoryBytes | Most memory per sandbox, in bytes. | Up to the free capacity |
maxDiskBytes | Largest disk per sandbox, in bytes. | Up to the workspace disk |
defaultDiskBytes | Disk of a sandbox or template created from a base without a disk size, in bytes. A sandbox from a template takes the template's disk. | 10 GiB |
maxIdleTtlSeconds | Longest idle TTL a sandbox may set. | No cap |
maxAbsoluteTtlSeconds | Longest absolute TTL a sandbox may set. | No cap |
coreReserveBytes | Memory kept for the workspace's own system, taken off the usable memory. 0 is allowed. | 512 MiB |
cpuOvercommit | vCPUs the running sandboxes may reserve per core, from 1 to 64. | 8 |
secrets.allowedModes | The secret modes a sandbox may use, of NONE, ALLOWLIST (a list of names) and ALL_ENVS (--secrets all). | All modes |
secrets.allowedNames | The workspace variables a sandbox may select or alias as secrets. With a list, ALL_ENVS is refused. | No limit, also when empty |
A sandbox or template over a ceiling is refused with 422 policyViolation, for example memoryBytes 1610612736 exceeds the template or Workspace ceiling. The size ceilings are checked on create, on every fork child and restore, on a wake that changes the size, and on import. A change of the name or the TTLs checks the network mode, the TTLs and the secrets again, but not the size, so it passes under a lowered size ceiling. The secrets ceiling is checked on create, on a change of the sandbox policy (PUT /api/rest/sandbox/{id}/policy) and on import (secrets). The TTL caps apply only to TTLs you set: a sandbox without TTLs is always allowed (idle and absolute TTL). A template can set lower ceilings of its own, but none above the workspace's (templates).
Print the policy, edit it and write it back. -f replaces the whole policy, so start from the printed one; - reads it from stdin:
# print the policy as JSON
zbox workspace policy > policy.json
# cap sandboxes at 2 vCPUs and 4 GiB, no project network access, only GH_TOKEN as a secret
cat > policy.json <<'EOF'
{
"maxCpus": 2,
"maxMemoryBytes": 4294967296,
"allowedNetworkModes": ["INTERNET", "AIRGAPPED"],
"secrets": { "allowedNames": ["GH_TOKEN"] }
}
EOF
zbox workspace policy -f policy.json
# back to the defaults
echo '{}' | zbox workspace policy -f -
The console's Workspace page has the same form. The API is PUT /api/rest/workspace/policy (HTTP API).
Changes apply at once to new requests. coreReserveBytes and cpuOvercommit change the capacity immediately. Existing sandboxes keep their size and network mode when you tighten the policy, even if they are now over a ceiling or the running ones reserve more than the new capacity; nothing new is admitted until they fit.
Defaults for new sandboxes
A sandbox created without these options gets:
| Setting | Default |
|---|---|
| Size | 1 vCPU, 512 MiB of memory, a disk of the policy's defaultDiskBytes or 10 GiB (sizes) |
| Network mode | PROJECT_INTERNET in the CLI and the console (the API requires a mode) |
| Egress rules | None, the network mode alone decides (egress rules) |
| Idle and absolute TTL | None |
| Ports | None |
A sandbox created from a template takes the template's size, ports and egress rules instead (templates). Apart from defaultDiskBytes, the policy has no fields for these defaults: set them per sandbox (create a sandbox) or through a template.
Domains
Sandbox ports get their public URLs from the workspace's domains. Each HTTP port of a sandbox gets one URL per domain, in the order the domains are listed, so hosts of a sandbox lists every port once per domain. zbox open and the console open the URL on the first domain. With no domain, sandbox ports have no public URL. Who may open a URL is up to the port's access mode.
A domain has one of two forms:
| Form | URL of port 3000 of sandbox l8mvceq5 | Use for |
|---|---|---|
| dash | https://3000-l8mvceq5-zbox-6da-8081.prg1.zerops.app/ | The Zerops subdomain of the workspace's port 8081 |
| dot | https://3000-l8mvceq5.box.example.com/ | Your own wildcard domain *.box.example.com |
The domains are set only through the CLI, the console or the API (PUT /api/rest/workspace/domains). Zerops never adds one on its own.
# list the domains
zbox workspace domain list
# add your own wildcard domain (dot form is the default)
zbox workspace domain add box.example.com
# add the Zerops subdomain of port 8081
zbox workspace domain add zbox-6da-8081.prg1.zerops.app --form dash
# remove a domain
zbox workspace domain remove box.example.com
A domain is a bare lowercase hostname, without *., a scheme or a path. A new domain goes to the end of the list. Removing a domain takes effect at once: every URL on it stops working, including links you have already shared.
Zerops subdomain
zbox setup turns on subdomain access and adds the subdomain of port 8081 as the first domain, in the dash form. A workspace created in the Zerops GUI or with import YAML starts without a domain. Turn on subdomain access for the service, then add the second URL Zerops shows for it (the one with 8081) without https://:
Your own domain
To publish sandbox ports under your own domain, for example box.example.com:
- In the Zerops GUI, add the domain access for the workspace service with the wildcard domain
*.box.example.comand route it to port 8081 of the workspace (public access through your domain). - Point
*.box.example.comto the project's IP addresses and add the_acme-challengeCNAME record, so Zerops can issue the wildcard certificate (wildcard domains). - Add the domain to the workspace:
zbox workspace domain add box.example.com.
Each sandbox port is then reachable at https://<port>-<sandbox-id>.box.example.com/.
Without a dedicated IPv4 address, the project's own domains go through the shared IPv4, which closes every connection after about two minutes. WebSockets and long downloads to sandbox ports break for IPv4 clients. Add a dedicated IPv4 to the project if you need them.