Skip to content

Running Claude Code Inside Docker

This setup runs Claude Code CLI inside the Docker container with full GUI and MCP Playwright support.

Architecture

┌─────────────────────────────────────────────┐
│  Docker Container: playwright-gui           │
│  Network: host mode (for Tailscale)         │
│                                             │
│  ┌─────────────────────────────────────┐   │
│  │  Xvfb (Virtual Display :99)         │   │
│  │  ├─ XFCE4 Desktop                   │   │
│  │  └─ Chromium (Headed Mode)          │   │
│  └─────────────────────────────────────┘   │
│                                             │
│  ┌─────────────────────────────────────┐   │
│  │  Claude Code CLI v2.0.31            │   │
│  │  └─ MCP Playwright (GUI-enabled)    │   │
│  └─────────────────────────────────────┘   │
│                                             │
│  ┌─────────────────────────────────────┐   │
│  │  Tailscale (100.126.2.91)           │◄──┼─── Remote Access
│  └─────────────────────────────────────┘   │
│                                             │
│  ┌─────────────────────────────────────┐   │
│  │  SSH Server (Port 2222)             │◄──┼─── n8n/External Access
│  └─────────────────────────────────────┘   │
│                                             │
│  ┌─────────────────────────────────────┐   │
│  │  VNC Server (Port 5900)             │◄──┼─── VNC Client (debugging)
│  └─────────────────────────────────────┘   │
│                                             │
│  Volumes:                                   │
│  - /work/nutri-e (repository, r/w)          │
│  - /gdrive (Google Drive, read-only)        │
│  - /output (generated images, write)        │
│  - playwright-storage (auth/sessions)       │
└─────────────────────────────────────────────┘

Setup Instructions

1. Rebuild Container with Claude Code

# Stop and remove old container
docker compose -f docker-compose.playwright-gui.yml down

# Rebuild with Claude Code CLI
docker compose -f docker-compose.playwright-gui.yml build

# Start container
docker compose -f docker-compose.playwright-gui.yml up -d

# Check logs
docker compose -f docker-compose.playwright-gui.yml logs -f

2. Launch Claude Code Inside Container

# SSH into container (choose one method):

# Option 1: Via Tailscale IP (remote access)
ssh root@<tailscale-ip> -p 2222
# Example: ssh root@100.126.2.91 -p 2222

# Option 2: Via public IP (if available)
ssh root@<public-ip> -p 2222

# Option 3: Via localhost (from same machine)
ssh root@localhost -p 2222

# Password: playwright

# Navigate to work directory
cd /work/nutri-e

# Launch Claude Code (you'll need to authenticate on first run)
claude-code

# Or run a specific command
claude-code "help me test the chatgpt automation"

# Optional: Use tmux for persistent sessions
tmux new -s claude
# Inside tmux, run claude-code
# Detach with: Ctrl+B, then D
# Reattach with: tmux attach -t claude

3. Using MCP Playwright from Claude Code

Claude Code running inside the container has access to MCP Playwright with GUI support.

Example tasks Claude can do: - Navigate to ChatGPT with real GUI - Interact with web pages using Playwright - Run automation scripts and debug visually via VNC - Generate images using ChatGPT DALL-E

MCP Configuration (already set up at /root/.mcp.json):

{
  "mcpServers": {
    "playwright": {
      "command": "npx",
      "args": ["-y", "@executeautomation/playwright-mcp-server"],
      "env": {
        "DISPLAY": ":99",
        "PLAYWRIGHT_BROWSERS_PATH": "/root/.cache/ms-playwright"
      }
    }
  }
}

4. Debugging via VNC

While Claude Code is working, you can watch the browser in real-time:

# Connect VNC client to:
# Host: localhost
# Port: 5901
# Password: playwright

You'll see: - Chromium browser running in headed mode - All Playwright interactions happening live - Any popup dialogs or UI elements

n8n Integration

Triggering Claude Code from n8n

You can trigger Claude Code inside the container from n8n workflows:

# SSH from n8n into container
ssh root@playwright-gui -p 22 \
  "cd /work/nutri-e && claude-code 'generate iron intro frames'"

Note: When n8n and playwright-gui are on the same Docker network, use playwright-gui as hostname instead of localhost.

Advantages

Unified Environment - Everything runs in one container ✅ True GUI Support - Playwright runs in headed mode with real X11 display ✅ MCP Playwright - Claude Code can use Playwright MCP tools directly ✅ No VNC Complexity - No need to run MCP tools from outside Docker ✅ Persistent Sessions - Playwright auth cookies persist across runs ✅ Easy Debugging - VNC available for visual monitoring ✅ Docker-to-Docker - n8n can SSH directly to container

Tailscale Auto-Authentication

To avoid manual Tailscale login each time the container recreates, use a Tailscale auth key:

  1. Generate reusable auth key: https://login.tailscale.com/admin/settings/keys
  2. Set environment variable:
    export TAILSCALE_AUTH_KEY="tskey-auth-XXXXXXXXXXXX"
    # OR create .env file
    echo 'TAILSCALE_AUTH_KEY=tskey-auth-XXXXXXXXXXXX' > .env
    
  3. Restart container - Tailscale will auto-connect!

See DOCKER_TAILSCALE_SETUP.md for complete setup guide.

Infrastructure Verification

The following components have been verified and are working:

# ✅ Claude Code CLI installed
root@playwright-gui:/work/nutri-e# which claude-code
/usr/local/bin/claude-code

root@playwright-gui:/work/nutri-e# claude-code --version
2.0.31 (Claude Code)

# ✅ MCP configuration exists and properly configured
root@playwright-gui:/work/nutri-e# cat /root/.mcp.json
{
  "mcpServers": {
    "playwright": {
      "command": "npx",
      "args": ["-y", "@executeautomation/playwright-mcp-server"],
      "env": {
        "DISPLAY": ":99",
        "PLAYWRIGHT_BROWSERS_PATH": "/root/.cache/ms-playwright"
      }
    }
  }
}

# ✅ Xvfb display server running
root@playwright-gui:/work/nutri-e# ps aux | grep Xvfb | grep -v grep
root  129  0.2  1.5 277304 126312 pts/0  S+  14:29  0:01 Xvfb :99 -screen 0 1920x1080x24

# ✅ DISPLAY variable set correctly
root@playwright-gui:/work/nutri-e# echo $DISPLAY
:99

# ✅ Playwright browsers installed
root@playwright-gui:/work/nutri-e# ls /root/.cache/ms-playwright/
chromium-1194  chromium_headless_shell-1194  ffmpeg-1011

# ✅ Repository cloned with full git history
root@playwright-gui:/work/nutri-e# git status
On branch main
Your branch is up to date with 'origin/main'.

Status: All components are verified and ready for interactive testing via SSH.

Next Step: SSH into container and launch Claude Code interactively to test MCP Playwright integration.

Troubleshooting

Claude Code not found

# Install Claude Code CLI
npm install -g @anthropic-ai/claude-code

# Verify installation
which claude-code
claude-code --version

MCP Playwright not working

# Check MCP config
cat /root/.mcp.json

# Test Playwright MCP manually
npx -y @executeautomation/playwright-mcp-server

Display issues

# Check Xvfb is running
ps aux | grep Xvfb

# Verify DISPLAY variable
echo $DISPLAY
# Should show: :99

# Test display
DISPLAY=:99 xdpyinfo

ChatGPT automation still failing

If automation fails even with GUI support: 1. Connect via VNC to see what's actually happening 2. Check if selectors need updating (ChatGPT UI changes) 3. Try increasing wait times in the script 4. Debug interactively using Claude Code with MCP Playwright tools

Next Steps

  1. Rebuild container with Claude Code
  2. SSH in and test Claude Code launch
  3. Try having Claude Code run the ChatGPT automation using MCP Playwright
  4. Set up n8n workflow to trigger automation via SSH