Claude Code devcontainer setup for the terminal
2025-12-11
I wanted to try out what the Anthropic docs call Safe
YOLO mode and let Claude Code run in a container with
claude --dangerously-skip-permissions.
Why restricting Claude code to a container is probably best explained in Simon Willisons lethal trifecta blog post. Also it‘s one of the viable options he listed in his other great article about how to design agentic loops.
Anthropic’s documentation for devcontainers is mostly targeted at VS Code users but it’s easy to adapt for running it in a terminal and extend. In my case I also wanted Claude Code to have access to a local PostgreSQL database to test how well it can perform database migrations.
For containerization I tried out podman as a docker alternative. Podman triggered my interest after I came across this great article. This guide assumes that podman is already installed on the machine.
1. Use Official Claude Code Devcontainer Files
This guide uses the devcontainer configuration from Anthropic’s official claude-code repository.
Licensing note: These files are from Anthropic’s public repository and are subject to their Commercial Terms of Service. This tutorial assumes you’re using them in compliance with Anthropic’s terms for personal testing and development purposes.
Download the Dockerfile and init-firewall.sh files onto your machine:
# From your project root
mkdir -p .devcontainer
cd .devcontainer
# Download the two core files from the official repo
curl -o Dockerfile https://raw.githubusercontent.com/anthropics/claude-code/main/.devcontainer/Dockerfile
curl -o init-firewall.sh https://raw.githubusercontent.com/anthropics/claude-code/main/.devcontainer/init-firewall.sh
# Make firewall script executable
chmod +x init-firewall.sh
cd ..
The additional devcontainer.json can be skipped for terminal usage.
At the end of the Dockerfile find the CMD line and replace it to chain firewall initialization:
CMD ["/bin/bash", "-c", "sudo /usr/local/bin/init-firewall.sh"]
And that’s already the setup for the standard image. Now we need to build the image and start the container.
2. Container workflow
Build the image:
podman build -t claude-test:latest -f .devcontainer/Dockerfile .devcontainer/
Run the container and mount the current working directory as volume.
Also if you want to be able to continue session with claude code it can
be helpful to also mount your .claude/ directory:
podman run -d \
--name claude-test \
--cap-add=NET_ADMIN \
--cap-add=NET_RAW \
-v "$(pwd):/workspace" \
-v "$HOME/.claude:/home/node/.claude" \
-w /workspace \
claude-test:latest
To rebuild after changes, stop and remove the old container first:
podman stop claude-test
podman rm claude-test
podman build -t claude-test:latest -f .devcontainer/Dockerfile .devcontainer/
# Then run again with podman run ...
Important flags: -
--cap-add=NET_ADMIN --cap-add=NET_RAW - Required for
firewall initialization - -v "$(pwd):/workspace" - Mounts
your current directory -
-v "$HOME/.claude:/home/node/.claude" - Shares Claude
authentication/config with host
Attach to the container
podman exec -it claude-test /bin/bash
Verify Setup and start Claude Code
# Test firewall (should fail)
curl https://example.com
# Test firewall (should succeed)
curl https://api.github.com/zen
Now you should be able to to run claude code on your machine in a mostly safe manner with
claude --dangerously-skip-permissions
First-time authentication
On macOS, Claude Code stores authentication in the Keychain, which
isn’t accessible inside the container. However, the container runs
Linux, which stores credentials in ~/.claude/ files
instead.
Since we mount ~/.claude from the host into the
container, you only need to login once inside the container:
# Inside the container
claude --dangerously-skip-permissions
# Complete the browser login flow
The Linux credentials are saved to ~/.claude/ on your
Mac. Future container starts will have authentication automatically - no
login needed.
3. Add PostgreSQL (Optional)
I wanted to test how well Claude Code could be for database migration. To enable it to loop itself to a working migration I wanted to provide it with a complete database restored from a dump file and also give it the capabilities to restore it to it’s original state.
The following chapter explains, how to install and start a PostgreSQL
within the container including the initialization of a
test_database based on a database dump.
Open .devcontainer/Dockerfile and add the PostgreSQL
section after the system dependencies (after line 27,
following the first apt-get install block). This installs
PostgreSQL, sets environment variables for easier database access, and
enable database access without password.
Caution: I enabled access without password to make my life easier. Not sure if it’s even needed but at the end it worked for me so I kept it. Please do not use this setup for production only for testing purposes.
# ============================================================================
# PostgreSQL server installation and configuration
# ============================================================================
# Install latest PostgreSQL server and client
RUN apt-get update \
&& apt-get install -y postgresql-common \
&& /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh -y \
&& apt-get install -y postgresql postgresql-client \
&& rm -rf /var/lib/apt/lists/*
# Configure PostgreSQL with trust authentication
RUN PG_VERSION=$(ls /etc/postgresql/ | head -n1) && \
echo "local all all trust" > /etc/postgresql/$PG_VERSION/main/pg_hba.conf && \
echo "host all all 127.0.0.1/32 trust" >> /etc/postgresql/$PG_VERSION/main/pg_hba.conf && \
echo "host all all ::1/128 trust" >> /etc/postgresql/$PG_VERSION/main/pg_hba.conf
# PostgreSQL environment variables
ENV PGHOST=localhost
ENV PGPORT=5432
ENV PGDATABASE=testing_db
ENV PGUSER=postgres
# Allow passwordless sudo for PostgreSQL service management only
RUN echo "node ALL=(root) NOPASSWD: /usr/sbin/service postgresql *" > /etc/sudoers.d/node-postgres && \
chmod 0440 /etc/sudoers.d/node-postgres
Modify the CMD Line, to chain both firewall initialization and PostgreSQL startup:
# Default command - start firewall and PostgreSQL, then keep container running
CMD ["/bin/bash", "-c", "sudo /usr/local/bin/init-firewall.sh && sudo service postgresql start && tail -f /dev/null"]
Verify PostgreSQL started correctly by running these commands inside the container:
# Wait for "PostgreSQL Ready!"
until psql -c '\q' 2>/dev/null; do sleep 1; done && echo 'PostgreSQL Ready'
psql -c 'SELECT version();'
Now we have Claude Code and PostgreSQL installed and running in a container.
4. Database workflow
As mentioned I wanted to provide Claude code with a way to initialize
and restore the database by itself. For that I added a database dump
testing_db.dump and the following
init_and_restore.sh script to workspace directory.
#!/bin/bash
# Create database if it doesn't exist
DB_NAME='testing_db'
psql -tc "SELECT 1 FROM pg_database WHERE datname = '$DB_NAME'" | grep -q 1 || {
echo "Creating $DB_NAME..."
createdb $DB_NAME
}
# Restore the dump if it exists
if [ -f "/workspace/$DB_NAME.dump" ]; then
echo "Restoring database from dump..."
psql -d $DB_NAME -c 'DROP SCHEMA public CASCADE;'
psql -d $DB_NAME -c 'CREATE SCHEMA public;'
pg_restore -d $DB_NAME -Fc /workspace/$DB_NAME.dump
echo "Database restored successfully"
else
echo "Warning: No dump file found at /workspace/$DB_NAME.dump"
fi
And that’s already the final setup.
5. Summary
This guide demonstrates how to run Claude Code in a sandboxed Podman container with optional PostgreSQL database access, based on Anthropic’s official devcontainer configuration