Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
doos
User-level containers in C++20: overlayfs, user/mount/pid namespaces, slirp4netns networking, optional images (Alpine, Ubuntu, or your own rootfs), a size cap per container. No root at runtime.
doos list
doos get_or_create [--image I] [--size S] [--net M] [--ids X] NAME
doos attach [--image I] [--size S] [--net M] [--ids X] NAME [-- CMD...]
doos delete [--yes] NAME
doos image list | add [--sha256 HEX] SOURCE [NAME] | delete [--yes] NAME
Version: see VERSION (currently 1.0.0). Release history: CHANGELOG.md.
User-level containers in C++20: overlayfs over the host's /usr, /etc, /opt, user/mount/pid namespaces, networking through slirp4netns. No root at runtime.
doos list
doos get_or_create [--net slirp|host|none] NAME
doos attach [--net slirp|host|none] NAME [-- CMD...]
doos delete [--yes] NAME
Build: cmake -S . -B build && cmake --build build. Test: tests/run.sh.
Requirements: Linux >= 5.11, slirp4netns (default network mode), uidmap (newuidmap/newgidmap, for more than one id inside; falls back to one id), curl, tar and sha256sum (images). On Ubuntu 24.04+ install the AppArmor profile once:
sudo cp apparmor/doos /etc/apparmor.d/doos && sudo apparmor_parser -r /etc/apparmor.d/doos
See SPEC.md (behavior, limits) and docs/RESEARCH.md (what works, measurements, known gaps).
Usage examples
doos attach dev # host mode: your system's /usr as base, shell as root inside
doos attach --image alpine box # first use downloads and verifies Alpine, then opens a shell
doos attach --image ubuntu web -- apt-get update
doos attach --image ubuntu-24.04 old # a specific Ubuntu release
doos attach --size 8g big # raise the writable-layer cap (default 4g)
doos attach --net none sandbox -- sh # no network at all
doos list
doos image list # what is installed, what the catalog offers
doos delete dev # dry run: shows what would go
doos delete --yes dev # really deletes
doos image delete --yes alpine # refused while a container uses it
Your own image (a root filesystem tarball):
doos image add https://example.org/debian-rootfs.tar.xz --sha256 <hex> debian # URL needs the hash
doos image add ./rootfs.tar.gz mybase # local file
doos attach --image mybase c1
Host mode or image mode
| Host mode (default) | Image mode (--image) |
|
|---|---|---|
| Base system | your /usr, /opt, copy of /etc |
the image, extracted once and shared |
| Needs a download | no | first use only |
apt-get install |
works when the host is Debian/Ubuntu based | works for the image's own package manager (apt, apk) |
| Sees host files | /usr, /opt, readable /etc at creation |
nothing from the host |
| Best for | quick throwaway shells with your tools | reproducible, separate systems |
Writes always stay in the container (copy-on-write); /root and /var persist, /tmp is memory-backed and lost on exit. A container is running while its first attach command is alive; more attach calls join it. Data persists until delete --yes.
Size cap
--size limits what a container writes (default 4g, 64m to 1t). The parent checks every 10 s: a warning at 80%, at 100% the container is frozen (nothing is deleted), and it thaws on its own below 95% after you free space with a second doos attach NAME -- .... Needs cgroup v2 delegation (standard on systemd desktops); without it the cap only warns.
Configuration
| Variable | Meaning |
|---|---|
DOOS_HOME |
State directory (default ~/.local/share/doos). No , or : allowed. |
XDG_DATA_HOME |
Used as $XDG_DATA_HOME/doos when DOOS_HOME is unset. |
Troubleshooting
| Message | Cause and fix |
|---|---|
write /proc/<pid>/uid_map ... blocked or mount ...: Permission denied |
AppArmor restricts user namespaces. Install apparmor/doos (command above). |
slirp4netns failed to start |
Install slirp4netns, or use --net none / --net host. |
subuid mapping unavailable |
Install uidmap and make sure /etc/subuid and /etc/subgid list your user, or use --ids single. |
sha256 mismatch |
The download is not what the publisher lists; nothing was installed. Retry or check the source. |
a URL image needs --sha256 |
Unverifiable input is rejected by design; pass the hash from the publisher. |
size cap only warns, cannot freeze |
No delegated cgroup v2 (no systemd user manager). Cap is advisory. |
doos: seeded ...: unreadable skipped: N |
Host entries the user cannot read were left out of the container. Informational. |
state path must not contain ',' or ':' |
Set DOOS_HOME to a plain path. |
container 'x' is running on delete |
Exit the attached command first. |
container limit reached (64) |
Delete one first. |
Safety summary
Host files are never written: system dirs are reached only through overlayfs. Host
/home, /sys and host loopback are not reachable in the default mode. Images are
verified against the publisher's checksum before they are extracted. --net host
removes network isolation and is opt-in. Known gaps (no cgroups, readable host /etc)
are listed with researched solutions (G1 to G6, not implemented) in docs/RESEARCH.md.
Project docs
| File | Content |
|---|---|
SPEC.md |
Behavior contract and limits |
docs/ARCHITECTURE.md |
Code map and flows |
docs/RESEARCH.md |
What works unprivileged, measurements, gaps |
AGENTS.md |
Rules for AI agents, release workflow |
CHANGELOG.md |
Release history |