# How to start a sandbox from a private registry image Store the registry's credential once with `runtime image registry set`, then build from the private image and start sandboxes from it. **On Runtime the credential is sealed to the servers the moment it arrives: no call returns it, and the API that stored it cannot read it back.** A build opens it only to pull, inside its own build machine, so neither your sandboxes nor your agent ever hold the registry token. Docker Hub, GitHub, Google, Amazon ECR and any other registry that takes a user name and token work ([private registries](/docs/images#private-registries), checked 25 September 2026). ## Store the credential Every CLI form reads the secret from standard input, so it never lands in your shell history or on a command line. ```bash no-run echo "$GHCR_TOKEN" | runtime image registry set ghcr.io --username my-user echo "$AWS_SECRET_ACCESS_KEY" | runtime image registry set 123456789012.dkr.ecr.us-east-1.amazonaws.com --access-key-id AKIA... runtime image registry ls ``` From code, keep the token in your own secret store and pass it through an environment variable: ```ts check import { Runtime } from "withruntime"; const runtime = new Runtime(); await runtime.images.registries.set({ registry: "ghcr.io", username: "my-user", password: process.env.GHCR_TOKEN ?? "", }); console.log(await runtime.images.registries.list()); // never the token ``` ```python check import os from withruntime import Runtime runtime = Runtime() runtime.images.registries.set("ghcr.io", username="my-user", password=os.environ.get("GHCR_TOKEN", "")) print(runtime.images.registries.list()) ``` ## What each registry needs | Registry | Give | | ------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | | Docker Hub (`docker.io`) | Your user name and an access token | | GitHub (`ghcr.io`) | Your user name and a token that can read packages | | Google (`gcr.io`, `*-docker.pkg.dev`) | `_json_key` and the service account key's JSON, or `oauth2accesstoken` and an access token | | Amazon ECR (`.dkr.ecr..amazonaws.com`) | An access key id and secret allowed `ecr:GetAuthorizationToken` and pull; each build asks ECR for a fresh token | | Any other | A user name and a token or password | An account holds up to 20 registry credentials. Remove one with `runtime.images.registries.delete(registry)`. ## Build from the private image A sandbox starts from a Runtime image, so the private image goes through one build. Use it as it is: ```ts check import { Runtime } from "withruntime"; const runtime = new Runtime(); await runtime.images.build({ name: "app", image: "ghcr.io/acme/app:1.4.2" }); await using sbx = await runtime.sandboxes.create({ image: "app" }); console.log((await sbx.exec("cat /etc/os-release")).stdout); ``` ```python check from withruntime import Runtime runtime = Runtime() runtime.images.build(name="app", image="ghcr.io/acme/app:1.4.2") with runtime.sandboxes.create(image="app") as sbx: print(sbx.exec("cat /etc/os-release").stdout) ``` ```bash no-run runtime image build --from ghcr.io/acme/app:1.4.2 --name app runtime sandbox create --image app ``` The same stored credential covers `FROM` in a [Dockerfile](/how-to/build-an-image-from-a-dockerfile), `COPY --from=` and a [recipe's](/how-to/build-an-image-from-a-recipe) `base`. So a private base image with a few packages on top is one build: ```ts check import { Runtime } from "withruntime"; const runtime = new Runtime(); await runtime.images.build({ name: "app-tools", recipe: { base: "ghcr.io/acme/app:1.4.2", apt: ["jq"], pip: ["pytest"] }, }); ``` A program in the sandbox is found on the image's own `PATH`, so `python` in an image built from `python:3.12-slim` runs as it does there. ## Keep it current Each build of a name is its next version and takes `latest`, or the tags you give. When the registry publishes 1.4.3, build again with the same `name`: sandboxes that ask for `app` get the new version, and ones already running keep theirs. Pin with `app@2` or a tag such as `app:prod` ([names, versions and tags](/docs/images#names-versions-and-tags)). ## Mistakes to avoid - **A GitHub token without package read access.** The pull is refused. Make a token that can read packages. - **Putting the token in a Dockerfile or build argument.** It would be in the image. Store it as a registry credential, which a build opens only to pull. - **An ECR login token instead of an access key.** Give an access key id and secret that may call `ecr:GetAuthorizationToken`; each build asks ECR for a fresh token itself. - **Giving the sandbox registry access to pull at run time.** It does not need it: the image is already built. If code in the sandbox must call a private API, use a [secret it never sees](/docs/security#secrets-sandboxes-never-see) scoped to that host. Building is free and uses no trial hours. A stored image costs $0.08 per decimal GB per 30-day month on its whole file, shared base included, and the trial keeps its first three images free ([pricing](/docs/pricing#snapshots-images-and-volumes)). For containers the sandbox runs itself, see [Docker in a sandbox](/how-to/run-docker-in-a-sandbox). Facts on this page were checked on 25 September 2026.