# Use a sandbox as your own template

> Set up one sandbox with your packages, repo and system libraries, pause it, and start every job as a fork of it, set up and running in a second or two.

URL: https://prized.dev/docs/sandboxes-own-template

Sandboxes start from [two fixed templates](https://prized.dev/docs/sandboxes#templates), and there are no templates from your own image yet. A paused sandbox does the same job: set it up once, pause it, and fork it for each job. Each copy starts with its files, memory and running processes in a second or two, instead of repeating the install.

The steps use the `prized` CLI, signed in or with `PRIZED_API_KEY` set ([CLI](https://prized.dev/docs/cli#sandboxes)), on a workspace that has paid in: on the [free tier](https://prized.dev/docs/sandboxes#free-tier) a sandbox gets 60 minutes of running in all, and copies keep the parent's deletion time.

## 1. Set it up once [#1-set-it-up-once]

```bash
TPL=$(prized sandbox create --vcpu 2 --memory 4 --label role=template --env LD_LIBRARY_PATH=/home/prized/sysroot/usr/lib/x86_64-linux-gnu)
prized sandbox exec $TPL --timeout 10m -- 'python3 -m venv ~/.venv && ~/.venv/bin/pip install pandas playwright && ~/.venv/bin/playwright install chromium'
prized sandbox exec $TPL --timeout 10m -- 'git clone --depth 1 https://github.com/expressjs/express && cd express && npm install'
```

Everything goes in `/home/prized`, since there is no sudo: Python packages in a venv, and `npm install -g` after `npm config set prefix ~/.local`. The `--env` is for step 2. Copies keep the template's shape, and a small shape fits more of them ([Fork](https://prized.dev/docs/sandboxes#fork)).

## 2. Add system packages without root [#2-add-system-packages-without-root]

`apt-get install` needs root, but apt can download packages as `prized` and unpack them in your home. Save this script:

```bash title="apt-home.sh"
set -e
shopt -s nullglob
mkdir -p ~/apt/lists/partial ~/apt/archives/partial ~/sysroot
cat > ~/apt/apt.conf <<EOF
Dir::State::Lists "$HOME/apt/lists";
Dir::Cache "$HOME/apt";
Dir::Cache::archives "$HOME/apt/archives";
Debug::NoLocking "true";
EOF
export APT_CONFIG=~/apt/apt.conf
apt-get update -qq
apt-get install --download-only -y -qq --no-install-recommends "$@"
for f in ~/apt/archives/*.deb; do case "$f" in */libc6_*|*/libc-bin_*) continue;; esac; dpkg -x "$f" ~/sysroot; done
LIB=~/sysroot/usr/lib/x86_64-linux-gnu
for f in $(find "$LIB" -mindepth 2 -name '*.so*'); do [ -e "$LIB/${f##*/}" ] || ln -s "$f" "$LIB/"; done
mkdir -p ~/.local/share && ln -sfn ~/sysroot/usr/share/fonts ~/.local/share/fonts
```

Run it with the packages you need, here the libraries Playwright's Chromium needs, and ffmpeg:

```bash
prized sandbox cp apt-home.sh $TPL:apt-home.sh
prized sandbox exec $TPL --timeout 10m -- 'bash apt-home.sh libnss3 libnspr4 libatk1.0-0t64 libatk-bridge2.0-0t64 libcups2t64 libdrm2 libxkbcommon0 libxcomposite1 libxdamage1 libxfixes3 libxrandr2 libgbm1 libasound2t64 ffmpeg'
```

Programs land in `~/sysroot/usr/bin` (run `~/sysroot/usr/bin/ffmpeg`), fonts where apps look for yours, and libraries where the create's `LD_LIBRARY_PATH` looks, for every command in the sandbox and its copies. Most libraries and command-line tools work this way; a tool that reads its data from a fixed path under `/usr/share` or `/etc` needs pointing at `~/sysroot`, and a package that needs its install scripts to run, such as a system service, does not work.

## 3. Pause it [#3-pause-it]

```bash
prized sandbox pause $TPL --wait
```

Paused, it keeps its memory, disk and processes and bills paused storage only: a 2 vCPU, 4 GB sandbox with the 10 GB disk holds 14 GB of it, and the first 20 GB are included ([Billing: Sandboxes](https://prized.dev/docs/billing#sandboxes)). It is kept until you delete it ([Paused retention](https://prized.dev/docs/sandboxes#paused-retention)), and still counts against your workspace's CPU and memory quota.

## 4. Start each job as a fork [#4-start-each-job-as-a-fork]

```bash
JOB=$(prized sandbox fork $TPL)
prized sandbox exec $JOB --cwd express -- npm test
prized sandbox rm $JOB
```

The copy has the venv, Chromium, ffmpeg and the installed repo, and any process the template had running; the template stays paused. The first fork of a template takes a few seconds longer, and `--count` makes several at once. Each copy is an ordinary sandbox, billed per second at the template's shape with its own run time.

> Every copy starts from the template's memory, clock included: restart anything that makes keys, tokens or IDs, and allow about 30 seconds before anything that checks or signs with the time, HTTPS included ([Do copies share randomness or identity?](https://prized.dev/docs/sandboxes-faq#do-copies-share-randomness-or-identity)).

## When a fork does not fit [#when-a-fork-does-not-fit]

Copies start on the template's machine, so a busy machine can fit fewer than you ask for, or none ([Fork](https://prized.dev/docs/sandboxes#fork)). Fork as many as fit, try again later, or set up a second template: keep steps 1 to 3 in a script, so that is one command.

## Change or replace it [#change-or-replace-it]

Run jobs only in copies: whatever a command leaves on the template reaches every later fork. To change it, run commands on it (the first resumes it) and pause it again; to start over, set up a new one and delete the old with `prized sandbox rm`. Keep the setup script: a paused sandbox lives on one machine and is lost if that machine fails.
