Skip to content

Instantly share code, notes, and snippets.

@simonw
Created September 30, 2025 18:33
Show Gist options
  • Save simonw/ad81a19456fe0b7e17256f429e013d0c to your computer and use it in GitHub Desktop.
Save simonw/ad81a19456fe0b7e17256f429e013d0c to your computer and use it in GitHub Desktop.
Docs generated using Claude Code against its own repo

Claude Code Devcontainer

A secure, isolated development environment for Claude Code with network restrictions and pre-configured development tools.

Overview

This devcontainer provides a sandboxed environment for Claude Code with:

  • Network firewall restrictions limiting outbound connections to approved domains
  • Pre-installed development tools (git, gh CLI, zsh, fzf)
  • VS Code extensions (Claude Code, ESLint, Prettier, GitLens)
  • Persistent command history and configuration
  • Node.js 20 runtime environment

Prerequisites

Quick Start

  1. Open in VS Code

    code /path/to/your/project
  2. Open Command Palette (Cmd+Shift+P / Ctrl+Shift+P)

  3. Select: Dev Containers: Reopen in Container

  4. Wait for the container to build and start (first run takes a few minutes)

Features

Network Security

The container runs with a restrictive firewall that only allows connections to:

  • GitHub: API, web, and git operations
  • npm registry: Package installations
  • Anthropic API: Claude Code functionality
  • VS Code services: Marketplace and updates
  • Monitoring: Sentry, Statsig
  • SSH: Port 22 for git operations
  • Local network: Container-to-host communication

All other outbound connections are blocked. The firewall is initialized on container startup via /usr/local/bin/init-firewall.sh.

Pre-installed Tools

  • Node.js 20: JavaScript/TypeScript runtime
  • Claude Code CLI: Latest version
  • git & GitHub CLI (gh): Version control
  • zsh: Enhanced shell with Oh My Zsh
  • git-delta: Better git diffs
  • fzf: Fuzzy finder
  • Text editors: nano (default), vim

VS Code Configuration

Extensions:

  • anthropic.claude-code: Claude Code assistant
  • dbaeumer.vscode-eslint: JavaScript linting
  • esbenp.prettier-vscode: Code formatting
  • eamodio.gitlens: Git integration

Settings:

  • Format on save enabled
  • ESLint auto-fix on save
  • Prettier as default formatter
  • zsh as default terminal

Persistent Storage

Two volumes maintain state across container rebuilds:

  • Command history: /commandhistory - preserves bash/zsh history
  • Claude config: /home/node/.claude - stores Claude Code settings

Configuration

Dockerfile Arguments

Customize the build in devcontainer.json:

"build": {
  "args": {
    "TZ": "${localEnv:TZ:America/Los_Angeles}",
    "CLAUDE_CODE_VERSION": "latest",
    "GIT_DELTA_VERSION": "0.18.2",
    "ZSH_IN_DOCKER_VERSION": "1.2.0"
  }
}

Environment Variables

Set in the container environment:

  • NODE_OPTIONS: Memory limit (default: 4GB)
  • CLAUDE_CONFIG_DIR: Claude settings location
  • EDITOR / VISUAL: Default text editor (nano)
  • SHELL: Default shell (zsh)

Adding Allowed Domains

To allow additional domains, edit init-firewall.sh and add to the domain list around line 67:

for domain in \
    "registry.npmjs.org" \
    "api.anthropic.com" \
    "your-domain.com"; do

Then rebuild the container: Dev Containers: Rebuild Container

Usage

First-time Setup

After opening the container:

  1. Configure Claude Code (if not already done):

    claude auth
  2. Verify firewall:

    # Should fail (blocked)
    curl https://example.com
    
    # Should succeed (allowed)
    curl https://api.github.com/zen

Daily Development

# Use Claude Code CLI
claude chat

# Install npm packages (registry allowed)
npm install package-name

# Git operations (GitHub allowed)
git clone https://github.com/user/repo
gh pr list

# Use zsh with fzf for fuzzy finding
# Ctrl+R: Search command history
# Ctrl+T: Search files

Troubleshooting

Container won't start:

  • Ensure Docker Desktop is running
  • Check docker logs <container-id> for errors
  • Verify --cap-add=NET_ADMIN is supported on your system

Firewall blocking needed domains:

  • Add domains to init-firewall.sh
  • Rebuild container
  • Or temporarily disable: sudo iptables -P OUTPUT ACCEPT (not recommended)

Command history not persisting:

  • Volume may not be mounted correctly
  • Check: docker volume ls | grep claude-code

Extensions not loading:

  • Rebuild container: Dev Containers: Rebuild Container
  • Check VS Code extension compatibility

Security Notes

⚠️ Important: This container has elevated network capabilities (NET_ADMIN, NET_RAW) to manage iptables. Only use in trusted environments.

The firewall configuration:

  • Blocks all outbound traffic by default
  • Uses ipset for efficient IP allowlisting
  • Validates DNS responses before adding IPs
  • Preserves Docker's internal DNS (127.0.0.11)
  • Verifies firewall is active on startup

Customization

Changing Default Shell to Bash

Edit devcontainer.json:

"terminal.integrated.defaultProfile.linux": "bash"

Installing Additional Tools

Add to Dockerfile before the USER node line:

RUN apt-get update && apt-get install -y your-package

Modifying VS Code Settings

Edit the customizations.vscode.settings section in devcontainer.json.

Architecture

  • Base image: node:20 (Debian-based)
  • User: node (non-root, uid 1000)
  • Workspace: /workspace (bind mount)
  • Working directory: Your project folder
  • Entrypoint: Standard Node.js container

License

See your project's LICENSE file.

Support

For issues specific to:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment