Claude Code Development Container - Multi-language Docker container with DNS filtering A developer published claude-polyglot, a multi-language Docker development container for running Anthropic's Claude Code CLI with DNS filtering enabled by default. The container restricts network access to api.anthropic.com and claude.ai unless the --network flag is passed, and supports mounting Claude configuration and command history along with a --yolo mode that runs claude --dangerously-skip-permissions. | | /usr/bin/env bash | | | set -euo pipefail | | | | | | claude-polyglot: Run the Claude Code Polyglot development container | | | Usage: claude-polyglot OPTIONS | | | | | | Options: | | | --build Build the container image before running | | | --no-config Don't mount Claude Code configuration | | | --no-history Don't mount command history | | | --network Disable DNS filtering allow all network access | | | --yolo Run claude --dangerously-skip-permissions | | | --help Show this help message | | | | | | Examples: | | | claude-polyglot Run with DNS filtering Claude API only | | | claude-polyglot --build Rebuild and run | | | claude-polyglot --network Run with full network access | | | claude-polyglot --yolo Run Claude without permission checks | | | claude-polyglot zsh Run with zsh command | | | claude-polyglot cargo build Run Rust cargo | | | claude-polyglot python3 script.py Run Python script | | | claude-polyglot swipl -s file.pl Run Prolog file | | | claude-polyglot ruff check . Run ruff linter | | | END HELP | | | | | | IMAGE NAME="claude-polyglot:latest" | | | BUILD=false | | | MOUNT CONFIG=true | | | MOUNT HISTORY=true | | | UNRESTRICTED NETWORK=false | | | YOLO MODE=false | | | DOCKER ARGS= | | | COMMAND ARGS= | | | | | | Whitelisted domains for DNS filtering | | | WHITELISTED DOMAINS= | | | "api.anthropic.com" | | | "claude.ai" | | | | | | | | | Parse arguments | | | while $ -gt 0 ; do | | | case $1 in | | | --build | | | BUILD=true | | | shift | | | ;; | | | --no-config | | | MOUNT CONFIG=false | | | shift | | | ;; | | | --no-history | | | MOUNT HISTORY=false | | | shift | | | ;; | | | --network | | | UNRESTRICTED NETWORK=true | | | shift | | | ;; | | | --yolo | | | YOLO MODE=true | | | shift | | | ;; | | | --help | | | sed -n '/^ claude-polyglot:/,/^ END HELP/p' "$0" \| sed 's/^ //' \| sed 's/^ $//' \| grep -v '^END HELP$' | | | exit 0 | | | ;; | | | | | | COMMAND ARGS+= "$1" | | | shift | | | ;; | | | esac | | | done | | | | | | Build if requested | | | if "$BUILD" = true ; then | | | SCRIPT DIR="$ cd "$ dirname "${BASH SOURCE 0 }" " && pwd " | | | echo "Building $IMAGE NAME..." | | | docker build -t "$IMAGE NAME" "$SCRIPT DIR" | | | fi | | | | | | Check if image exists | | | if docker image inspect "$IMAGE NAME" & /dev/null; then | | | echo "Error: Image $IMAGE NAME not found." | | | echo "Build it with: docker build -t $IMAGE NAME /path/to/container/polyglot" | | | echo "Or run: $ basename "$0" --build" | | | exit 1 | | | fi | | | | | | Setup volume mounts | | | DOCKER ARGS+= | | | "-v" "$ pwd :/workspace" | | | | | | | | | if "$MOUNT CONFIG" = true && -d "$HOME/.claude" ; then | | | DOCKER ARGS+= "-v" "$HOME/.claude:/home/node/.claude" | | | fi | | | | | | if "$MOUNT HISTORY" = true ; then | | | DOCKER ARGS+= "-v" "claude-polyglot-history:/commandhistory" | | | fi | | | | | | DNS filtering by default, unrestricted network when --network is specified | | | if "$UNRESTRICTED NETWORK" = false ; then | | | Enable network but filter DNS - only allow whitelisted domains | | | echo "Enabling DNS filtering Claude API access only ..." | | | | | | Resolve whitelisted domains and add as host entries | | | for domain in "${WHITELISTED DOMAINS @ }"; do | | | Resolve domain to IP addresses | | | ips=$ dig +short "$domain" 2 /dev/null \| grep -E '^ 0-9 +\. 0-9 +\. 0-9 +\. 0-9 +$' | | | | | | if -n "$ips" ; then | | | Add first IP as host entry | | | first ip=$ echo "$ips" \| head -1 | | | DOCKER ARGS+= "--add-host" "${domain}:${first ip}" | | | echo " ✓ ${domain} - ${first ip}" | | | else | | | echo " ⚠ Warning: Could not resolve ${domain}" | | | fi | | | done | | | | | | Set DNS to non-existent server to block all other lookups | | | DOCKER ARGS+= "--dns" "0.0.0.0" | | | else | | | echo "DNS filtering disabled - full network access enabled" | | | fi | | | | | | If no command specified, run interactive shell or Claude in YOLO mode | | | if ${ COMMAND ARGS @ } -eq 0 ; then | | | DOCKER ARGS+= "-it" | | | if "$YOLO MODE" = true ; then | | | COMMAND ARGS= "claude" "--dangerously-skip-permissions" | | | else | | | COMMAND ARGS= "zsh" | | | fi | | | else | | | If command is provided, determine if we need interactive mode | | | case "${COMMAND ARGS 0 }" in | | | bash\|zsh\|sh\|claude | | | DOCKER ARGS+= "-it" | | | ;; | | | swipl\|python\|python3\|ipython | | | Only interactive if no additional arguments | | | if ${ COMMAND ARGS @ } -eq 1 ; then | | | DOCKER ARGS+= "-it" | | | fi | | | ;; | | | esac | | | fi | | | | | | Run the container | | | exec docker run --rm "${DOCKER ARGS @ }" "$IMAGE NAME" "${COMMAND ARGS @ }" |