Custom images
Sandboxes run an OCI image. By default that’s firebrick-base of the installed
Firebrick version, ghcr.io/wmeints/firebrick-base:v<version>. Point image in
.firebrick.yml at another image to give a project the tools it needs from the
start.
What firebrick-base contains
Section titled “What firebrick-base contains”The base image is built from the
Dockerfile in the
repository, for linux/amd64 and linux/arm64:
- Ubuntu 26.04 with
build-essential,curl,git,gpg,libicu78(ICU for .NET apps such as the Aspire CLI),libssl-dev,pkg-config,procps,python3,sudo,tcpdumpand tini. - mise, activated for bash, with its shims on the
PATH. - The Docker engine with the
buildxandcomposeplugins. - An
agentuser with UID1000and GID1000, home directory/home/agent, passwordlesssudoand membership of thedockergroup. The image’subuntuuser is removed. - An
/sbin/initthat disables guest IPv6 (see Networking), startsdockerdand the network logger in the background and hands PID 1 to tini, which reaps zombie processes. firebrick-netlog, the network logger, which reports the domains and IP addresses the sandbox contacts tofbkd. It logs to/var/log/firebrick-netlog.log. See Recording network activity.xdg-openand$BROWSERpointing atfirebrick-open, which opens URLs in the browser on your host.firebrick-git-credential, the git credential helper for github.com that hands git theGH_TOKENorGITHUB_TOKENplaceholder. See Git over HTTPS.
Docker runs directly on the sandbox VM and keeps its images and containers on
the sandbox’s own disk at /var/lib/docker, so they survive fbk stop and fbk start. agent can run docker, docker compose and docker buildx without
sudo. When dockerd fails to start, the reason is in /var/log/dockerd.log.
Building on firebrick-base
Section titled “Building on firebrick-base”The simplest custom image starts from the base image and adds a toolchain. This
Dockerfile installs Python and uv with mise, for every shell of the agent
user:
FROM ghcr.io/wmeints/firebrick-base:v0.7.0
RUN mise use -g python@3.13 uv@latest
USER rootRUN apt-get update \ && apt-get install -y --no-install-recommends postgresql-client \ && rm -rf /var/lib/apt/lists/*USER agentThe base image’s user is agent, so switch to root for system packages and
back to agent at the end.
Build the image and push it to a registry the sandbox can pull from, such as the GitHub Container Registry:
docker build -t ghcr.io/<you>/my-sandbox:1 .docker push ghcr.io/<you>/my-sandbox:1Then point the project’s .firebrick.yml at it:
name: my-projectimage: ghcr.io/<you>/my-sandbox:1The image applies when the sandbox is created, so recreate an existing sandbox:
fbk rm --forcefbk startBringing your own image
Section titled “Bringing your own image”Firebrick runs everything in a sandbox as the agent user. An image that isn’t
based on firebrick-base must:
- Have a user named
agentwith UID1000and GID1000and a home directory, such as/home/agent. Images based on Ubuntu ship anubuntuuser with UID 1000; remove it first. - Set
USER agent.fbk runruns commands as the image’s user, while SSH always logs in asagent. - Install
sudoand allowagentto use it without a password, if agents should be able to install system packages. - Provide an executable
/sbin/init, or setinit: falsein.firebrick.yml. Withiniton, which is the default, Firebrick runs/sbin/initas PID 1, andfbk startfails with a hint when the image has none. - Add
agentto thedockergroup and startdockerdfrom/sbin/init, if agents should be able to rundockerwithoutsudo. Firebrick attaches a disk for Docker’s data at/var/lib/dockerto every sandbox. - Copy
/usr/local/sbin/firebrick-netlogfrom the base image’sDockerfile, installpython3andtcpdump, and start the logger as root from/sbin/init, if Firebrick should record the network activity of the sandbox. Without it, the sandbox’s network record stays empty.
The workspace is mounted at /workspaces/<leaf>, and its files show up as owned
by agent, whatever the UID of your user on the host is.
For another distribution, create the user yourself, and set init: false in
.firebrick.yml or add an init like the base image’s:
FROM alpine:3.22
RUN apk add --no-cache bash git sudo \ && addgroup -g 1000 agent \ && adduser -D -u 1000 -G agent -s /bin/bash agent \ && echo "agent ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/agent
USER agentWORKDIR /home/agentname: my-projectimage: ghcr.io/<you>/my-alpine-sandbox:1init: falseWith init: false, nothing disables guest IPv6, so on hosts without IPv6
internet access the sandbox can’t download from servers that have an IPv6
address. Nothing starts dockerd either, and docker reports Cannot connect to the Docker daemon; start it in the background with sudo sh -c 'dockerd >/var/log/dockerd.log 2>&1 &'. Nothing starts the network logger
either, so Firebrick records no network activity for the sandbox.
Sandboxes created by an older version of Firebrick run ubuntu:26.04, which has
no agent user, so SSH can no longer log in to them. Recreate them with fbk rm and fbk start, or connect with ssh root@<name>.fbk.