Skip to content

Commit 457744b

Browse files
feat: update openclaw Dockerfile
1 parent a461d42 commit 457744b

1 file changed

Lines changed: 81 additions & 13 deletions

File tree

openclaw/Dockerfile

Lines changed: 81 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,17 @@
1-
FROM node:22-bookworm
1+
FROM node:22-bookworm@sha256:cd7bcd2e7a1e6f72052feb023c7f6b722205d3fcab7bbcbd2d1bfdab10b1e935
2+
# OCI base-image metadata for downstream image consumers.
3+
#
4+
# If you change these annotations, also update:
5+
# - docs/install/docker.md ("Base image metadata" section)
6+
# - https://docs.openclaw.ai/install/docker
7+
LABEL org.opencontainers.image.base.name="docker.io/library/node:22-bookworm" \
8+
org.opencontainers.image.base.digest="sha256:cd7bcd2e7a1e6f72052feb023c7f6b722205d3fcab7bbcbd2d1bfdab10b1e935" \
9+
org.opencontainers.image.source="https://github.com/openclaw/openclaw" \
10+
org.opencontainers.image.url="https://openclaw.ai" \
11+
org.opencontainers.image.documentation="https://docs.openclaw.ai/install/docker" \
12+
org.opencontainers.image.licenses="MIT" \
13+
org.opencontainers.image.title="OpenClaw" \
14+
org.opencontainers.image.description="OpenClaw gateway and CLI runtime container image"
215

316
# Install Bun (required for build scripts)
417
RUN curl -fsSL https://bun.sh/install | bash
@@ -23,7 +36,9 @@ COPY --chown=node:node patches ./patches
2336
COPY --chown=node:node scripts ./scripts
2437

2538
USER node
26-
RUN pnpm install --frozen-lockfile
39+
# Reduce OOM risk on low-memory hosts during dependency installation.
40+
# Docker builds on small VMs may otherwise fail with "Killed" (exit 137).
41+
RUN NODE_OPTIONS=--max-old-space-size=2048 pnpm install --frozen-lockfile
2742

2843
# Optionally install Chromium and Xvfb for browser automation.
2944
# Build with: docker build --build-arg OPENCLAW_INSTALL_BROWSER=1 ...
@@ -42,30 +57,74 @@ RUN if [ -n "$OPENCLAW_INSTALL_BROWSER" ]; then \
4257
rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/*; \
4358
fi
4459

60+
# Optionally install Docker CLI for sandbox container management.
61+
# Build with: docker build --build-arg OPENCLAW_INSTALL_DOCKER_CLI=1 ...
62+
# Adds ~50MB. Only the CLI is installed - no Docker daemon.
63+
# Required for agents.defaults.sandbox to function in Docker deployments.
64+
ARG OPENCLAW_INSTALL_DOCKER_CLI=""
65+
ARG OPENCLAW_DOCKER_GPG_FINGERPRINT="9DC858229FC7DD38854AE2D88D81803C0EBFCD88"
66+
RUN if [ -n "$OPENCLAW_INSTALL_DOCKER_CLI" ]; then \
67+
apt-get update && \
68+
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
69+
ca-certificates curl gnupg && \
70+
install -m 0755 -d /etc/apt/keyrings && \
71+
# Verify Docker apt signing key fingerprint before trusting it as a root key.
72+
# Update OPENCLAW_DOCKER_GPG_FINGERPRINT when Docker rotates release keys.
73+
curl -fsSL https://download.docker.com/linux/debian/gpg -o /tmp/docker.gpg.asc && \
74+
expected_fingerprint="$(printf '%s' "$OPENCLAW_DOCKER_GPG_FINGERPRINT" | tr '[:lower:]' '[:upper:]' | tr -d '[:space:]')" && \
75+
actual_fingerprint="$(gpg --batch --show-keys --with-colons /tmp/docker.gpg.asc | awk -F: '$1 == "fpr" { print toupper($10); exit }')" && \
76+
if [ -z "$actual_fingerprint" ] || [ "$actual_fingerprint" != "$expected_fingerprint" ]; then \
77+
echo "ERROR: Docker apt key fingerprint mismatch (expected $expected_fingerprint, got ${actual_fingerprint:-<empty>})" >&2; \
78+
exit 1; \
79+
fi && \
80+
gpg --dearmor -o /etc/apt/keyrings/docker.gpg /tmp/docker.gpg.asc && \
81+
rm -f /tmp/docker.gpg.asc && \
82+
chmod a+r /etc/apt/keyrings/docker.gpg && \
83+
printf 'deb [arch=%s signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian bookworm stable\n' \
84+
"$(dpkg --print-architecture)" > /etc/apt/sources.list.d/docker.list && \
85+
apt-get update && \
86+
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
87+
docker-ce-cli docker-compose-plugin && \
88+
apt-get clean && \
89+
rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/*; \
90+
fi
91+
4592
USER node
4693
COPY --chown=node:node . .
94+
# Normalize copied plugin/agent paths so plugin safety checks do not reject
95+
# world-writable directories inherited from source file modes.
96+
RUN for dir in /app/extensions /app/.agent /app/.agents; do \
97+
if [ -d "$dir" ]; then \
98+
find "$dir" -type d -exec chmod 755 {} +; \
99+
find "$dir" -type f -exec chmod 644 {} +; \
100+
fi; \
101+
done
102+
47103
RUN pnpm build
104+
48105
# Force pnpm for UI build (Bun may fail on ARM/Synology architectures)
49106
ENV OPENCLAW_PREFER_PNPM=1
50107
RUN pnpm ui:build
51108

52-
ARG OPENCLAW_VERSION=""
53-
ENV OPENCLAW_VERSION=$OPENCLAW_VERSION
54-
ENV OPENCLAW_SERVICE_VERSION=$OPENCLAW_VERSION
55-
56-
ENV NODE_ENV=production
57-
58109
# ---- add openclaw command ----
59-
# Makes `openclaw ...` == `node /app/dist/index.js ...`
110+
# Makes `openclaw ...` follow the upstream launcher while preserving
111+
# the customized CMD shape used by this image.
60112
USER root
61113
RUN printf '%s\n' \
62114
'#!/bin/sh' \
63115
'set -e' \
64-
'exec node /app/dist/index.js "$@"' \
116+
'exec node /app/openclaw.mjs "$@"' \
65117
> /usr/local/bin/openclaw \
66118
&& chmod +x /usr/local/bin/openclaw
67119
# -----------------------------
68120

121+
USER node
122+
# Preinstall bundled plugin into the image so containers start with it present.
123+
# OpenClaw stores npm-installed plugins under ~/.openclaw/extensions by default.
124+
RUN openclaw plugins install @sliverp/qqbot@latest
125+
126+
ENV NODE_ENV=production
127+
69128
# Security hardening: Run as non-root user
70129
# The node:22-bookworm image includes a 'node' user (uid 1000)
71130
# This reduces the attack surface by preventing container escape via root privileges
@@ -74,7 +133,16 @@ USER node
74133
# Start gateway server with default config.
75134
# Binds to loopback (127.0.0.1) by default for security.
76135
#
77-
# For container platforms requiring external health checks:
78-
# 1. Set OPENCLAW_GATEWAY_TOKEN or OPENCLAW_GATEWAY_PASSWORD env var
79-
# 2. Override CMD: ["node","openclaw.mjs","gateway","--allow-unconfigured","--bind","lan"]
136+
# IMPORTANT: With Docker bridge networking (-p 18789:18789), loopback bind
137+
# makes the gateway unreachable from the host. Either:
138+
# - Use --network host, OR
139+
# - Override --bind to "lan" (0.0.0.0) and set auth credentials
140+
#
141+
# Built-in probe endpoints for container health checks:
142+
# - GET /healthz (liveness) and GET /readyz (readiness)
143+
# - aliases: /health and /ready
144+
# For external access from host/ingress, override bind to "lan" and set auth.
145+
HEALTHCHECK --interval=3m --timeout=10s --start-period=15s --retries=3 \
146+
CMD node -e "fetch('http://127.0.0.1:18789/healthz').then((r)=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"
147+
80148
CMD ["openclaw", "gateway", "--allow-unconfigured"]

0 commit comments

Comments
 (0)