Claude Container

A simple, secure, containerized sandbox for unleashing Claude Code with configurable network restrictions, persistent configuration, and comprehensive development tools.

Views1
PublishedJan 14, 2026

Loading actions...

5 minBeginnerpromptSingle file

Skill content

Main instructions and any bundled files for this skill.

markdown

Claude Container

A simple, secure, containerized sandbox for unleashing Claude Code with configurable network restrictions, persistent configuration, and comprehensive development tools.

Overview

Claude Container provides a Docker-based sandbox environment that includes:

  • Security: Network firewall restricting outbound connections to approved domains only
  • Persistence: Your Claude authentication and configuration persist across sessions
  • Development Tools: Complete development environment with pinned tool versions
  • Project Isolation: Each project runs in a clean environment while preserving your settings
  • Smart Mounting: Current directory is mounted at the same path inside the container for seamless tool compatibility
  • Customizable: Easily update your docker environment to add tools or change versions.

Features

Network Security

Claude Container offers three firewall modes to balance security and usability:

--allow-outgoing (Default)

  • Allows all HTTP/HTTPS outbound traffic
  • Blocks other protocols (FTP, SSH to external hosts, etc.)
  • Ideal for general development work that requires broad internet access
  • Supports local development server ports (3000-9000)

--strict

  • Blocks all outbound connections by default
  • Allows connections only to essential services:
    • GitHub (API, web, git, and raw content)
    • GitLab (API, web, git, and raw content)
    • NPM registry
    • Python Package Index (PyPI)
    • Rust crates registry
    • Anthropic API
    • Statsig telemetry
  • Restricts DNS queries to the container's local DNS resolver (127.0.0.11) provided by Docker's networking layer, preventing DNS tunneling attacks that require direct access to external DNS servers
  • Supports local development server ports (3000-9000)
  • Add custom domains via ADDITIONAL_ALLOWED_DOMAINS environment variable
  • Provides maximum security for sensitive development environments

--no-firewall

  • Completely disables network restrictions
  • Allows all network traffic (HTTP, HTTPS, SSH, FTP, etc.)
  • Use with caution in trusted environments only
  • Useful for specialized development scenarios requiring unrestricted access

Development Environment

Languages & Runtimes:

  • Node.js 20.19.4
  • Python 3.13.7 (with pip, venv, uv package manager)

Version Control:

  • Git
  • GitHub CLI (gh)
  • Git Delta (enhanced diff viewer)

Databases:

  • PostgreSQL client
  • MySQL client
  • SQLite3

Claude Tools:

  • Claude CLI
  • CCUsage (usage tracking)

Text & File Processing:

  • Ripgrep (rg)
  • fd-find
  • bat
  • tree
  • jq
  • yq v4.40.5
  • curl
  • wget

Code Quality:

  • ESLint
  • ShellCheck
  • yamllint
  • yamlfmt v0.10.0
  • ruff
  • hadolint v2.12.0

System Monitoring:

  • btop v1.2.13
  • procs v0.14.10
  • hyperfine v1.18.0

Shell:

  • Zsh with Oh My Zsh (Eastwood theme)
  • Git plugin
  • Custom aliases for Claude tools
  • Prompt prefixed with [claude-container] for easy identification

Installation

1. Clone and Setup

# Clone to a persistent location
git clone https://gitlab.com/edward.kirton/claude-container.git ~/claude-container

# Add to your shell configuration (e.g., ~/.zshrc or ~/.bashrc)
echo 'export PATH="$HOME/claude-container/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc

2. First Run

Navigate to any project directory and start the container:

cd /path/to/your/project
claude-container

On first run:

  • Creates ~/claude-container-home for persistent configuration
  • Builds the Docker image with your user credentials (is slow the first time)
  • Initializes Oh My Zsh configuration
  • Sets up the network firewall with verification

Inside the container, authenticate with Claude:

claude

This authentication only needs to be done once and persists across sessions.

Usage

Aliases

The container includes convenient aliases for Claude tools:

  • claude - Main Claude CLI interface (aliased to claude --dangerously-skip-permissions)
  • ccusage - Claude Code usage tracking tool (aliased to npx ccusage blocks --active)

These aliases are available inside the container's Zsh shell environment.

Starting the Container

From any project directory:

# Default mode (allow all HTTP/HTTPS outbound)
claude-container

# Strict mode (only allow specific domains)
claude-container --strict

# No firewall (allow all network traffic)
claude-container --no-firewall

This will:

  1. Start a fresh container with your project mounted
  2. Initialize the firewall in the selected mode (verbose on first run, silent thereafter)
  3. Mount your project at its actual path
  4. Launch zsh with Oh My Zsh and custom aliases

Limitations

Separate Claude Configurations

Claude Container uses an isolated home directory (~/claude-container-home) for security, which means Claude Code sessions inside and outside the container maintain completely separate configurations:

Outside the container (host):

  • Configuration stored in ~/.claude/ (your regular home directory)
  • Conversations, history, and settings belong to your host environment

Inside the container:

  • Configuration stored in ~/claude-container-home/.claude/
  • Separate conversations, history, and settings from the host

Important implications:

  • You cannot use /resume to continue a conversation started outside the container (or vice versa)
  • Custom commands, hooks, and plugins are not shared between environments
  • Each environment maintains its own conversation history

Sharing configurations between environments: If you want to use the same custom commands or settings in both environments, you can manually copy them:

# Copy custom commands from host to container
cp ~/.claude/commands/*.md ~/claude-container-home/.claude/commands/

# Copy hooks from host to container; scripts often require editing to work, particulary if OS differs.
cp ~/.claude/hooks/*.sh ~/claude-container-home/.claude/hooks/

Firewall Modes

Default Mode (--allow-outgoing)

Allows broad internet access for general development:

claude-container              # Uses default mode
claude-container --allow-outgoing  # Explicit

Strict Mode (--strict)

Maximum security with only essential domains allowed:

claude-container --strict

No Firewall (--no-firewall)

Completely unrestricted network access:

claude-container --no-firewall

Running Commands

Execute commands directly with any firewall mode:

claude-container ls -la
claude-container --strict claude --help
claude-container --no-firewall npm install

Adding Custom Domains (Strict Mode Only)

In strict mode, you can add additional allowed domains:

Permanent (recommended): Edit docker/whitelist.txt and add domains (one per line):

echo "example.com" >> docker/whitelist.txt
echo "api.example.com" >> docker/whitelist.txt
claude-container --rebuild --strict

Temporary (current session only):

export ADDITIONAL_ALLOWED_DOMAINS="example.com api.example.com"
claude-container --strict

Note: Custom domains are only used in --strict mode. In --allow-outgoing and --no-firewall modes, all or most domains are already accessible.

Rebuilding

To rebuild the container image (can be combined with firewall modes):

claude-container --rebuild
claude-container --rebuild --strict
claude-container --rebuild --no-firewall

Note: Rebuilding the container is safe and won't affect your:

  • Claude authentication (stored in ~/claude-container-home/.claude.json)
  • SSH keys, Git configuration, or shell history
  • Any other files in your persistent home directory

This means you can freely modify the Dockerfile to add new tools or update versions without needing to re-authenticate with Claude.

Directory Structure

Project Files

claude-container/
├── bin/
│   └── claude-container          # Launcher script
├── docker/
│   ├── Dockerfile               # Container definition
│   ├── init-firewall.sh        # Firewall configuration
│   └── whitelist.txt           # Allowed domains for strict mode
├── LICENSE.md                  # MIT License
└── README.md

Persistent Home

~/claude-container-home/
├── .claude/                    # Claude configuration
├── .claude.json                # Authentication tokens
├── .gitconfig                  # Git configuration
├── .ssh/                       # SSH keys
├── .oh-my-zsh/                 # Shell framework
└── .zsh_history                # Command history

How It Works

Path Consistency

Your project is mounted at the same path inside the container as on your host system. For example:

  • Host: /Users/yourname/Projects/myapp
  • Container: /Users/yourname/Projects/myapp

This ensures path references remain valid and tools like Git work seamlessly.

Persistent Configuration

The ~/claude-container-home directory is mounted as your home inside the container, preserving:

  • Claude authentication
  • Shell configuration and history
  • SSH keys and Git config
  • Any files you create in your container home

Security Model

  • Runs as your host user (same UID/GID) for proper file permissions
  • Network traffic restricted via iptables firewall
  • DNS queries limited to Docker's resolver
  • No access to host home directory or other projects

Troubleshooting

Container Won't Start

  • Ensure Docker is running
  • Verify execute permissions: chmod +x ~/claude-container/bin/claude-container
  • Cannot run from home directory - use a specific project directory
  • Check logs: docker logs <container-name>

Authentication Issues

  • Remove ~/claude-container-home/.claude.json and re-authenticate
  • Ensure your host can reach api.anthropic.com

Network Issues

  • Strict mode: View blocked connections: docker logs <container-name> 2>&1 | grep BLOCKED
  • Strict mode: Add temporary domains: export ADDITIONAL_ALLOWED_DOMAINS="domain.com"
  • Check firewall rules: docker exec -it <container-name> sudo iptables -L -v -n
  • Try a less restrictive mode: claude-container --allow-outgoing or claude-container --no-firewall

Viewing Firewall Details

  • First run shows full initialization output
  • Use --rebuild to see firewall configuration again
  • Errors are always displayed regardless of verbosity
  • Different modes show different initialization messages:
    • --strict: Shows domain resolution and IP configuration
    • --allow-outgoing: Shows HTTP/HTTPS rule configuration
    • --no-firewall: Shows firewall disabled message

Permission Issues

  • Files created in container have correct ownership automatically
  • For debugging: docker exec -it --user root <container-name> bash

Python Development with uv

Platform-Specific Virtual Environments

The container includes uv, a fast Python package manager. However, Python virtual environments are platform-specific because compiled binaries and C extensions differ between operating systems and architectures.

  • Host (macOS): Creates macOS-compatible binaries and wheels (Darwin ARM64 or x86_64)
  • Container (Linux): Creates Linux-compatible binaries and wheels (Linux x86_64 or aarch64)

Key Concept: When You Switch Platforms, You Must Re-sync

If you run uv sync in the container (Linux), the .venv directory will contain Linux binaries. After you exit the container, you'll need to run uv sync again on your host (macOS) before you can use uv run because:

  1. The Python interpreter itself is a platform-specific binary
  2. Any packages with C extensions (numpy, pandas, cryptography, etc.) are compiled for a specific platform
  3. The .venv/bin/ directory contains platform-specific executables

Typical Workflow Example:

# Working on macOS host
cd myproject
uv sync                    # Creates/updates .venv with macOS binaries
uv run python script.py    # Works! Using macOS Python

# Enter container to test in Linux environment
claude-container
uv sync                    # Re-creates .venv with Linux binaries
uv run python script.py    # Works! Using Linux Python
exit

# Back on macOS host
uv run python script.py    # ERROR! .venv contains Linux binaries
uv sync                    # Re-sync for macOS
uv run python script.py    # Works again!

What Happens During Platform Switch:

When uv detects a platform change, it will:

  1. Recognize that the current .venv is for a different platform
  2. Download platform-appropriate wheels from PyPI (or use cached ones)
  3. Rebuild the virtual environment with correct binaries
  4. Preserve your uv.lock file for consistency across platforms

Important Notes:

  1. The uv.lock file is platform-independent - it ensures the same package versions across all platforms
  2. The .venv directory is platform-specific - always add it to .gitignore
  3. First sync on a new platform takes longer - subsequent syncs use cached packages
  4. The container sets UV_LINK_MODE=copy - this suppresses hardlink warnings caused by Docker filesystem boundaries

Best Practices:

  • Always run uv sync after switching between host and container if they're different platforms
  • Use uv.lock for reproducible installs - commit this file to version control
  • Never commit .venv/ - it contains platform-specific binaries
  • Consider separate venv directories if you frequently switch between platforms:
    # On macOS host
    UV_PROJECT_ENVIRONMENT=.venv-macos uv sync
    UV_PROJECT_ENVIRONMENT=.venv-macos uv run python script.py
    
    # In Linux container
    UV_PROJECT_ENVIRONMENT=.venv-linux uv sync
    UV_PROJECT_ENVIRONMENT=.venv-linux uv run python script.py
    
    This approach maintains both environments simultaneously, avoiding re-syncs when switching.
  • Or simply always run uv run ... inside the container

MCP Servers

Configuration

Claude Container does not include any preconfigured MCP services. You can add your own MCP servers in the usual way - your configuration will persist between sessions as it's stored in your persistent home directory (~/claude-container-home).

Adding MCP Servers

To add an MCP server inside the container:

  1. For HTTP-based MCP servers in strict mode: Add the domain to your firewall configuration by editing docker/whitelist.txt and rebuilding:

    # Outside the container: Add any required URLs to docker/whitelist.txt
    echo "mcp.context7.com" >> docker/whitelist.txt
    claude-container --rebuild --strict
    
  2. Inside the container: Add the MCP server using the Claude CLI

    # Example: Adding Context7 MCP server
    claude mcp add --transport http context7 https://mcp.context7.com/mcp --header "CONTEXT7_API_KEY: YOUR_API_KEY"
    
  3. Your MCP configuration will be saved to ~/.claude/mcp_settings.json and persist across container sessions.

MCP Server Types

  • Local servers: Work out of the box as they run inside the container
  • HTTP/HTTPS servers: May require firewall configuration in strict mode
  • Stdio servers: Work as normal within the container environment

For more information about MCP servers, see the Claude MCP documentation.

Development

Modifying the Container

  1. Edit files in docker/ (e.g., to add new tools or change versions)
  2. Rebuild: claude-container --rebuild
  3. Test: claude-container

Your Claude authentication and all configuration in ~/claude-container-home persists across rebuilds.

Updating Tool Versions

Edit version variables at the top of docker/Dockerfile:

ARG PYTHON_VERSION=3.13.7
ARG YAMLFMT_VERSION=v0.10.0
# etc...

Requirements

  • Docker
  • Bash shell
  • Internet connection for initial setup

Credits

Derived from Claude Code devcontainer. Written by Claude Code under the direction of Edward Kirton.

License

MIT License - See LICENSE file for details

Some Notable Alternatives

Share: