DevCon 4
DEFCON (Defense Readiness Condition) is the US military alert system. DEFCON 5 is peacetime. DEFCON 1 is nuclear war.
DevCon 4 is where we operate: heightened awareness, not full lockdown. Your development container is secured with a restrictive firewall, but you still have access to everything you need -- GitHub, Hex, Anthropic. Vigilant, but productive.
Devcontainer setup for Elixir projects. A Mix archive installer that generates
a complete .devcontainer/ configuration with Claude Code, a restrictive
firewall, and development tools.
What it generates
Three files are created in your project's .devcontainer/ directory:
| File | Purpose |
|---|---|
devcontainer.json | Container settings, volume mounts, VS Code extensions, and lifecycle commands |
Dockerfile | Elixir + Node.js image with Claude Code, zsh, git, and firewall tools |
init-firewall.sh | Restrictive outbound firewall allowing only essential domains |
Dockerfile details
The generated Dockerfile builds an image with:
- Elixir & Erlang -- from the official
hexpm/elixirimage (version configurable) - Node.js 20 -- required for Claude Code
- Claude Code -- installed globally via npm
- Shell -- zsh with git and fzf plugins
- Dev tools -- git, vim, nano, jq, gh (GitHub CLI), fzf, unzip
- Firewall tools -- iptables, ipset, iproute2, dnsutils, aggregate
- Non-root user --
developerwith passwordless sudo - Hex & Rebar -- pre-installed for Elixir development
Firewall details
The init-firewall.sh script applies a default-deny outbound policy, allowing
only these domains:
| Domain | Reason |
|---|---|
api.github.com, GitHub IP ranges | Git operations, GitHub CLI |
registry.npmjs.org | Claude Code installation/updates |
api.anthropic.com | Claude Code API access |
sentry.io | Claude Code error reporting |
statsig.anthropic.com, statsig.com | Claude Code telemetry |
repo.hex.pm, builds.hex.pm, hex.pm | Elixir package management |
DNS (port 53), SSH (port 22), and localhost are always allowed.
Installation
mix archive.install hex devcon4Usage
Run in any Elixir project:
mix devcon4.installOptions
All options have sensible defaults. Override them as needed:
| Option | Default | Description |
|---|---|---|
--elixir-version | 1.18.3 | Elixir version for the base Docker image |
--erlang-version | 27.3.3 | Erlang/OTP version for the base Docker image |
--ubuntu-version | noble | Ubuntu release codename |
--ubuntu-date-tag | 20260217 |
Ubuntu image date tag from hexpm/elixir |
--timezone | America/Sao_Paulo |
Default timezone fallback (host $TZ takes priority) |
--force | false | Overwrite existing files without prompting |
Examples
Install with defaults:
mix devcon4.installInstall with custom Elixir/Erlang versions:
mix devcon4.install \
--elixir-version 1.17.0 \
--erlang-version 26.2.1Starting the container
Via terminal (devcontainer CLI)
# Build and start the container
devcontainer up --workspace-folder .
# Execute commands inside the container
devcontainer exec --workspace-folder . mix test
devcontainer exec --workspace-folder . claude
# Enter an interactive shell
docker exec -it <container_id> zsh
# Rebuild after changing devcontainer files
devcontainer up --workspace-folder . --rebuild-if-existsVia VS Code
- Install the Dev Containers extension
- Open the project folder
-
Press
Ctrl+Shift+Pand select Dev Containers: Reopen in Container - The ElixirLS extension is automatically installed
Using Claude Code inside the container
Once inside the container, Claude Code is available globally:
claude # Start Claude Code
claude --dangerously-skip-permissions # Unattended mode (use with caution)
The Claude Code configuration is persisted across container rebuilds via a
Docker volume mounted at /home/developer/.claude.
Customization
After installation, the generated files are yours to modify. Common customizations:
Adding firewall domains
Edit .devcontainer/init-firewall.sh and add domains to the for domain in
loop:
for domain in \
"registry.npmjs.org" \
"api.anthropic.com" \
...
"your-domain.example.com"; do # <-- add hereAdding system packages
Edit .devcontainer/Dockerfile and add packages to the apt-get install line:
RUN apt-get update && apt-get install -y --no-install-recommends \
...
postgresql-client \ # <-- add here
&& apt-get clean && rm -rf /var/lib/apt/lists/*Adding VS Code extensions
Edit .devcontainer/devcontainer.json:
"customizations": {
"vscode": {
"extensions": [
"JakeBecker.elixir-ls",
"your.extension-id"
]
}
}Changing container settings
Edit .devcontainer/devcontainer.json. Common changes:
postCreateCommand-- add project-specific setup stepsforwardPorts-- expose ports to the host (e.g.,[4000]for Phoenix)containerEnv-- add environment variables
Security considerations
The firewall restricts outbound network access to a whitelist of domains. This provides meaningful isolation but is not a complete sandbox:
- A malicious project could still access any whitelisted domain
- Claude Code credentials are accessible inside the container
-
The
developeruser has passwordless sudo
Only use devcontainers with repositories you trust.
The --dangerously-skip-permissions flag for Claude Code is designed for use
within this restricted environment. It allows Claude Code to operate without
interactive permission prompts, which is useful for automated workflows. The
firewall limits the blast radius of any unintended actions.
Finding available image tags
The base image tag follows the pattern
hexpm/elixir:{elixir}-erlang-{erlang}-ubuntu-{ubuntu}-{date}. To find
available tags:
# Search for tags matching your desired versions
curl -s "https://hub.docker.com/v2/repositories/hexpm/elixir/tags?page_size=100&name=1.18" \
| jq -r '.results[].name' | grep noble | sort -VLicense
Apache-2.0