For a team environment, add the Claude Code Dev Container Feature to .devcontainer/devcontainer.json and rebuild; that is the whole install. For CI, build a plain image with a pinned version and DISABLE_AUTOUPDATER=1. In both cases run as a non-root user, pass credentials at runtime rather than baking them into a layer, and mount a named volume at ~/.claude with CLAUDE_CONFIG_DIR pointing at it so sign-in survives a rebuild. Inside a container with restricted egress, skipping permission prompts is defensible. Accurate as of August 2026.
- One feature line installs it:
ghcr.io/anthropics/devcontainer-features/claude-code:1.0. - Mount a volume at
~/.claudeand setCLAUDE_CONFIG_DIR, or you re-authenticate every rebuild. - Run as a non-root user. The CLI refuses
--dangerously-skip-permissionsas root. - Never bake credentials into an image. Runtime environment or a mounted secret.
- Fully offline does not work: the API is a hard dependency. Use an egress allowlist.
- Do not mount
~/.sshor cloud credential files into an agent container.
The one-line dev container install
If your team already uses dev containers, this is the entire installation. The feature works with anything that supports the Dev Containers specification, including VS Code, GitHub Codespaces, JetBrains IDEs and Cursor.
{
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
"features": {
"ghcr.io/anthropics/devcontainer-features/claude-code:1.0": {}
}
}
Rebuild
In VS Code, open the Command Palette with <kbd>Cmd</kbd>+<kbd>Shift</kbd>+<kbd>P</kbd> or <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>P</kbd> and run Dev Containers: Rebuild Container. In Codespaces or the Dev Containers CLI, use the equivalent rebuild action.
Sign in inside the container
claude
If the browser sign-in completes but the callback never reaches the container, copy the code shown in the browser and paste it at the Paste code here if prompted prompt. That is a port-forwarding artefact, not a failure.
A plain image, for CI
A pipeline does not want a feature that always installs the newest release. Build the version you tested.
FROM node:22-bookworm-slim
RUN apt-get update && apt-get install -y --no-install-recommends \
git curl ca-certificates ripgrep less \
&& rm -rf /var/lib/apt/lists/*
ARG CLAUDE_VERSION=2.1.89
RUN npm install -g @anthropic-ai/claude-code@${CLAUDE_VERSION}
ENV DISABLE_AUTOUPDATER=1
# An agent that can write to system paths is a worse agent, not a better one.
RUN useradd -m -s /bin/bash agent
USER agent
WORKDIR /workspace
ENTRYPOINT ["claude"]
docker build -t claude-agent .
docker run --rm -it \
-v "$PWD:/workspace" \
-e ANTHROPIC_API_KEY \
claude-agent
Credentials that survive a rebuild
By default the container home directory is discarded on rebuild, so every engineer signs in again every time. The fix has two halves and skipping either one leaves you signed out.
"mounts": [
"source=claude-code-config-${devcontainerId},target=/home/node/.claude,type=volume"
],
"containerEnv": {
"CLAUDE_CONFIG_DIR": "/home/node/.claude"
}
- Codespaces keeps
~/.claudeacross stop and start, but clears it on rebuild, so the same configuration applies. - To carry authentication across codespaces, store
ANTHROPIC_API_KEY, or aCLAUDE_CODE_OAUTH_TOKENfromclaude setup-token, as a Codespaces secret. Secrets appear as environment variables inside the container automatically. - Cloud providers pass credentials through
containerEnv, a Codespaces secret, or workload identity. Do not mount credential files from the host.
Restricting what the container can reach
If the agent will run code you have not read, which is the normal case the moment it installs a dependency, limit where the container can go. Start from the list of hosts Claude Code genuinely needs.
The core allowlist. Verified against the network reference, August 2026.
| Host | Needed for |
|---|---|
api.anthropic.com | Model requests, feature flags, telemetry events |
claude.ai and claude.com | Account sign-in |
platform.claude.com | Console sign-in, and OAuth token exchange and refresh |
downloads.claude.ai | Native installer, auto-updater, plugin downloads |
registry.npmjs.org | Only if you install or update through npm |
mcp-proxy.anthropic.com | Only if you use claude.ai connectors |
The reference dev container ships an init-firewall.sh that blocks everything outbound except the domains Claude Code and your toolchain need. Running a firewall inside a container needs extra privileges, so the reference grants NET_ADMIN and NET_RAW through runArgs. Neither the script nor those capabilities is required by Claude Code itself; if you already control egress at your own network boundary, leave them out.
The permission argument
On a laptop, approval prompts are the only thing between an agent and your filesystem, your SSH keys and your shell history. In a container with only the repository mounted and egress restricted, the blast radius is the repository and you can throw the container away.
docker run --rm -it \
-v "$PWD:/workspace" \
-e ANTHROPIC_API_KEY \
claude-agent --dangerously-skip-permissions
What the container boundary is actually buying you.
| Risk | On the host | In a container |
|---|---|---|
| Destructive command outside the repo | Real | Contained |
| Reading SSH keys or shell history | Possible | Not mounted, if you did not mount them |
| Installing packages globally | Affects your machine | Thrown away |
| Network egress | Unrestricted | Restrictable |
Exfiltrating the Claude credential in ~/.claude | Real | Real |
| Damage to the repository itself | Real either way | Real either way |
- The CLI refuses the flag as root. Confirm
remoteUseris a non-root account, or the flag simply will not run. - Want fewer prompts without turning them off? Auto mode has a classifier review actions before they run, which is the middle setting most teams actually want.
- To forbid the flag entirely, set
permissions.disableBypassPermissionsModeto"disable"in managed settings.
Policy that travels with the image
A container is a convenient place to apply policy, because the same image runs on every machine. On Linux, Claude Code reads /etc/claude-code/managed-settings.json at the highest precedence in the settings hierarchy.
RUN mkdir -p /etc/claude-code
COPY managed-settings.json /etc/claude-code/managed-settings.json
"containerEnv": {
"CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1",
"DISABLE_AUTOUPDATER": "1"
}
Questions people ask
Install it into an image with npm at a pinned version, set DISABLE_AUTOUPDATER=1, run as a non-root user, mount your repository at the working directory, and pass credentials as runtime environment variables rather than baking them into a layer.
Add ghcr.io/anthropics/devcontainer-features/claude-code:1.0 to the features block of .devcontainer/devcontainer.json and rebuild the container. The feature also installs the VS Code extension when you open the container in VS Code or Codespaces.
Because the container home directory is discarded. Mount a named volume at ~/.claude and set CLAUDE_CONFIG_DIR to the same path, so the separate ~/.claude.json file that holds your account also lands inside the volume.
More defensible than anywhere else, because the boundary limits the damage to what you mounted. It still does not protect the repository or the Claude credential inside the container, so use it with trusted repositories, restrict egress, and commit before an unattended run.
Use remoteEnv with ${localEnv:ANTHROPIC_API_KEY} in devcontainer.json, which reads the variable from your machine at start, or store it as a Codespaces secret. Either way it never enters the image or the repository.
No. Model requests to api.anthropic.com are a hard dependency. An egress proxy that allows the Anthropic hosts plus your package registry, and denies everything else, is the workable version of this.
No. The repository is mounted read-write, which is the point. The container protects your machine and everything you chose not to mount, which is why mounting ~/.ssh into an agent container defeats the exercise.
Yes, and disable the auto-updater in the same step. The Dev Container Feature always installs the newest release, so a build that must be reproducible installs the CLI from the Dockerfile at an explicit version instead.
Sources
Every figure above was read from these pages on August 2026. Vendors reprice without notice; if you find a stale number, tell us.