Files
claude-docker/dockerfile.md

3.9 KiB

Dockerfile Notes

Base image

FROM node:24-bookworm-slim

Uses the official Node.js 24 image on Debian Bookworm (slim variant). Node.js is required because claude is a Node.js application distributed as a self-contained binary.

The slim variant strips documentation and locale files to keep the image small, while still including everything needed to run Node apps.

Note: This image ships with a node user and node group, both at UID/GID 1000. This is a convention in official Docker images — providing a ready-made unprivileged user so containers don't run as root by default. We replace this user with claude (see below).


System packages

RUN apt-get update && apt-get install -y \
    git curl wget jq netcat-openbsd socat \
    iputils-ping iproute2 dnsutils python3 \
    unzip zstd procps lsof psmisc \
    && rm -rf /var/lib/apt/lists/*

Tools installed for use inside the container:

Package Purpose
git Version control
curl, wget HTTP requests / file downloads
jq JSON processing on the command line
netcat-openbsd TCP/UDP connection testing (nc)
socat Multipurpose socket relay
iputils-ping ping command
iproute2 ip command, network inspection
dnsutils dig, nslookup
python3 Scripting
unzip Zip archive extraction
zstd Zstandard compression/decompression
procps ps, top, process inspection
lsof List open files / sockets
psmisc fuser, killall, pstree

The rm -rf /var/lib/apt/lists/* at the end discards the apt package index so it doesn't bloat the image layer.


UID/GID build args

ARG UID=1000
ARG GID=1000

Build-time arguments that control which UID and GID the claude user gets inside the container. The defaults are 1000/1000 (the most common primary user on Linux desktops).

The purpose is to match the host system's user, so that files written inside the container (e.g. in a mounted workspace volume) are owned by the correct user on the host — avoiding permission issues.

Pass these at build time to override:

docker build --build-arg UID=$(id -u) --build-arg GID=$(id -g) .

Claude binary installation

RUN GCS="https://storage.googleapis.com/..." \
    && VERSION=$(curl -fsSL "$GCS/latest") \
    && CHECKSUM=$(curl -fsSL "$GCS/$VERSION/manifest.json" | jq -r '.platforms["linux-x64"].checksum') \
    && curl -fsSL "$GCS/$VERSION/linux-x64/claude" -o /tmp/claude \
    && echo "$CHECKSUM  /tmp/claude" | sha256sum -c \
    && mv /tmp/claude /usr/local/bin/claude \
    && chmod +x /usr/local/bin/claude

Downloads the latest claude release from Google Cloud Storage:

  1. Fetches the current version string from latest
  2. Fetches the expected SHA-256 checksum from manifest.json
  3. Downloads the linux-x64 binary to /tmp/claude
  4. Verifies the checksum before installing — build fails if it doesn't match
  5. Moves the binary to /usr/local/bin/claude and makes it executable

User setup

RUN userdel node && groupdel node \
    && groupadd -g $GID claude \
    && useradd -u $UID -g $GID -m -s /bin/bash claude
USER claude

The base image's node user and group are removed first to free up UID/GID 1000 (or whatever was passed in). A claude user and group are then created in their place.

  • -m creates a home directory at /home/claude
  • -s /bin/bash sets bash as the login shell
  • USER claude switches all subsequent instructions (and the running container) to this unprivileged user

Workspace and entrypoint

WORKDIR /workspace

CMD ["claude"]

/workspace is the default working directory — intended to be bind-mounted from the host:

docker run -it -v "$PWD:/workspace" claude-image

CMD ["claude"] launches the Claude Code CLI when the container starts.