镜像构建历史
# 2026-03-15 12:06:37 0.00B 设置默认要执行的命令
CMD ["gateway"]
# 2026-03-15 12:06:37 0.00B 配置容器启动时运行的命令
ENTRYPOINT ["/usr/local/bin/openclaw-entrypoint.sh"]
# 2026-03-15 12:06:37 0.00B 指定检查容器健康状态的命令
HEALTHCHECK &{["CMD-SHELL" "node -e \"const p=process.env.OPENCLAW_GATEWAY_PORT||'18789';fetch('http://127.0.0.1:'+p+'/healthz').then((r)=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))\""] "30s" "5s" "20s" "0s" '\x05'}
# 2026-03-15 12:06:37 0.00B 声明容器运行时监听的端口
EXPOSE map[18789/tcp:{} 18790/tcp:{}]
# 2026-03-15 12:06:37 0.00B 设置环境变量 HOME
ENV HOME=/home/node
# 2026-03-15 12:06:37 0.00B 设置环境变量 NODE_ENV
ENV NODE_ENV=production
# 2026-03-15 12:06:37 7.00KB 执行命令并创建新的镜像层
RUN |2 DEBIAN_FRONTEND=noninteractive OPENCLAW_VERSION=2026.3.13 /bin/sh -c chmod 755 /usr/local/bin/openclaw-entrypoint.sh && mkdir -p /home/node/.openclaw/workspace && chown -R node:node /home/node # buildkit
# 2026-03-15 12:06:37 7.00KB 执行命令并创建新的镜像层
RUN |2 DEBIAN_FRONTEND=noninteractive OPENCLAW_VERSION=2026.3.13 /bin/sh -c cat > /usr/local/bin/openclaw-entrypoint.sh <<'ENTRYPOINT_EOF'
#!/usr/bin/env bash
set -euo pipefail
OPENCLAW_USER="${OPENCLAW_USER:-node}"
OPENCLAW_GROUP="${OPENCLAW_GROUP:-node}"
OPENCLAW_HOME="${OPENCLAW_HOME:-/home/node}"
OPENCLAW_STATE_DIR="${OPENCLAW_STATE_DIR:-${OPENCLAW_HOME}/.openclaw}"
OPENCLAW_CONFIG_PATH="${OPENCLAW_CONFIG_PATH:-${OPENCLAW_STATE_DIR}/openclaw.json}"
OPENCLAW_WORKSPACE_DIR="${OPENCLAW_WORKSPACE_DIR:-${OPENCLAW_STATE_DIR}/workspace}"
OPENCLAW_GATEWAY_BIND="${OPENCLAW_GATEWAY_BIND:-lan}"
OPENCLAW_GATEWAY_PORT="${OPENCLAW_GATEWAY_PORT:-18789}"
OPENCLAW_INIT_GATEWAY_MODE="${OPENCLAW_INIT_GATEWAY_MODE:-local}"
OPENCLAW_STDOUT_LOG_PATH="${OPENCLAW_STDOUT_LOG_PATH:-${OPENCLAW_STATE_DIR}/logs/openclaw.stdout.log}"
OPENCLAW_STDERR_LOG_PATH="${OPENCLAW_STDERR_LOG_PATH:-${OPENCLAW_STATE_DIR}/logs/openclaw.stderr.log}"
bool_to_json() {
local raw="${1:-}"
raw="$(printf '%s' "$raw" | tr '[:upper:]' '[:lower:]')"
case "$raw" in
1|true|yes|on)
printf 'true'
;;
*)
printf 'false'
;;
esac
}
FALLBACK_ENV_RAW="${OPENCLAW_GATEWAY_CONTROLUI_DANGEROUSLY_ALLOW_HOST_HEADER_ORIGIN_FALLBACK:-${OPENCLAW_CONTROLUI_DANGEROUSLY_ALLOW_HOST_HEADER_ORIGIN_FALLBACK:-false}}"
OPENCLAW_GATEWAY_CONTROLUI_DANGEROUSLY_ALLOW_HOST_HEADER_ORIGIN_FALLBACK_JSON="$(bool_to_json "$FALLBACK_ENV_RAW")"
export OPENCLAW_GATEWAY_CONTROLUI_DANGEROUSLY_ALLOW_HOST_HEADER_ORIGIN_FALLBACK_JSON
DEFAULT_ALLOWED_ORIGINS="[\"http://127.0.0.1:${OPENCLAW_GATEWAY_PORT}\"]"
OPENCLAW_INIT_CONTROL_UI_ALLOWED_ORIGINS="${OPENCLAW_INIT_CONTROL_UI_ALLOWED_ORIGINS:-${DEFAULT_ALLOWED_ORIGINS}}"
export OPENCLAW_INIT_CONTROL_UI_ALLOWED_ORIGINS
mkdir_state_dirs() {
mkdir -p "$OPENCLAW_STATE_DIR"
mkdir -p "$OPENCLAW_WORKSPACE_DIR"
mkdir -p "$OPENCLAW_STATE_DIR/identity"
mkdir -p "$OPENCLAW_STATE_DIR/agents/main/agent"
mkdir -p "$OPENCLAW_STATE_DIR/agents/main/sessions"
mkdir -p "$OPENCLAW_STATE_DIR/logs"
mkdir -p "$(dirname "$OPENCLAW_STDOUT_LOG_PATH")"
mkdir -p "$(dirname "$OPENCLAW_STDERR_LOG_PATH")"
touch "$OPENCLAW_STDOUT_LOG_PATH" "$OPENCLAW_STDERR_LOG_PATH"
mkdir -p "$OPENCLAW_WORKSPACE_DIR/.openclaw"
}
fix_permissions() {
if [[ "$(id -u)" -ne 0 ]]; then
return 0
fi
# Keep ownership fixes scoped to OpenClaw state paths to avoid rewriting
# unrelated workspace content on bind mounts.
chown "$OPENCLAW_USER:$OPENCLAW_GROUP" "$OPENCLAW_HOME" "$OPENCLAW_STATE_DIR" "$OPENCLAW_WORKSPACE_DIR"
chown "$OPENCLAW_USER:$OPENCLAW_GROUP" \
"$(dirname "$OPENCLAW_STDOUT_LOG_PATH")" \
"$(dirname "$OPENCLAW_STDERR_LOG_PATH")" \
"$OPENCLAW_STDOUT_LOG_PATH" \
"$OPENCLAW_STDERR_LOG_PATH"
find "$OPENCLAW_STATE_DIR" -xdev -exec chown "$OPENCLAW_USER:$OPENCLAW_GROUP" {} +
if [[ -d "$OPENCLAW_WORKSPACE_DIR/.openclaw" ]]; then
chown -R "$OPENCLAW_USER:$OPENCLAW_GROUP" "$OPENCLAW_WORKSPACE_DIR/.openclaw"
fi
}
generate_gateway_token() {
if command -v openssl >/dev/null 2>&1; then
openssl rand -hex 32
else
node -e "process.stdout.write(require('node:crypto').randomBytes(32).toString('hex'))"
fi
}
read_config_gateway_token() {
if [[ ! -f "$OPENCLAW_CONFIG_PATH" ]]; then
return 0
fi
OPENCLAW_CONFIG_PATH="$OPENCLAW_CONFIG_PATH" node <<'NODE'
const fs = require("node:fs");
const configPath = process.env.OPENCLAW_CONFIG_PATH;
try {
const cfg = JSON.parse(fs.readFileSync(configPath, "utf8"));
const token = cfg?.gateway?.auth?.token;
if (typeof token === "string" && token.trim()) {
process.stdout.write(token.trim());
}
} catch {
// Keep startup resilient if user config is malformed.
}
NODE
}
write_initial_config() {
OPENCLAW_CONFIG_PATH="$OPENCLAW_CONFIG_PATH" \
OPENCLAW_GATEWAY_BIND="$OPENCLAW_GATEWAY_BIND" \
OPENCLAW_GATEWAY_PORT="$OPENCLAW_GATEWAY_PORT" \
OPENCLAW_GATEWAY_TOKEN="$OPENCLAW_GATEWAY_TOKEN" \
OPENCLAW_INIT_GATEWAY_MODE="$OPENCLAW_INIT_GATEWAY_MODE" \
OPENCLAW_INIT_CONTROL_UI_ALLOWED_ORIGINS="$OPENCLAW_INIT_CONTROL_UI_ALLOWED_ORIGINS" \
OPENCLAW_GATEWAY_CONTROLUI_DANGEROUSLY_ALLOW_HOST_HEADER_ORIGIN_FALLBACK_JSON="$OPENCLAW_GATEWAY_CONTROLUI_DANGEROUSLY_ALLOW_HOST_HEADER_ORIGIN_FALLBACK_JSON" \
node <<'NODE'
const fs = require("node:fs");
const path = require("node:path");
const configPath = process.env.OPENCLAW_CONFIG_PATH;
const bind = process.env.OPENCLAW_GATEWAY_BIND || "lan";
const mode = process.env.OPENCLAW_INIT_GATEWAY_MODE || "local";
const token = process.env.OPENCLAW_GATEWAY_TOKEN || "";
const parsedPort = Number.parseInt(process.env.OPENCLAW_GATEWAY_PORT || "18789", 10);
const gatewayPort = Number.isFinite(parsedPort) && parsedPort > 0 ? parsedPort : 18789;
const defaultOrigins = [`http://127.0.0.1:${gatewayPort}`];
let allowedOrigins = defaultOrigins;
const rawAllowedOrigins = (process.env.OPENCLAW_INIT_CONTROL_UI_ALLOWED_ORIGINS || "").trim();
if (rawAllowedOrigins.length > 0) {
try {
const parsed = JSON.parse(rawAllowedOrigins);
if (Array.isArray(parsed)) {
const normalized = parsed
.filter((value) => typeof value === "string")
.map((value) => value.trim())
.filter(Boolean);
if (normalized.length > 0) {
allowedOrigins = normalized;
}
}
} catch {
// Keep default origins when env JSON is invalid.
}
}
const fallback =
(process.env.OPENCLAW_GATEWAY_CONTROLUI_DANGEROUSLY_ALLOW_HOST_HEADER_ORIGIN_FALLBACK_JSON || "false") ===
"true";
const config = {
gateway: {
mode,
bind,
auth: {
token,
},
controlUi: {
allowedOrigins,
dangerouslyAllowHostHeaderOriginFallback: fallback,
},
},
};
fs.mkdirSync(path.dirname(configPath), { recursive: true });
fs.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`, { mode: 0o600 });
NODE
}
ensure_config() {
if [[ -n "${OPENCLAW_GATEWAY_TOKEN:-}" ]]; then
export OPENCLAW_GATEWAY_TOKEN
fi
if [[ ! -f "$OPENCLAW_CONFIG_PATH" ]]; then
if [[ -z "${OPENCLAW_GATEWAY_TOKEN:-}" ]]; then
OPENCLAW_GATEWAY_TOKEN="$(generate_gateway_token)"
export OPENCLAW_GATEWAY_TOKEN
fi
write_initial_config
echo "openclaw: wrote initial config to $OPENCLAW_CONFIG_PATH"
elif [[ -z "${OPENCLAW_GATEWAY_TOKEN:-}" ]]; then
OPENCLAW_GATEWAY_TOKEN="$(read_config_gateway_token || true)"
if [[ -n "$OPENCLAW_GATEWAY_TOKEN" ]]; then
export OPENCLAW_GATEWAY_TOKEN
fi
fi
}
run_as_node() {
local cmd=("$@")
if [[ "$(id -u)" -eq 0 ]]; then
exec gosu "$OPENCLAW_USER:$OPENCLAW_GROUP" "${cmd[@]}" >>"$OPENCLAW_STDOUT_LOG_PATH" 2>>"$OPENCLAW_STDERR_LOG_PATH"
fi
exec "${cmd[@]}" >>"$OPENCLAW_STDOUT_LOG_PATH" 2>>"$OPENCLAW_STDERR_LOG_PATH"
}
main() {
if [[ "$#" -eq 0 ]]; then
set -- gateway
fi
local subcommand="$1"
shift || true
if [[ "$subcommand" == "gateway" ]]; then
mkdir_state_dirs
fix_permissions
ensure_config
run_as_node openclaw gateway --allow-unconfigured --bind "$OPENCLAW_GATEWAY_BIND" --port "$OPENCLAW_GATEWAY_PORT" "$@"
else
run_as_node openclaw "$subcommand" "$@"
fi
}
main "$@"
ENTRYPOINT_EOF # buildkit
# 2026-03-15 12:06:37 9.52KB 执行命令并创建新的镜像层
RUN |2 DEBIAN_FRONTEND=noninteractive OPENCLAW_VERSION=2026.3.13 /bin/sh -c if ! getent group node >/dev/null; then groupadd --system node || groupadd node; fi && if ! id -u node >/dev/null 2>&1; then useradd --system --create-home --gid node --shell /bin/bash node || useradd --create-home --gid node --shell /bin/bash node; fi # buildkit
# 2026-03-15 12:06:37 17.00B 执行命令并创建新的镜像层
RUN |2 DEBIAN_FRONTEND=noninteractive OPENCLAW_VERSION=2026.3.13 /bin/sh -c /bin/bash -lc 'set -euo pipefail; OPENCLAW_BIN="$(command -v openclaw || true)"; if [[ -z "$OPENCLAW_BIN" && -x /root/.npm-global/bin/openclaw ]]; then OPENCLAW_BIN=/root/.npm-global/bin/openclaw; fi; if [[ -z "$OPENCLAW_BIN" && -x /root/.local/bin/openclaw ]]; then OPENCLAW_BIN=/root/.local/bin/openclaw; fi; if [[ -z "$OPENCLAW_BIN" ]]; then echo "openclaw command not found after installer" >&2; exit 1; fi; ln -sf "$OPENCLAW_BIN" /usr/local/bin/openclaw; openclaw --help >/dev/null' # buildkit
# 2026-03-15 12:06:33 1.45GB 执行命令并创建新的镜像层
RUN |2 DEBIAN_FRONTEND=noninteractive OPENCLAW_VERSION=2026.3.13 /bin/sh -c curl -fsSL https://openclaw.ai/install.sh | bash -s -- --no-onboard --version "${OPENCLAW_VERSION}" # buildkit
# 2026-03-15 12:05:05 85.02MB 执行命令并创建新的镜像层
RUN |2 DEBIAN_FRONTEND=noninteractive OPENCLAW_VERSION=2026.3.13 /bin/sh -c apt-get update && apt-get install -y --no-install-recommends ca-certificates curl git gnupg gosu hostname openssl procps && rm -rf /var/lib/apt/lists/* # buildkit
# 2026-03-15 12:05:05 0.00B 定义构建参数
ARG OPENCLAW_VERSION=latest
# 2026-03-15 12:05:05 0.00B 定义构建参数
ARG DEBIAN_FRONTEND=noninteractive
# 2026-02-11 00:49:57 0.00B
/bin/sh -c #(nop) CMD ["/bin/bash"]
# 2026-02-11 00:49:56 78.13MB
/bin/sh -c #(nop) ADD file:1ae27d2ef4369361104b699712f3897141e394785df5d193d67b44626f57eb87 in /
# 2026-02-11 00:49:54 0.00B
/bin/sh -c #(nop) LABEL org.opencontainers.image.version=24.04
# 2026-02-11 00:49:54 0.00B
/bin/sh -c #(nop) LABEL org.opencontainers.image.ref.name=ubuntu
# 2026-02-11 00:49:54 0.00B
/bin/sh -c #(nop) ARG LAUNCHPAD_BUILD_ARCH
# 2026-02-11 00:49:54 0.00B
/bin/sh -c #(nop) ARG RELEASE
镜像信息
{
"Id": "sha256:10053f10b744c35048375546629bc98a1b72106930285754f567d7c49d1f77a7",
"RepoTags": [
"tenfyzhong/openclaw:latest",
"swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/tenfyzhong/openclaw:latest"
],
"RepoDigests": [
"tenfyzhong/openclaw@sha256:5ad119e25924e0630af2ef2fd4f7bea0160d3b5df9327d75543ceb39064270b6",
"swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/tenfyzhong/openclaw@sha256:5434198565c58e8cfb76c6276894fbf437ed274b680a7d545ba8465431a36962"
],
"Parent": "",
"Comment": "buildkit.dockerfile.v0",
"Created": "2026-03-15T04:06:37.807556704Z",
"Container": "",
"ContainerConfig": null,
"DockerVersion": "",
"Author": "",
"Config": {
"Hostname": "",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"ExposedPorts": {
"18789/tcp": {},
"18790/tcp": {}
},
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"NODE_ENV=production",
"HOME=/home/node"
],
"Cmd": [
"gateway"
],
"Healthcheck": {
"Test": [
"CMD-SHELL",
"node -e \"const p=process.env.OPENCLAW_GATEWAY_PORT||'18789';fetch('http://127.0.0.1:'+p+'/healthz').then((r)=\u003eprocess.exit(r.ok?0:1)).catch(()=\u003eprocess.exit(1))\""
],
"Interval": 30000000000,
"Timeout": 5000000000,
"StartPeriod": 20000000000,
"Retries": 5
},
"ArgsEscaped": true,
"Image": "",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": [
"/usr/local/bin/openclaw-entrypoint.sh"
],
"OnBuild": null,
"Labels": {
"org.opencontainers.image.ref.name": "ubuntu",
"org.opencontainers.image.version": "24.04"
}
},
"Architecture": "amd64",
"Os": "linux",
"Size": 1613393619,
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/774e9bf3f00cf411b3880eb1bdd88d2efe3219395445d875cd0fabe6c1f2c3a7/diff:/var/lib/docker/overlay2/e8fd04439a41509b8e27f5ef13bfdfa56702ba401a8ce12b1a36d772e76b1de5/diff:/var/lib/docker/overlay2/e2ea06ca11e89272f43fba91f6a8b643804d9d5af3c9a79bf0ca739948efe831/diff:/var/lib/docker/overlay2/a0997dbcd6091e3b960dd2dca3d97c604a3bb39ce32a48cb7e8e6b38f58d25a4/diff:/var/lib/docker/overlay2/ec6d65905b7655bb52b87acf961606448a341476f0f2ca241bffeadb98bfacd1/diff:/var/lib/docker/overlay2/1a5b3730c6e2310ed6b01e973326f50f0b7563f8aefb246ebd58396e7c11132e/diff",
"MergedDir": "/var/lib/docker/overlay2/46cc62ac54f0fcdbcbb826c30fa6e2cc37f6deb551b1d56a6328d5196183e563/merged",
"UpperDir": "/var/lib/docker/overlay2/46cc62ac54f0fcdbcbb826c30fa6e2cc37f6deb551b1d56a6328d5196183e563/diff",
"WorkDir": "/var/lib/docker/overlay2/46cc62ac54f0fcdbcbb826c30fa6e2cc37f6deb551b1d56a6328d5196183e563/work"
},
"Name": "overlay2"
},
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:efafae78d70c98626c521c246827389128e7d7ea442db31bc433934647f0c791",
"sha256:56d602fef7f9b0ced8071b2c69f0e3c268870b73353c8a482b18d1d2ac2858b0",
"sha256:44e7a2f556ac9ee986b35028e61c6cc48d83aae7469c282e4fe9292a6982fdc4",
"sha256:297e82b7c60784d10ac22e6130c341d45dc89853536a1b9c448b03b5f07e5462",
"sha256:1b6c386a6597797a68a486e1efa13a8b1e297c9fe337c0ca0d3eb6d2ac5c357f",
"sha256:8bacf117e6b96a4fc8048fa4efbde42eaefcffa84d4a0ca4e7227a918cf86ece",
"sha256:fafef400771c3b9be766505b05ac411254bf4e0a3651ab6d599bd84c0b86657f"
]
},
"Metadata": {
"LastTagTime": "2026-03-16T00:38:05.554873504+08:00"
}
}