You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Problem: Need to run Claude Code with --dangerously-skip-permissions inside DDEV containers safely, as an alternative to the official devcontainer.
Solution: DDEV addon that installs Claude Code + iptables firewall (ported from official devcontainer) into the web container. Firewall restricts outbound to whitelisted domains only, preventing exfiltration. Includes SSH-based git signing and OAuth credential persistence.
Key decisions:
Firewall adapted from official devcontainer, with DDEV-specific allowances (Docker networking, inbound HTTP)
SSH signing instead of GPG/1Password
Extra domains configurable via extra-domains.txt (one per line)
OAuth login for API key, persisted in named Docker volume
#\!/bin/bash#ddev-generated## Description: Run Claude Code with --dangerously-skip-permissions## Usage: claude [flags] [args]## Example: "ddev claude" or "ddev claude --help"## ExecRaw: true
claude --dangerously-skip-permissions "$@"
claude-code/init-firewall.sh
Adapt from official script with these DDEV-specific changes:
Allow RFC1918 private ranges — covers all Docker networking (db, router, ssh-agent, host) without needing to discover specific CIDRs
Allow inbound HTTP on ports 80, 443, 8025 (Mailpit), 5173 (Vite) — web container must keep serving WordPress
Skip aggregate — add GitHub CIDRs individually via jq
Non-fatal warnings — DNS resolution failures warn but don't exit
DROP policies last — prevents bricking container if script fails midway
claude-code/extra-domains.example.txt
# Add project-specific domains here, one per line.
# Copy this file to extra-domains.txt and add your domains.
# Example:
# satis.example.com
# my-api.example.com
claude-code/.gitignore
.claude/
.claude.json
Open Questions
Multiple SSH keys in agent — ssh-add -L | head -1 takes the first. Match by fingerprint/comment instead?
Pin @anthropic-ai/claude-code version or use @latest?
Does ${DDEV_USER} resolve in docker-compose.yaml context?
Overview
Problem: Need to run Claude Code with
--dangerously-skip-permissionsinside DDEV containers safely, as an alternative to the official devcontainer.Solution: DDEV addon that installs Claude Code + iptables firewall (ported from official devcontainer) into the web container. Firewall restricts outbound to whitelisted domains only, preventing exfiltration. Includes SSH-based git signing and OAuth credential persistence.
Key decisions:
extra-domains.txt(one per line)ALL ALLsudoers for portability across DDEV usersReference implementations:
Task Checklist
1. Repository Setup
install.yaml— verify: valid YAML with all project_files listed.gitignore2. Dockerfile & Docker Compose
web-build/Dockerfile.claude-code— install iptables, ipset, iproute2, dnsutils, jq, claude-code, sudoers entrydocker-compose.claude-code.yaml— NET_ADMIN/NET_RAW caps, named volume for claude config persistence${DDEV_USER}resolves in docker-compose context; if not, use fixed path +CLAUDE_CONFIG_DIRenv var3. Firewall Script
claude-code/init-firewall.shadapted from official devcontainer/metaAPI, add to ipset (noaggregate, add individually)api.anthropic.com,statsig.anthropic.com,statsig.com,sentry.io,registry.npmjs.org,packagist.org,repo.packagist.org,getcomposer.org,api.wordpress.org,downloads.wordpress.orgextra-domains.txtif it existsexample.com, allowapi.anthropic.comchmod +x4. Hooks & Config
config.claude-code.yamlwith post-start hooks~/.ssh/signing-key.pubgpg.format=ssh,commit.gpgsign=true)5. Command Wrapper
commands/web/claudewithExecRaw: truefor TTY passthrough--dangerously-skip-permissionsflag6. Domain Customization
claude-code/extra-domains.example.txtwith instructionsclaude-code/.gitignoreto ignore auth data7. Documentation
8. Testing
ddev restartsucceeds without errorsddev exec curl --connect-timeout 3 https://example.comfails (blocked)ddev exec curl --connect-timeout 3 https://api.anthropic.comsucceedsddev claude --helpworks with TTYddev exec git log --show-signature -1shows SSH signatureddev restartCompletion Signal
All checkboxes checked + addon installs cleanly + firewall verification passes + WordPress still works = DONE
Implementation Details
install.yaml
web-build/Dockerfile.claude-code
docker-compose.claude-code.yaml
Note: verify
${DDEV_USER}resolves. Fallback: fixed path +CLAUDE_CONFIG_DIRenv var.config.claude-code.yaml
commands/web/claude
claude-code/init-firewall.sh
Adapt from official script with these DDEV-specific changes:
EXTRA_DOMAINS_FILE="/mnt/ddev_config/claude-code/extra-domains.txt", parse non-comment non-empty linesaggregate— add GitHub CIDRs individually via jqclaude-code/extra-domains.example.txt
claude-code/.gitignore
Open Questions
ssh-add -L | head -1takes the first. Match by fingerprint/comment instead?@anthropic-ai/claude-codeversion or use@latest?${DDEV_USER}resolve in docker-compose.yaml context?