Skip to main content

Define once.
Run anywhere.
No host daemon.

Write one TOML file. podbox turns it into a container image and a few systemd units, then gets out of the way. Nothing of podbox keeps running on your machine.

dev.tomlyou write this
[image]
name = "dev"
base = "fedora:44"
 
[image.packages]
install = ["neovim", "ripgrep", "gcc"]
 
[integration]
wayland = true
audio = true
gpu = "auto"
$ podbox build devimage + units
~/.config/containers/systemd/dev.container
[Container]
ContainerName=dev
Image=localhost/podbox-dev:latest
UserNS=keep-id
Volume=/home/you/containers/dev:/home/you:Z
AddDevice=/dev/dri
 
[Install]
WantedBy=default.target
The TOML on top is the whole configuration. podbox build turns it into an image and Quadlet unit files that systemd runs.

Install

One static binary. Use whichever channel you already have.

bash
1# Grab the binary & verify
2curl -fsSL https://bethropolis.github.io/podbox/install.sh | sh
bash
1# Install as a mise tool (Linux only)
2mise use -g github:bethropolis/podbox
bash
1# Homebrew (Linux only)
2brew install bethropolis/homebrew-tap/podbox
bash
1# Arch Linux, via AUR (binary, fast)
2paru -S podbox-bin
3 
4# ...or build from source
5paru -S podbox
bash
1# From crates.io (supports prebuilt images only)
2cargo install podbox-cli

Note: the crates.io build supports prebuilt images only (image_ref in your config, or podbox create ghcr.io/bethropolis/podbox:<tag>). Custom image builds need a full source build from the workspace.

bash
1# Source install (builds CLI & guest daemon)
2git clone https://github.com/bethropolis/podbox
3cd podbox && scripts/install.sh # installs to ~/.local/bin
first run
1# Spin up a prebuilt Fedora container and hop in
2podbox create fedora
3podbox enter fedora
The first run uses a prebuilt image, so no config file is needed.Read the Getting Started guide

A container you can rebuild from a file

Your home directory stays out of it unless you ask. Everything the container can reach is written down first.

One TOML file

Image, packages, mounts and runtime in a single file you can commit. No flags to retype.

base = "fedora:44"

systemd runs it

Autostart, restarts and socket activation come from systemd. No podbox process stays behind.

systemctl --user status dev.service

Your screen and sound

GUI apps and games work, GPU included. Wayland, PipeWire and graphics are wired up for you.

wayland = true · gpu = "auto"

Filtered D-Bus

The session bus is not handed over whole. Only the names you allow reach the host.

talk = ["org.freedesktop.Notifications"]

Apps without a shared home

Put a desktop entry in your launcher or a tool on your PATH, with no home directory shared.

podbox export app code

Fast starts

Packages are baked into the image at build time, so starting a container installs nothing.

install = ["neovim", "ripgrep", "gcc"]

podbox, Distrobox, or raw podman

Distrobox shares your home and gets out of the way. podbox shares nothing until you write it down.

Your files
Isolated by default
DistroboxWhole $HOME mountedpodmanManual -v flags
Config
One TOML file
DistroboxCommand-line flagspodmanFlags every run
Lifecycle
systemd units
DistroboxWrapper scriptspodmanYou start it
Desktop bus
Filtered proxy
DistroboxWhole session buspodmanWhole session bus
Screen, sound, GPU
Shared, GPU optional
DistroboxShared by defaultpodmanManual device flags
Alerts, clipboard
Works, no shared bus
DistroboxVia the shared buspodmanNot supported
Host commands
Opt-in and filtered
Distroboxdistrobox-host-execpodmanNot supported
Built-in packages
Baked into the image
DistroboxReinstalled each buildpodmann/a
Reproducible
Yes, from the file
DistroboxPartly, image onlypodmanNo
Runtimes
Podman only
DistroboxPodman, DockerpodmanAny

Both are reasonable choices. Distrobox optimises for feeling like the host; podbox optimises for reproducing the same environment from a file.

How it works

Two moments matter: when you build, and while the container runs. Select a box to see what that part does.

podbox.tomlYou write thispodbox buildPure codegen, no daemonOCI ImagePackages baked inQuadlet units.container .socket .build+ companion servicessystemd --userOwns the lifecycle
runs once, then exits

podbox build

Reads the TOML and writes two kinds of output: a Containerfile for the image and Quadlet unit files for systemd. Generation is a pure function of the config, so the same file always produces the same output.

Architecture docs
  • TOML → Containerfile + .container / .socket / .build units
  • The guest binary is copied into the build context
  • podbox build --dry-run prints everything without writing

Try a config

Flip a switch and watch the podbox.toml and the .container unit change. Studio covers every option.

The basics
Name

Used for the container, its folder and its systemd unit.

Base image
Packages to install

Baked into the image, separated by commas.

What the container can use
Graphics
GPU access
Your config
Open in Studio
# the real podbox engine is loading…

The commands you will actually use

Most days it is build, enter, and the occasional export. The rest is plain systemd.

Build the image

# Build, or rebuild after editing the config
podbox build dev
 
# Point at a config file anywhere
podbox --config ./podbox.toml build

Get in, or run one command

# Start it if needed and open a shell
podbox enter dev
 
# Run a single command without a shell
podbox -C dev exec cargo check

Put an app on your desktop

# Add an app to your host launcher
podbox -C dev export app code
 
# Put a CLI tool on your host PATH
podbox -C dev export bin rg

See what it is doing

podbox status dev
podbox logs dev --follow
 
# It is an ordinary systemd user service
systemctl --user status dev.service

Before you start

What you need

  • Podman 5.5 or newer5.6+ for SSH agent passthrough
  • A systemd user session
  • Linux with a Wayland compositorX11 apps run through Xwayland
  • xdg-dbus-proxy, for filtered D-Busoptional

Something not working?

Run podbox doctor first. It catches most setup problems on its own, and the troubleshooting guide goes deeper.

bash
podbox doctor