-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDockerfile
More file actions
94 lines (76 loc) · 3.27 KB
/
Dockerfile
File metadata and controls
94 lines (76 loc) · 3.27 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# =============================================================================
# AgentSafe: Hardened Docker sandbox for local coding agents
# =============================================================================
# ---------------------------------------------------------------------------
# Stage 1: Build — install Claude CLI and strip unnecessary platform binaries
# ---------------------------------------------------------------------------
FROM node:22-slim AS builder
RUN npm install -g @anthropic-ai/claude-code @openai/codex \
&& find /usr/local/lib/node_modules/@anthropic-ai/claude-code \
-path "*/vendor/*" \( \
-name "win32*" -o \
-name "darwin*" -o \
-name "*jetbrains*" \
\) -exec rm -rf {} + 2>/dev/null || true
# ---------------------------------------------------------------------------
# Stage 2: Runtime — lean image with only what the agent needs
# ---------------------------------------------------------------------------
FROM node:22-slim
ARG CLAUDE_USER=claude
ARG CLAUDE_UID=1001
ARG CLAUDE_GID=1001
# System packages
RUN apt-get update && apt-get install -y --no-install-recommends \
python3 \
python3-pip \
python3-venv \
git \
curl \
jq \
openssh-server \
gosu \
iptables \
tini \
ca-certificates \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# sshd requires this directory
RUN mkdir -p /var/run/sshd
# Fix PAM for container: pam_loginuid fails without CAP_AUDIT_WRITE
RUN sed -i 's/session\s*required\s*pam_loginuid.so/session optional pam_loginuid.so/' /etc/pam.d/sshd
# Copy CLI packages from builder and create bin symlinks
COPY --from=builder /usr/local/lib/node_modules /usr/local/lib/node_modules
RUN ln -s /usr/local/lib/node_modules/@anthropic-ai/claude-code/cli.js /usr/local/bin/claude \
&& ln -s /usr/local/lib/node_modules/@openai/codex/bin/codex.js /usr/local/bin/codex
# Remove the node user/group from the base image to free UID/GID (e.g. 1000)
RUN userdel -r node 2>/dev/null || true \
&& groupdel node 2>/dev/null || true
# Create non-root user
RUN groupadd -g ${CLAUDE_GID} ${CLAUDE_USER} \
&& useradd -m -u ${CLAUDE_UID} -g ${CLAUDE_GID} -s /bin/bash ${CLAUDE_USER}
# Unlock account for sshd pubkey auth (! = locked, * = no password but not locked)
RUN sed -i 's/^claude:!:/claude:*:/' /etc/shadow
# Create directory structure
RUN mkdir -p /workspace \
/home/${CLAUDE_USER}/.claude/commands \
/home/${CLAUDE_USER}/.claude/hooks \
/home/${CLAUDE_USER}/.codex \
/home/${CLAUDE_USER}/.ssh \
&& chown -R ${CLAUDE_USER}:${CLAUDE_USER} \
/workspace \
/home/${CLAUDE_USER}/.claude \
/home/${CLAUDE_USER}/.codex \
/home/${CLAUDE_USER}/.ssh
# Set up a default Python venv so the agent never needs --break-system-packages
RUN python3 -m venv /home/${CLAUDE_USER}/.venv \
&& chown -R ${CLAUDE_USER}:${CLAUDE_USER} /home/${CLAUDE_USER}/.venv
# Add venv to PATH for all users
ENV PATH="/home/${CLAUDE_USER}/.venv/bin:${PATH}"
ENV VIRTUAL_ENV="/home/${CLAUDE_USER}/.venv"
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
WORKDIR /workspace
EXPOSE 22
EXPOSE 8000-8099
ENTRYPOINT ["tini", "--", "/entrypoint.sh"]
CMD ["claude"]