Run Claude Code CLI in a Docker container. Claude Code is Anthropic's agentic coding tool that lives in your terminal, understands your codebase, and helps you code faster.
- Quick Start
- Prerequisites
- Authentication
- Usage Examples
- Configuration
- Volume Mounts
- Working with External Files and Screenshots
- Environment Variables
- MCP (Model Context Protocol) Support
- Troubleshooting
- Shell Alias (Convenience)
- Building Locally
- License
- Links
Most users have a Claude Pro or Max subscription and should use OAuth:
# One-time login (opens browser)
docker run -it --rm \
--network host \
-v ~/.claude:/home/coder/.claude \
ungb/claude-code \
claude login
# Then run normally (no API key needed!)
docker run -it --rm \
-v $(pwd):/workspace \
-v ~/.claude:/home/coder/.claude \
ungb/claude-codeIf you're using API credits instead, see API Key authentication.
- Docker installed
- One of the following:
- Claude Pro or Max subscription (use OAuth)
- Anthropic API key with API credits (use API Key)
Choose your authentication method based on how you pay for Claude:
| Plan Type | Authentication Method | Section |
|---|---|---|
| Claude Pro/Max Subscription | OAuth Login (recommended) | OAuth Setup |
| API Credits (Pay-as-you-go) | API Key | API Key Setup |
Recommended for most users. If you have a Claude Pro or Max subscription, OAuth is the easiest way to authenticate.
# Login with browser-based OAuth (one-time only)
docker run -it --rm \
--network host \
-v ~/.claude:/home/coder/.claude \
ungb/claude-code \
claude loginThis opens your browser, authenticates with your Claude account, and saves tokens to ~/.claude/ on your host machine.
After the one-time login, simply run:
# No API key needed!
docker run -it --rm \
-v $(pwd):/workspace \
-v ~/.claude:/home/coder/.claude \
ungb/claude-codeImportant: Always mount
-v ~/.claude:/home/coder/.claudeto persist your login. Without this mount, you'll need to login every time.
How it works: OAuth tokens are stored in ~/.claude/ on your host. By mounting this directory, your credentials persist between container runs. You only need to run claude login once (or when tokens expire).
If you're using Anthropic API credits (pay-as-you-go), use an API key from Anthropic Console:
# Set your API key as an environment variable
docker run -it --rm \
-v $(pwd):/workspace \
-e ANTHROPIC_API_KEY=sk-ant-... \
ungb/claude-codeOr use an environment variable from your shell:
# Export once in your shell
export ANTHROPIC_API_KEY=sk-ant-...
# Then use in docker commands
docker run -it --rm \
-v $(pwd):/workspace \
-e ANTHROPIC_API_KEY=$ANTHROPIC_API_KEY \
ungb/claude-codeNote: This method doesn't require mounting
~/.claudefor authentication (though you may still want to mount it for custom commands and settings).
All examples below assume you've completed the OAuth one-time setup.
# Start an interactive Claude Code session
docker run -it --rm \
-v $(pwd):/workspace \
-v ~/.claude:/home/coder/.claude \
ungb/claude-codeUse the -p flag for non-interactive mode (prints result and exits):
# Ask a question about your codebase
docker run -it --rm \
-v $(pwd):/workspace \
-v ~/.claude:/home/coder/.claude \
ungb/claude-code \
claude -p "explain the architecture of this project"
# Generate code
docker run -it --rm \
-v $(pwd):/workspace \
-v ~/.claude:/home/coder/.claude \
ungb/claude-code \
claude -p "create a REST API endpoint for user authentication"
# Fix bugs
docker run -it --rm \
-v $(pwd):/workspace \
-v ~/.claude:/home/coder/.claude \
ungb/claude-code \
claude -p "fix the failing tests in src/utils"
# Code review
docker run -it --rm \
-v $(pwd):/workspace \
-v ~/.claude:/home/coder/.claude \
ungb/claude-code \
claude -p "review the changes in the last commit"# Full setup with persistent config, git, SSH, and screenshots
docker run -it --rm \
-v $(pwd):/workspace \
-v ~/.claude:/home/coder/.claude \
-v ~/.ssh:/home/coder/.ssh:ro \
-v ~/.gitconfig:/home/coder/.gitconfig:ro \
-v ~/claude-screenshots:/screenshots \
ungb/claude-code- Copy
docker-compose.ymlto your project - Ensure you've run
claude login(one-time setup) - Run:
# Interactive session
docker compose run --rm claude
# One-shot command (non-interactive)
docker compose run --rm claude claude -p "explain this code"# Continue from where you left off
docker run -it --rm \
-v $(pwd):/workspace \
-v ~/.claude:/home/coder/.claude \
ungb/claude-code \
claude --resume# Analyze a file
cat README.md | docker run -i --rm \
-v $(pwd):/workspace \
-v ~/.claude:/home/coder/.claude \
ungb/claude-code \
claude -p "summarize this document"
# Analyze git diff
git diff | docker run -i --rm \
-v $(pwd):/workspace \
-v ~/.claude:/home/coder/.claude \
ungb/claude-code \
claude -p "review these changes"All examples below use the API key authentication method.
docker run -it --rm \
-v $(pwd):/workspace \
-e ANTHROPIC_API_KEY=$ANTHROPIC_API_KEY \
ungb/claude-code# Ask a question about your codebase
docker run -it --rm \
-v $(pwd):/workspace \
-e ANTHROPIC_API_KEY=$ANTHROPIC_API_KEY \
ungb/claude-code \
claude -p "explain the architecture of this project"
# Generate code
docker run -it --rm \
-v $(pwd):/workspace \
-e ANTHROPIC_API_KEY=$ANTHROPIC_API_KEY \
ungb/claude-code \
claude -p "create a REST API endpoint for user authentication"
# JSON output (for scripts/automation)
docker run -it --rm \
-v $(pwd):/workspace \
-e ANTHROPIC_API_KEY=$ANTHROPIC_API_KEY \
ungb/claude-code \
claude -p --output-format json "list all TODO comments"- Copy
docker-compose.ymlto your project:
curl -O https://raw.githubusercontent.com/ungb/claude-code-docker/main/docker-compose.yml- Create a
.envfile:
echo "ANTHROPIC_API_KEY=your-key-here" > .env- Run:
# Interactive session
docker compose run --rm claude
# One-shot command (non-interactive)
docker compose run --rm claude claude -p "explain this code"# Run without interactive prompts (for scripts/CI)
docker run --rm \
-v $(pwd):/workspace \
-e ANTHROPIC_API_KEY=$ANTHROPIC_API_KEY \
ungb/claude-code \
claude -p --allowedTools "Bash(npm run format)" "format all TypeScript files"
# Skip all permission prompts (use with caution!)
docker run --rm \
-v $(pwd):/workspace \
-e ANTHROPIC_API_KEY=$ANTHROPIC_API_KEY \
ungb/claude-code \
claude -p --dangerously-skip-permissions "run the linter and fix issues"The ~/.claude directory contains your personal Claude Code configuration including custom slash commands, skills, agents, and settings. Mount it to use your customizations inside the container.
~/.claude/
├── settings.json # Global settings and preferences
├── settings.local.json # Local overrides and permissions
├── commands/ # Custom slash commands (.md files)
│ ├── my-command.md
│ └── another-command.md
├── agents/ # Custom agents (.md files with YAML frontmatter)
│ ├── code-reviewer.md
│ └── debugger.md
└── .claude.json # MCP server configurations
# OAuth users: This is automatically included in OAuth setup
docker run -it --rm \
-v $(pwd):/workspace \
-v ~/.claude:/home/coder/.claude \
ungb/claude-code
# API Key users: Add this mount to access your custom commands/agents
docker run -it --rm \
-v $(pwd):/workspace \
-v ~/.claude:/home/coder/.claude \
-e ANTHROPIC_API_KEY=$ANTHROPIC_API_KEY \
ungb/claude-codeOnce your ~/.claude is mounted, your custom commands are available:
docker run -it --rm \
-v $(pwd):/workspace \
-v ~/.claude:/home/coder/.claude \
ungb/claude-code
# Then inside the session, type: /my-custom-commandProjects can have their own .claude/ directory with project-specific commands:
# Your project's .claude/ is automatically available at /workspace/.claude/
docker run -it --rm \
-v $(pwd):/workspace \
-v ~/.claude:/home/coder/.claude \
ungb/claude-codeIf you want to use different Claude Code settings for Docker than your local setup (e.g., your local has MCP servers that won't work in Docker), you can create a separate configuration directory:
# Create a separate config directory for Docker
mkdir -p ~/.claude-docker
# Copy your existing config if you want to start from there
cp -r ~/.claude/* ~/.claude-docker/
# Or start fresh - Claude will create default settings on first run# OAuth login with Docker-specific config
docker run -it --rm \
--network host \
-v ~/.claude-docker:/home/coder/.claude \
ungb/claude-code \
claude login
# Use the Docker-specific config
docker run -it --rm \
-v $(pwd):/workspace \
-v ~/.claude-docker:/home/coder/.claude \
ungb/claude-codeEdit ~/.claude-docker/settings.json or .claude.json on your host to:
- Remove MCP servers that don't work in Docker
- Add Docker-specific slash commands
- Adjust settings for containerized environment
- Configure different agents or hooks
# Edit your Docker-specific settings
nano ~/.claude-docker/settings.json
# Remove problematic MCP servers
nano ~/.claude-docker/.claude.jsonThis approach keeps your local Claude Code setup separate from your Docker setup, allowing each to have their own:
- MCP server configurations
- Custom commands and agents
- Settings and preferences
- OAuth credentials (if using different accounts)
| Mount | Purpose |
|---|---|
/workspace |
Your project directory (required) |
/home/coder/.claude |
Claude config, commands, agents, settings, OAuth tokens |
/home/coder/.ssh |
SSH keys for git operations (read-only) |
/home/coder/.gitconfig |
Git configuration (read-only) |
/home/coder/.claude.json |
MCP server configurations (read-only) |
/screenshots |
Optional: Dedicated folder for screenshots and images (recommended) |
Important: Drag-and-drop doesn't work when Claude Code runs in a Docker container because it's isolated from your host filesystem. You need to explicitly mount directories to make files accessible.
Create a dedicated folder on your host machine for screenshots and images you want to share with Claude Code:
# Create a dedicated screenshots folder
mkdir -p ~/claude-screenshotsUsing docker run:
docker run -it --rm \
-v $(pwd):/workspace \
-v ~/.claude:/home/coder/.claude \
-v ~/claude-screenshots:/screenshots \
ungb/claude-codeUsing docker-compose:
Update your docker-compose.yml to include the screenshots mount (see example in the repository).
# Copy screenshots or images to the folder
cp ~/Downloads/screenshot.png ~/claude-screenshots/
cp ~/Desktop/diagram.jpg ~/claude-screenshots/
# Or save screenshots directly to this folder using your screenshot toolInside Claude Code, reference files using the mounted path:
Can you analyze /screenshots/screenshot.png?
Please review the UI in /screenshots/mockup.png and suggest improvements
Read the diagram at /screenshots/architecture.jpg and explain the flow
You can also mount your Downloads folder directly:
# Mount Downloads folder (read-only recommended for safety)
docker run -it --rm \
-v $(pwd):/workspace \
-v ~/.claude:/home/coder/.claude \
-v ~/Downloads:/downloads:ro \
ungb/claude-codeThen reference files:
Analyze /downloads/screenshot.png
If you're working on a specific project, copy files directly into your project directory:
# Copy to your project directory (which is already mounted as /workspace)
cp ~/Downloads/screenshot.png /path/to/your/project/
# Then in Claude Code:
# Analyze /workspace/screenshot.pngYou can mount multiple directories for different purposes:
docker run -it --rm \
-v $(pwd):/workspace \
-v ~/.claude:/home/coder/.claude \
-v ~/claude-screenshots:/screenshots \
-v ~/Downloads:/downloads:ro \
-v ~/Documents:/docs:ro \
ungb/claude-codeThis gives you access to:
/workspace- Your current project/screenshots- Dedicated screenshots folder (read-write)/downloads- Downloads folder (read-only)/docs- Documents folder (read-only)
- Use descriptive paths: Instead of
screenshot.png, uselogin-page-error.png - Organize by purpose: Create subfolders in
~/claude-screenshots/likebugs/,designs/,diagrams/ - Read-only mounts: Use
:roflag for folders you only need to read from (safety measure) - Absolute paths: Always use absolute paths when referencing files (e.g.,
/screenshots/image.png)
# 1. Take a screenshot (macOS example)
# Press Cmd+Shift+4 and save to ~/claude-screenshots/
# 2. Start Claude Code with screenshots mounted
docker run -it --rm \
-v $(pwd):/workspace \
-v ~/.claude:/home/coder/.claude \
-v ~/claude-screenshots:/screenshots \
ungb/claude-code
# 3. In Claude Code, reference the screenshot
> Can you analyze the error message in /screenshots/error-screenshot.png and help me fix it?| Variable | Required | Description |
|---|---|---|
ANTHROPIC_API_KEY |
Conditional* | Your Anthropic API key |
ANTHROPIC_API_BASE_URL |
No | Custom API endpoint (for proxies) |
CLAUDE_CONFIG_DIR |
No | Override config directory location |
*Required if using API key authentication. Not required if using OAuth.
Warning: MCP support in Docker containers is limited and may require additional configuration.
MCP servers may not work out of the box in Docker because:
- Stdio-based MCP servers need the server binary installed inside the container
- Network-based MCP servers need proper network configuration
- MCP servers that access local resources (files, databases) need those resources available in the container
- Authentication for MCP servers may not transfer into the container
| MCP Type | Status | Notes |
|---|---|---|
| HTTP/SSE servers (remote) | May work | Requires --network host or proper port mapping |
| Stdio servers (local) | Unlikely | Server must be installed in container |
| Servers needing local files | Partial | Files must be mounted into container |
| Servers with OAuth | Unlikely | Auth flow may not complete in container |
If you want to try MCP servers:
# Mount MCP config and use host network
docker run -it --rm \
--network host \
-v $(pwd):/workspace \
-v ~/.claude:/home/coder/.claude \
-v ~/.claude.json:/home/coder/.claude.json:ro \
ungb/claude-codeFor stdio-based MCP servers, you'll need to build a custom image:
FROM ungb/claude-code:latest
# Switch to root to install packages
USER root
# Example: Install an MCP server
RUN npm install -g @anthropic/mcp-server-example
# Switch back to coder user
USER coderFull MCP support in Docker containers requires further investigation:
- Testing specific MCP servers for compatibility
- Network configuration for different MCP transport types
- Credential/auth forwarding for authenticated MCP servers
- Potential need for Docker-in-Docker for some servers
If you have insights or solutions for MCP in Docker, please open an issue or PR!
Use --network host to allow the OAuth callback:
docker run -it --rm \
--network host \
-v ~/.claude:/home/coder/.claude \
ungb/claude-code \
claude loginYou must mount ~/.claude to persist OAuth tokens between container runs:
# Always include this mount for OAuth persistence
-v ~/.claude:/home/coder/.claudeIf you're still being prompted to login:
- Verify the mount exists:
ls -la ~/.claude/ - Check for credential files:
ls ~/.claude/*.json 2>/dev/null - Ensure you ran
claude loginwith the same mount path
The container runs as user coder (UID 1000). If you have permission issues:
# Run with your user ID
docker run -it --rm \
--user $(id -u):$(id -g) \
-v $(pwd):/workspace \
ungb/claude-codeEnsure SSH keys are mounted and git is configured:
docker run -it --rm \
-v $(pwd):/workspace \
-v ~/.ssh:/home/coder/.ssh:ro \
-v ~/.gitconfig:/home/coder/.gitconfig:ro \
ungb/claude-codeMake sure you're mounting your ~/.claude directory:
docker run -it --rm \
-v $(pwd):/workspace \
-v ~/.claude:/home/coder/.claude \
ungb/claude-code# Check version
docker run --rm ungb/claude-code claude --version
# Run health check (OAuth)
docker run --rm \
-v ~/.claude:/home/coder/.claude \
ungb/claude-code \
claude doctor
# Run health check (API Key)
docker run --rm \
-e ANTHROPIC_API_KEY=$ANTHROPIC_API_KEY \
ungb/claude-code \
claude doctor
# List available commands
docker run --rm \
-v ~/.claude:/home/coder/.claude \
ungb/claude-code \
claude /helpAdd to your ~/.bashrc or ~/.zshrc:
alias claude-docker='docker run -it --rm \
-v $(pwd):/workspace \
-v ~/.claude:/home/coder/.claude \
-v ~/.ssh:/home/coder/.ssh:ro \
-v ~/.gitconfig:/home/coder/.gitconfig:ro \
-v ~/claude-screenshots:/screenshots \
ungb/claude-code claude'
# Usage (interactive): claude-docker
# Usage (one-shot): claude-docker -p "explain this code"
# Usage (with screenshot): claude-docker -p "analyze /screenshots/bug.png"alias claude-docker='docker run -it --rm \
-v $(pwd):/workspace \
-v ~/.claude:/home/coder/.claude \
-v ~/.ssh:/home/coder/.ssh:ro \
-v ~/.gitconfig:/home/coder/.gitconfig:ro \
-v ~/claude-screenshots:/screenshots \
-e ANTHROPIC_API_KEY=$ANTHROPIC_API_KEY \
ungb/claude-code claude'
# Usage (interactive): claude-docker
# Usage (one-shot): claude-docker -p "explain this code"
# Usage (with screenshot): claude-docker -p "analyze /screenshots/bug.png"git clone https://github.com/ungb/claude-code-docker.git
cd claude-code-docker
docker build -t claude-code .MIT License - see LICENSE