https://github.com/icanhasjonas/run-claude-docker
Run claude code in somewhat safe and isolated yolo mode
https://github.com/icanhasjonas/run-claude-docker
claude claude-code docker
Last synced: 2 months ago
JSON representation
Run claude code in somewhat safe and isolated yolo mode
- Host: GitHub
- URL: https://github.com/icanhasjonas/run-claude-docker
- Owner: icanhasjonas
- License: mit
- Created: 2025-08-13T19:19:03.000Z (3 months ago)
- Default Branch: main
- Last Pushed: 2025-08-14T21:01:05.000Z (3 months ago)
- Last Synced: 2025-08-23T10:05:01.249Z (3 months ago)
- Topics: claude, claude-code, docker
- Language: Shell
- Homepage:
- Size: 203 KB
- Stars: 29
- Watchers: 0
- Forks: 4
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- awesome-ai - icanhasjonas/run-claude-docker
- awesome-claude-code - **run-claude-docker**
- awesome-claude-code - `run-claude-docker`
README
# Claude Code Docker Runner
Run claude code in somewhat safe and isolated yolo mode
## Features
- 🚀 **Standalone Script**: Single file contains everything - Dockerfile, MCP servers, configuration
- 🤖 **Pre-configured MCP Servers**: Unsplash, Context7, and Playwright ready to use
- 🔧 **Auto-build**: Automatically builds Docker image if it doesn't exist
- 🔒 **Secure**: Host system protected by Docker boundaries with read-only mounts
- ⚡ **Fast Setup**: No manual Docker builds or MCP configuration needed
- 🔄 **Persistent Container**: Reuses existing container for faster startup
## Table of Contents
- [Quick Start](#quick-start)
- [Prerequisites](#prerequisites)
- [Basic Usage](#basic-usage)
- [Script Options](#script-options)
- [Build Commands](#build-commands)
- [Runtime Options](#runtime-options)
- [Container Persistence](#container-persistence)
- [What's Included](#whats-included)
- [Embedded Dockerfile](#embedded-dockerfile)
- [MCP Servers](#mcp-servers)
- [Environment Variables](#environment-variables)
- [Volume Mounts](#volume-mounts)
- [Testing the Setup](#testing-the-setup)
- [Advanced Usage](#advanced-usage)
- [Custom Image Names](#custom-image-names)
- [Verbose Output](#verbose-output)
- [Environment Variable Setup](#environment-variable-setup)
- [Security Notes](#security-notes)
- [Container Security](#container-security)
- [Dangerous Permissions](#dangerous-permissions)
- [Best Practices](#best-practices)
- [Troubleshooting](#troubleshooting)
- [Permission Issues](#permission-issues)
- [Authentication Issues](#authentication-issues)
- [Image Not Found](#image-not-found)
- [Container Management](#container-management)
- [How It Works](#how-it-works)
- [Contributing](#contributing)
- [Development Workflow](#development-workflow)
- [Key Points for Contributors](#key-points-for-contributors)
- [Testing Container Changes](#testing-container-changes)
- [Visual Workflow](#visual-workflow)
## Quick Start
### Prerequisites
- Docker installed and running
- Claude authentication configured (`claude auth`)
- Environment variables for MCP servers (e.g., `UNSPLASH_ACCESS_KEY`)
### Basic Usage
```bash
# Download the script (single file needed)
curl -O https://raw.githubusercontent.com/icanhasjonas/run-claude-docker/main/run-claude.sh
chmod +x run-claude.sh
# Interactive shell (auto-pulls from Docker Hub on first run, reuses existing container)
./run-claude.sh
# Run specific command
./run-claude.sh claude --dangerously-skip-permissions "analyze this codebase"
# Custom workspace
./run-claude.sh -w /path/to/project
# If run-claude.sh fails due to architecture issues, build locally
./run-claude.sh --build
```
## Script Options
### Build Commands
```bash
# Build Docker image and exit
./run-claude.sh --build
# Force rebuild image and continue
./run-claude.sh --rebuild
```
### Runtime Options
```bash
# Custom workspace
./run-claude.sh -w /path/to/project
# Custom Claude config path
./run-claude.sh -c /path/to/.claude
# Custom container name (default: claude-code)
./run-claude.sh -n my-claude-container
# Custom image name
./run-claude.sh -i my-claude:v1.0
# One-shot with cleanup (removes container after exit)
./run-claude.sh --rm --no-interactive claude auth status
# Safe mode (no dangerous permissions)
./run-claude.sh --safe
# Non-interactive mode
./run-claude.sh --no-interactive
# Recreate container (remove existing and create new)
./run-claude.sh --recreate
# Help
./run-claude.sh --help
```
### Container Persistence
By default, the script creates a persistent container named `claude-code` that is reused across runs:
- **First run**: Creates and starts the container
- **Subsequent runs**: Reuses the existing container for faster startup
- **Container running**: Executes commands in the running container
- **Container stopped**: Restarts the existing container preserving all changes
This behavior significantly reduces startup time and preserves any modifications made inside the container (installed packages, configuration changes, etc.).
## What's Included
### Embedded Dockerfile
The script contains a complete Dockerfile that includes:
- Ubuntu 22.04 base image
- Claude Code installation
- Go, Node.js, Python, and build tools
- Pre-built Unsplash MCP server
- All MCP servers pre-configured
### MCP Servers
Automatically configured and ready to use:
- **Unsplash**: Photo search and download (`unsplash-mcp-server`)
- **Context7**: AI context service (`https://mcp.context7.com/mcp`)
- **Playwright**: Browser automation (`@playwright/mcp@latest`)
### Environment Variables
#### Script Configuration
- `CLAUDE_CODE_IMAGE_NAME` - Override default Docker Hub image (default: `icanhasjonas/claude-code`)
#### Automatically forwarded from host
- `UNSPLASH_ACCESS_KEY`
- `OPENAI_API_KEY`
- `NUGET_API_KEY`
- `CLAUDE_DANGEROUS_MODE=1`
- `NODE_OPTIONS=--max-old-space-size=8192`
- `TERM` - Terminal settings for proper color support
#### Claude Authentication Forwarding
The script automatically forwards Claude authentication and OAuth credentials from your host system:
- **OAuth Account**: Preserves your Claude login session
- **User Settings**: Maintains preferences and onboarding state
- **Permissions**: Automatically enables bypass permissions mode in container
- **Subscription**: Forwards subscription and access cache information
This ensures seamless authentication without needing to re-login inside the container.
### Volume Mounts
Automatically mounted:
- Workspace: `$(pwd)` → `/home/$(whoami)/workspace`
- Claude config: `~/.claude` → `/home/$(whoami)/.claude`
- SSH keys: `~/.ssh` → `/home/$(whoami)/.ssh` (read-only)
- Git config: `~/.gitconfig` → `/home/$(whoami)/.gitconfig` (read-only)
### Authentication Integration
The script makes a best effort to forward your Claude authentication into the container session:
- **Seamless Login**: Your existing Claude authentication is automatically available (after initial setup)
- **OAuth Preservation**: Maintains your logged-in state and subscription access
- **Config Merging**: Intelligently merges host Claude configuration with container settings
- **Permission Bypass**: Automatically enables bypass permissions mode for streamlined operation
**Important:** On your first run, you may need to run `claude /login` inside the container. After that initial authentication, your login state is preserved and forwarded automatically for future runs.
## Testing the Setup
### 1. First Run (Auto-pull)
```bash
# First run will automatically pull the pre-built image from Docker Hub
./run-claude.sh claude auth status
# If not authenticated, you'll need to login (usually only required once)
./run-claude.sh claude /login
# Test MCP servers are working
./run-claude.sh claude "search for sunset photos on unsplash"
```
### 2. Test Build Commands
```bash
# Build image only (useful for CI/CD)
./run-claude.sh --build
# Force rebuild (get latest updates)
./run-claude.sh --rebuild
```
### 3. Test File Operations
```bash
# Create test project
mkdir test-project
cd test-project
echo "console.log('hello');" > test.js
# Test Claude with file modification
./run-claude.sh claude --dangerously-skip-permissions "add error handling to test.js"
# Check if file persists on host
cat test.js
```
### 4. Test MCP Integration
```bash
# Test Unsplash MCP
./run-claude.sh claude "find a photo of mountains using unsplash"
# Test Playwright MCP
./run-claude.sh claude "take a screenshot of google.com"
```
## Advanced Usage
### Custom Image Names
```bash
# Use custom image name
./run-claude.sh -i my-claude:v1.0
# Build with custom name
./run-claude.sh -i my-claude:v1.0 --build
```
### Verbose Output
```bash
# Show docker command being executed
RUN_CLAUDE_VERBOSE=1 ./run-claude.sh
# Example output:
# Running Claude Code container...
# Command: docker run --rm -it --privileged --name claude-code-1234567890 ...
```
### Environment Variable Setup
```bash
# Set required environment variables
export UNSPLASH_ACCESS_KEY="your-key-here"
export OPENAI_API_KEY="your-openai-key"
# Use custom Docker image
export CLAUDE_CODE_IMAGE_NAME="myregistry/my-claude-code"
./run-claude.sh
# Or use .env file approach
echo "UNSPLASH_ACCESS_KEY=your-key" >> ~/.bashrc
source ~/.bashrc
```
## Security Notes
### Container Security
- ✅ **Host isolation**: Host system protected by Docker boundaries
- ✅ **Read-only mounts**: SSH keys and system configs mounted read-only
- ✅ **User isolation**: Runs as non-root user inside container
- ⚠️ **Privileged mode**: Required for dangerous permissions functionality
### Dangerous Permissions
- Container has `--privileged` flag for full system access within container
- Claude runs with `--dangerously-skip-permissions` by default
- Only use with trusted code and repositories
- All file modifications are contained within mounted volumes
### Best Practices
1. Only mount directories you want Claude to access
2. Use read-only mounts for sensitive configs
3. Regularly rebuild image for security updates
4. Monitor container resource usage
5. Use temporary containers (`--rm`) for one-shot commands
## Troubleshooting
### Permission Issues
```bash
# Fix workspace permissions
docker run --rm -v $(pwd):/workspace claude-code:latest sudo chown -R claude:claude /workspace
```
### Authentication Issues
**First Time Setup:**
On your very first run, you may need to authenticate Claude inside the container:
```bash
# Check Claude authentication status
./run-claude.sh claude auth status
# If not authenticated, login (this is usually only needed once)
./run-claude.sh claude /login
```
After the initial `/login`, the script automatically forwards your authentication between the host and container, so you shouldn't need to re-authenticate in future runs.
**Note:** The authentication forwarding works most of the time but isn't bulletproof. If you encounter auth issues, try running `/login` again inside the container.
**Troubleshooting Authentication:**
```bash
# Check Claude config
./run-claude.sh claude auth status
# Re-authenticate if needed
./run-claude.sh claude auth
# Or use the web login method
./run-claude.sh claude /login
```
### Image Not Found
```bash
# Force rebuild image
./run-claude.sh --rebuild
# Or build only
./run-claude.sh --build
# Check existing images
docker images | grep claude
```
### Container Management
```bash
# List containers
docker ps -a | grep claude
# Stop persistent container
docker stop claude-code
# Remove persistent container
docker rm claude-code
# Or use the script to recreate
./run-claude.sh --recreate
```
## How It Works
```
┌─────────────────────────────────────────────────────────────────────────────────┐
│ HOST SYSTEM │
├─────────────────────────────────────────────────────────────────────────────────┤
│ ./run-claude.sh │
│ │ │
│ ├─ 1. Check if Docker image exists │
│ │ ├─ NO → Build embedded Dockerfile │
│ │ └─ YES → Continue │
│ │ │
│ ├─ 2. Check if container exists │
│ │ ├─ RUNNING → Execute in existing container │
│ │ ├─ STOPPED → Start existing container (preserves state) │
│ │ └─ MISSING → Create new container │
│ │ │
│ └─ 3. Mount volumes & forward env vars │
│ │ │
│ ▼ │
├─────────────────────────────────────────────────────────────────────────────────┤
│ DOCKER CONTAINER (Ubuntu 25.04 + Claude + MCP) │
│ │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Unsplash MCP │ │ Context7 MCP │ │ Playwright MCP │ │
│ │ (Pre-built) │ │ (HTTP/Web) │ │ (npm global) │ │
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
│ │ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ CLAUDE CODE │ │
│ │ (--dangerously-skip-permissions) │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ ZSH + Oh-My-Zsh + LazyVim + Dev Tools │ │
│ │ • Node.js (via fnm) • Go • Python • Git • Build tools │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ MOUNTED VOLUMES (Read/Write): │
│ • ~/.claude → Container config │
│ • $(pwd) → Working directory │
│ │
│ MOUNTED VOLUMES (Read-Only): │
│ • ~/.ssh → SSH keys │
│ • ~/.gitconfig → Git configuration │
│ │
│ ENV FORWARDED: │
│ • API Keys (Unsplash, OpenAI, etc.) │
│ • CLAUDE_DANGEROUS_MODE=1 │
│ • Claude Authentication & OAuth │
│ • Terminal settings (TERM) │
└─────────────────────────────────────────────────────────────────────────────────┘
🔒 ISOLATION BENEFITS:
✅ Host system protected by Docker boundaries
✅ All dangerous operations contained in container
✅ Persistent containers with preserved state
✅ Pre-configured MCP servers ready to use
⚠️ YOLO MODE:
• Container runs with --privileged flag
• Claude runs with --dangerously-skip-permissions
• Use only with trusted projects!
```
The `run-claude.sh` script is completely self-contained:
1. **Embedded Dockerfile**: Contains a complete Ubuntu 22.04 setup with Claude Code
2. **Auto-detection**: Checks if Docker image exists, pulls from Docker Hub if missing, builds only with `--build` or `--rebuild`
3. **Container Persistence**: Reuses existing `claude-code` container for faster startup
4. **MCP Setup**: Automatically configures Unsplash, Context7, and Playwright servers
5. **Environment Forwarding**: Passes through API keys, configurations, and Claude authentication
6. **Volume Management**: Mounts workspace and config directories automatically
7. **User Matching**: Creates container user matching your host user
No separate files needed - just the single `run-claude.sh` script!
## Contributing
Pull requests are welcome! Feel free to contribute improvements, bug fixes, or new features.
### Development Workflow
The Dockerfile is **embedded directly** in the `run-claude.sh` script to maintain the self-contained nature of the tool. When making changes to the container configuration:
1. **Edit the embedded Dockerfile** in the `generate_dockerfile_content()` function
2. **Test your changes** by rebuilding the container:
```bash
# Build new image and test (doesn't run container)
./run-claude.sh --build
# Or rebuild and run container immediately
./run-claude.sh --rebuild
```
3. **Export for standalone use** (optional):
```bash
# Export current Dockerfile for inspection or external use
./run-claude.sh --export-dockerfile Dockerfile
```
### Key Points for Contributors
- **Single source of truth**: The `generate_dockerfile_content()` function contains the authoritative Dockerfile
- **No separate Dockerfile**: Everything is embedded to maintain the self-contained design
- **Always test rebuilds**: After changing container configuration, use `--rebuild` to test
- **Both build options available**:
- `--build`: Just builds the image (useful for testing build process)
- `--rebuild`: Builds image and runs container (full testing)
### Testing Container Changes
```bash
# After editing the embedded Dockerfile:
# Option 1: Build only (test build process)
./run-claude.sh --build
# Option 2: Rebuild and test (full workflow)
./run-claude.sh --rebuild
# Option 3: Export and inspect
./run-claude.sh --export-dockerfile debug.dockerfile
less debug.dockerfile
```
This workflow ensures that the container changes are properly tested while maintaining the tool's self-contained design.
## Visual Workflow
```mermaid
flowchart TD
Start([🚀 ./run-claude.sh]) --> CheckImage{🐳 Docker Image
Exists?}
CheckImage -->|No| PullImage[📥 Try Pull from
Docker Hub]
PullImage --> PullSuccess{Pull Success?}
PullSuccess -->|Yes| TagImage[🏷️ Tag as
claude-code:latest]
PullSuccess -->|No| BuildImage[🔨 Build from
Embedded Dockerfile]
TagImage --> CheckContainer
BuildImage --> CheckContainer
CheckImage -->|Yes| CheckContainer{📦 Container
Exists?}
CheckContainer -->|Missing| CreateContainer[⚡ Create New Container
with Volumes & Env]
CheckContainer -->|Stopped| StartContainer[♻️ Start Existing
Container
🎯 Preserves State]
CheckContainer -->|Running| ExecContainer[🔄 Execute in
Running Container]
CreateContainer --> RunCommand{💻 Command
Provided?}
StartContainer --> RunCommand
ExecContainer --> RunCommand
RunCommand -->|Yes| ExecuteCmd[⚡ Execute:
claude --dangerously-skip-permissions]
RunCommand -->|No| InteractiveShell[🐚 Interactive Shell
zsh + oh-my-zsh]
ExecuteCmd --> MCPServers[🤖 MCP Servers Available]
InteractiveShell --> MCPServers
MCPServers --> Unsplash[📸 Unsplash
Photo Search]
MCPServers --> Context7[🧠 Context7
AI Context]
MCPServers --> Playwright[🎭 Playwright
Browser Automation]
Unsplash --> WorkInContainer[🛠️ Work in Isolated
Container Environment]
Context7 --> WorkInContainer
Playwright --> WorkInContainer
WorkInContainer --> PersistChanges[💾 Changes Persist
in Container]
PersistChanges --> End([✅ Complete])
%% Styling
classDef startEnd fill:#e1f5fe,stroke:#01579b,stroke-width:3px,color:#000
classDef decision fill:#fff3e0,stroke:#e65100,stroke-width:2px,color:#000
classDef process fill:#f3e5f5,stroke:#4a148c,stroke-width:2px,color:#000
classDef container fill:#e8f5e8,stroke:#2e7d32,stroke-width:2px,color:#000
classDef mcp fill:#fff8e1,stroke:#f57f17,stroke-width:2px,color:#000
class Start,End startEnd
class CheckImage,PullSuccess,CheckContainer,RunCommand decision
class PullImage,TagImage,BuildImage,CreateContainer,StartContainer,ExecContainer,ExecuteCmd,InteractiveShell,WorkInContainer,PersistChanges process
class MCPServers,Unsplash,Context7,Playwright mcp
```