Skip to content

Guides

Sandboxes

Markdown

Short-lived machines for one task each. A sandbox starts from a template, runs commands and holds files, and is removed at its deadline.

A sandbox is a machine with a deadline. Create it from a template, run commands in it, read and write its files, and let it go: at its deadline Rytiv removes the machine and everything on its disk. Each sandbox has an id like sbx-1a2b3c4d5e6f and its own address.

ry sandbox create app:web --ttl 30m

POST /v1/sandboxes answers when the machine runs, with 201 and the sandbox. The answer also carries createMs, the time from your request to the running machine, and, for a sandbox with signed access, an accessToken.

A sandbox boots the image of a template you already have:

Template Boots
app:<name> The image an app of your organization runs right now. The app must run a machine.
build:<id> A build of your organization that produced a machine image (not a static site).

Nothing else is inherited from the template: no environment variables and no secrets of the app. Pass what the sandbox needs in env.

Field Type Default Notes
template string required app:<name> or build:<id>
ttlSeconds integer 300 Lifetime from now, 10 to 86400
vcpus integer 1 1 to 16
memoryMb integer 512 128 to 16384
diskMb integer 512 to 131072
env object {} Up to 128 variables, names like MY_VAR. A few RYTIV_ names are reserved.
ports integer[] [] Up to 8 more ports to reach from outside
internalPort integer the template app’s port, else 3000 The port url points at
readiness boot or port boot Ready when the machine boots, or when internalPort answers
access signed or public signed Who can open the sandbox’s URLs, see Access
idleSeconds integer 300 10 to 86400, see the note below
metadata object {} Up to 16 key/value pairs for your own bookkeeping
egress object allow all Outbound network, see Network

Unknown fields are refused with 400.

Field Meaning
id sbx- and 12 hex digits
template The template it was created from
state starting, running, sleeping or ended
createdAt, expiresAt When it was created, and its deadline
endedAt, endReason When and why it ended: expired, killed, failed or app-deleted
machineId The machine behind the sandbox
vcpus, memoryMb, readiness, access, metadata, egress As requested
url https://<id>.rytiv.app
ports One {port, url} per extra port, with url like https://<port>-<id>.rytiv.app

With access: "signed" (the default), the sandbox’s URLs only answer requests that carry a token. The create answer contains one:

"accessToken": { "token": "...", "expiresAt": "...", "header": "x-rytiv-access" }

Send it in the header named by header. It is valid for the lifetime the sandbox was created with, at most 24 hours. With access: "public", anyone with the URL can open it.

ry sandbox exec sbx-1a2b3c4d5e6f -- uname -a

POST /v1/sandboxes/:id/exec waits for the command and answers with its result.

Field Type Default Notes
cmd string or string[] required A string runs through /bin/sh -c, an array is the argument list (no shell)
cwd string An absolute path
env object More environment for this command
timeoutMs integer 60000 1000 to 600000, and never past the sandbox’s deadline
stdin string Up to 1 MiB

The answer has exitCode, signal, timedOut, durationMs, stdout and stderr. Each output stream is cut at 1 MiB, and stdoutTruncated or stderrTruncated say so.

ry sandbox exec exits with the command’s own exit code, 124 on a timeout, 128 + n when signal n ended it, and 255 for an error of its own.

Method Path Body and answer
GET /v1/sandboxes/:id/files?path=/abs/path The file’s bytes
PUT /v1/sandboxes/:id/files?path=/abs/path Send the bytes. Optional mode (default 0644) and mkdirs=1. Answers {path, bytes, sha256}.
GET /v1/sandboxes/:id/files/list?path=/abs/dir {path, entries}, each entry {name, type, size, mode, mtimeMs}

Paths are absolute and may not contain ... One file is at most 64 MiB.

curl -X PUT "https://api.rytiv.app/v1/sandboxes/sbx-1a2b3c4d5e6f/files?path=/tmp/hello.txt" \
-H "Authorization: Bearer $RYTIV_TOKEN" \
--data-binary "hello"

egress decides what the sandbox may reach:

mode Meaning
allow-all The default
deny-all Nothing, not even DNS
allowlist Only the listed domains (up to 100, a leading *. allowed) and IPv4 cidrs (up to 10), on ports 80 and 443

The policy is fixed for the sandbox’s lifetime.

{ "template": "app:web", "egress": { "mode": "allowlist", "domains": ["api.github.com", "*.npmjs.org"] } }
Method Path What it does
POST /v1/sandboxes/:id/timeout {ttlSeconds}: the new deadline is now plus ttlSeconds (10 to 86400). Calling it twice does not add up.
GET /v1/sandboxes Running sandboxes, newest first. ?state=all adds the ones that ended in the last 14 days.
GET /v1/sandboxes/:id One sandbox
DELETE /v1/sandboxes/:id Ends it now. 204, or 202 if it is already ending. Its machine and disk are gone.
ry sandbox timeout sbx-1a2b3c4d5e6f 1h
ry sandbox list --all
ry sandbox kill sbx-1a2b3c4d5e6f

An organization can run 100 sandboxes at a time by default; the next create answers 429 with too-many-sandboxes.

Status Code When
404 template-not-found No such app or build in your organization
409 template-not-runnable The build is a static site, or the app runs no machine
404 sandbox-not-found No such sandbox in your organization
409 sandbox-ended, sandbox-starting The sandbox has ended, or is not running yet
429 too-many-sandboxes The organization’s limit is reached
503 no-capacity No room right now, try again

See the CLI reference for every flag of ry sandbox.