docker run, on a Linux machine with Docker Engine or on a Mac with
Docker Desktop. You install no CLI and you write no config file. Docker’s
restart policy keeps the runner running.
Builds run as containers beside the runner’s container, on the host’s
Docker. The runner image cannot run microVM builds. For those, see
Set up your first host.
Before you start
You need:- A Linux machine with Docker Engine 26 or later, or a Mac with Docker
Desktop. The engine behind Docker Desktop must also be version 26 or
later. Check it with
docker version --format '{{.Server.Version}}'. The runner image refuses to start with an older engine. On a Mac, read Docker Desktop first. - A runner key. It is an API key with the Runner preset. Create it as Give the runner its key shows.
- The factory’s id. It is the Factory ID on Settings → General.
- A Claude credential. Create a token with
claude setup-tokenon a machine where Claude Code is installed, or use an Anthropic API key.
Start the runner
-
Put the settings in a file, so they stay out of your shell history. The
file holds the runner key, so make it readable only by your account.
runner-image.env
-
Start the container. Use
--env-file, not-e: a value in-estays in your shell history.
docker inspect on the host can read the runner key and
the Claude credential. That person already controls the Docker daemon.
The variables
The file must set these variables:
These variables are optional:
The container refuses to start, and names the problem, when a required
variable is missing or a value is not valid.
The image tags
Each release has these tags:<version>, such as0.31.0. It always names that exact release.<major>.<minor>, such as0.31. It names the newest patch release of that minor version.latest. It names the same version as thelatesttag of@outerlayer/clion npm.
Check that it runs
OUTERLAYER_RUNNER_NAME.
What the volume holds
The volumeouterlayer-runner holds everything the runner keeps: its config
file, its host key and the state of its builds.
The first start writes the config file from the variables. A later start
uses the config file in the volume, and these rules apply:
- The factory, key and name cannot change. The runner refuses to start
when
OUTERLAYER_URL,OUTERLAYER_APP_ID,OUTERLAYER_API_KEYorOUTERLAYER_RUNNER_NAMEdisagrees with the volume. To move a runner to another factory, key or name, use a new volume. OUTERLAYER_BUILD_MEMORYandOUTERLAYER_CONCURRENCYreplace the value in the volume at each start. A variable you remove leaves its last value there. See Stop setting the build memory.- The Claude credential is never written to the volume. To replace it, change it in the env file and recreate the container with the same volume.
/root/.outerlayer/config.json. Edit it with docker exec. The
runner reads the file again when it changes. See
The config file.
Stop setting the build memory
A line you remove from the env file does not remove its value from the volume. The value stays inrunner.build.memory, so the runner does not fit
the build memory to the machine again.
To let the runner fit the build memory again:
-
Remove the
OUTERLAYER_BUILD_MEMORYline from the env file. -
Delete
runner.build.memoryfrom the config file in the volume: - Recreate the container with the same volume.
OUTERLAYER_CONCURRENCY works the same way. To go back to one build at a
time, delete runner.concurrency with the same command.
Docker Desktop
On a Mac, the runner image runs in Docker Desktop’s Linux VM, on Apple silicon and on Intel. Builds run as containers in that VM and recordcontainer. What a build there can reach is in
Security and limits.
Docker Desktop needs a paid Docker subscription for some companies. Read
Docker’s terms
before you choose the runner image over Lima. Lima is free. See
Run the runner on a Mac.
Size the VM
By default each build is limited to8g of memory, 4 CPUs and 40g of
disk. Docker Desktop’s default VM can be smaller. A small Linux machine gets
the same fit.
- Memory. The runner claims work only when the VM’s memory is at least
runner.concurrencytimesrunner.build.memory, plus 2 GiB. With the defaults, that is 10 GiB. When nothing sets the build memory and8gdoes not fit, the runner lowers it to fit, down to4g, and logs the value. A VM with 8 GB gives each build5g. A VM too small for4gclaims no work. - CPUs. A VM with fewer than 4 CPUs gives each build all of its CPUs.
- Disk. The runner claims work only when the VM’s disk has
runner.housekeeping.minFreeDiskfree, 40 GB by default. The VM’s disk also holds every other image and volume on the Mac.
- Set
OUTERLAYER_BUILD_MEMORYorOUTERLAYER_CONCURRENCYin the env file, and recreate the container. - Set
runner.build.cpus,runner.build.diskandrunner.housekeeping.minFreeDiskin the config file in the volume. - Set
runner.housekeeping.savedStateMaxlower. The runner keeps up to that much, 20 GiB by default, in saved states from setup scripts.
Start the runner after a reboot
Two settings bring the runner back with no one starting it:- In Docker Desktop’s settings, turn on Start Docker Desktop when you sign in.
- Start the runner container with
--restart unless-stopped, as the command above does.
interrupted, so the item can be built
again.
Operate the runner
Drain before maintenance
To let the running builds finish before you stop the runner, drain it:docker stop outerlayer-runner when no build is left.
Stop the runner
docker stop outerlayer-runner stops the runner and leaves every build
running. The container that starts next, with the same volume, takes the
builds over.
Start the next container soon. A build keeps its claim only while a runner
renews it, and the claim expires after 15 minutes. A build’s network
connections also fail while no runner runs.
Update the runner
A runner in the image does not update itself, whatever the factory’s Runner updates setting says. An update is a new image. The runner’s log,outerlayer runner status and outerlayer doctor name the tag to pull.
To update, follow The runner image on
the update page. It keeps the container’s mounts, so the new container is
the same runner. Builds survive the change.
Update before the support window
ends, 30 days after OuterLayer names a newer version. A runner outside the
window claims nothing.
Pin the image by digest
Thelatest and <major>.<minor> tags move with each release. A digest
does not move. Pin the image when a host must run one tested release until
you change it.
-
Find the digest of the version you tested:
-
Name the image by its digest in
docker run: