Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

17 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ClaudeBox

ClaudeBox

Run Claude Code in a sandboxed Docker container.

How it works: claudebox is a Bash wrapper around a single docker run — no daemon, no background process. Each time you run it, the script:

  1. Splits the arguments — its own flags (--docker, --ssh, -p, --build, …) are handled locally; everything else is passed straight through to claude in the container.
  2. Ensures the image exists — builds it on first run (docker build), reuses it after; --build forces a rebuild.
  3. Assembles the docker run, mainly:
    • mounts your project at its real host path (not /workspace) and works there, so file paths and ~/.claude/projects/<path> session files line up with a native claude run;
    • mounts ~/.claude (and ~/.claude.json) so config, memory, and auth persist — on macOS it reads your Keychain token and forwards it in as an env var;
    • by default adds --cap-add=NET_ADMIN plus an env flag that tells the container to firewall off your LAN; -p, --ssh, and --docker/--host-docker add ports, the SSH agent, and Docker access;
    • allocates a TTY so the session is interactive.
  4. Hands off to the container's entrypoint, which installs the LAN firewall, then drops NET_ADMIN before launching Claude (so Claude can't undo it), optionally starts a rootless Docker daemon, and finally execs claude with your passed-through arguments.

Net effect: the same Claude on your real files, with config/memory persisted, the network sandboxed to internet-only, and Docker off unless you opt in — isolated enough to run --dangerously-skip-permissions. See Sandboxing for specifics.

Note (macOS): If you use a Claude subscription (Pro/Max), your auth token lives in the macOS Keychain, which the container can't read directly. claudebox reads it and forwards it into the container automatically, so auth just works. If that ever fails (you'll see a warning), run /login once inside the container — the token is then saved to ~/.claude and persists across sessions.

Prerequisites

  • Docker installed and running

Prebuilt images

Each release is published to GitHub Container Registry for linux/amd64 and linux/arm64, so you can skip the local build. You still need the claudebox wrapper script (see Setup below) — the prebuilt image just saves it from building one.

Pull a release and tag it as the local image the wrapper looks for:

docker pull ghcr.io/startswithaj/claudebox:latest
docker tag ghcr.io/startswithaj/claudebox:latest claudebox

Now run claudebox as usual — it finds the local claudebox image and won't rebuild. Pin a specific version with a tag like :v1.0.0 instead of :latest. To update later, re-pull and re-tag.

The prebuilt image includes all optional languages (Go, Python, Rust). For a smaller image — or to go back to building from source — run claudebox --build (see Custom builds).

Setup

  1. Clone the repo:
git clone https://github.com/youruser/claudebox.git
  1. Add it to your PATH (pick one):
# bash
echo 'export PATH="$PATH:$HOME/claudebox"' >> ~/.bashrc
source ~/.bashrc

# zsh
echo 'export PATH="$PATH:$HOME/claudebox"' >> ~/.zshrc
source ~/.zshrc

Adjust the path if you cloned it somewhere other than $HOME/claudebox.

  1. (Optional) Alias claude to claudebox:
# bash
echo 'alias claude="claudebox"' >> ~/.bashrc
source ~/.bashrc

# zsh
echo 'alias claude="claudebox"' >> ~/.zshrc
source ~/.zshrc

Usage

# Just run it — the Docker image builds automatically on first launch
claudebox

All arguments are passed through to Claude Code:

claudebox --resume
claudebox --print "explain this repo"
claudebox --model sonnet

Tip: While Claude's interactive UI is running, the terminal captures the mouse, so a normal click-drag won't select text. Hold Option (⌥) while dragging to select and copy in macOS terminals (iTerm2/Terminal.app); on most Linux terminals it's Shift.

Port forwarding

Publish a port so you can reach a server Claude starts inside the container. For example, if Claude runs a web frontend on port 3000 in the container, map it out and open it in your browser:

claudebox -p 3000:3000
# then visit http://localhost:3000 on your machine

The format is -p HOST:CONTAINER. Repeat the flag for multiple ports — say a frontend and its API:

claudebox -p 3000:3000 -p 8080:8080

SSH agent forwarding

Forward your local SSH agent into the container for git operations over SSH:

claudebox --ssh

Custom builds

Rebuild the image at any time:

claudebox --build

Only include specific languages to keep the image smaller:

claudebox --build --with go,python
claudebox --build --with rust

Available tools: go, python, rust. All are included by default.

Node.js and npm are always included as they are required by Claude Code.

Combining flags

Claudebox flags and Claude flags can be mixed freely:

claudebox --ssh -p 3000:3000 --docker --resume

Flags

Flag Description
--docker Start an isolated rootless Docker daemon inside the container (safe; host Docker untouched)
--host-docker Mount the host Docker socket — grants host-root power and escapes the sandbox; use only when you need the host's daemon
--allow-lan Allow the container to reach your local network (the LAN firewall is on by default)
--ssh Forward your local SSH agent into the container for git over SSH
-p, --port <host:container> Publish a container port to your host so you can reach it — e.g. -p 3000:3000, then open http://localhost:3000 (repeatable)
--build (Re)build the image before launching
--with <list> With --build, include only these optional languages: go, python, rust
--help, -h Show usage and exit

Any other arguments are passed straight through to Claude Code (e.g. --resume, --model, --print, --dangerously-skip-permissions).

Sandboxing

claudebox is built to run Claude — including in --dangerously-skip-permissions mode — without giving it a path to your local network or host machine.

Network isolation

By default, egress to private/LAN ranges (10/8, 172.16/12, 192.168/16, 169.254/16) is dropped inside the container, so Claude can reach the public internet but not other machines on your network, your router's admin page, or cloud metadata endpoints. DNS still works (the container's own resolvers are allowlisted).

The firewall is installed by the container's entrypoint, which then drops the CAP_NET_ADMIN capability before launching Claude — so Claude itself cannot flush or alter the rules, even running as root.

Allow LAN access if you actually need it (e.g. hitting a service on your host):

claudebox --allow-lan

Docker access

Claude has no access to Docker unless you opt in. Two modes:

# Isolated, rootless Docker daemon inside the container. Safe: it has its own
# image cache and containers, can't see or touch your host's Docker, and a
# breakout from a nested container lands in the sandbox, not on your host.
claudebox --docker

# Mount the host's Docker socket. DANGEROUS: this is effectively root on your
# host — it lets the container escape the sandbox and bypass the LAN firewall.
# Only use it when you specifically need the host's daemon (e.g. pushing to a
# local registry or driving the host's Kubernetes) and trust the session.
claudebox --host-docker

--docker is the right choice for most "Claude needs to build/run a container" tasks. Reach for --host-docker only when the work genuinely targets the host's Docker.

What's in the box

The base image always includes:

  • Node.js 24 + npm (required by Claude Code)
  • Git, git-lfs, ssh
  • Build tools (gcc, cmake, pkg-config)
  • Search tools (ripgrep, fd, jq)
  • Claude Code CLI
  • Deno
  • Rootless Docker (daemon + CLI, started on demand with --docker)

Optional (included by default, configurable with --with):

  • Go 1.24
  • Python 3 + pip + venv
  • Rust (stable via rustup)

Testing

test/run.sh builds a lean image and verifies the sandbox end to end — the firewall rules, the CAP_NET_ADMIN drop, internet egress, LAN blocking, and rootless Docker (--docker). Run it after changing the Dockerfile, the entrypoint, or the claudebox wrapper:

test/run.sh

It exits non-zero if any check fails. On hosts that block the user-namespace mapping rootless Docker needs (e.g. some nested CI containers), the rootless test automatically falls back to --privileged and says so — normal claudebox --docker runs unprivileged.

About

Sandboxed Claude Code in Docker — same experience, isolated environment.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages