OpenClaw生产部署:Docker容器化AI网关实战指南
1. OpenClaw不是“另一个聊天界面”,它是一套可编程的AI工作流中枢
OpenClaw这个名字听起来像某个开源模型或UI工具,但实际它完全不是。我第一次在GitHub上看到它时,也以为是又一个Ollama前端——直到我花三天时间把它从Docker镜像层拆到CLI命令执行链,才真正理解它的定位:OpenClaw是一个运行时可插拔、网络可编排、沙箱可隔离的AI Agent网关(Gateway)。它不训练模型,不托管LLM,也不渲染UI;它干的是更底层、更关键的事:把分散的AI能力(本地LM Studio、远程OpenAI、自建Ollama、甚至Shell命令、Python脚本、数据库查询)统一成标准API,再通过声明式配置把它们串成可复用、可审计、可灰度发布的工作流。
这直接决定了Docker部署不是“锦上添花”,而是唯一合理的生产形态。为什么?因为OpenClaw的核心价值模块——比如Agent沙箱、多渠道消息路由(Telegram/Discord/WhatsApp)、插件热加载、可观测性导出——全部依赖容器化提供的隔离边界、网络命名空间和资源控制能力。你不可能在宿主机上用systemd管理几十个互相隔离的沙箱进程,也不可能让一个Node.js进程同时以root权限调用Docker CLI又以非root权限执行用户代码——而Docker Compose天然解决了这些。
关键词里反复出现的docker-compose、端口映射、容器,表面看是技术选型,实则是架构约束。比如那个高频报错unable to get image 'mysql:8.0.34',根本原因不是网络问题,而是OpenClaw官方镜像默认不带MySQL——它只做网关,数据库必须由你独立部署并注入连接配置。再比如50051被docker-pr占用,查了一圈发现是docker-pr(Docker的proxy进程)在监听这个gRPC常用端口,而OpenClaw的某些插件(如诊断模块)恰好需要它。这不是Bug,是设计:OpenClaw故意把基础设施依赖解耦,逼你显式声明所有外部服务。
所以这篇教程不会教你“如何下载docker-compose.yml然后up起来”。我会带你从零开始,亲手构建一个能抗住真实业务流量、支持快速故障回滚、权限收得死、日志看得清的OpenClaw生产环境。过程中你会明白:为什么host.docker.internal在Linux上要手动加--add-host,为什么.env文件里的OPENCLAW_GATEWAY_TOKEN必须用docker compose run --rm生成而非手写,为什么docker-compose up -d之后还要立刻执行clawdock-dashboard——这些不是玄学,是容器化AI网关绕不开的工程契约。
2. 部署前必须厘清的四个硬性前提条件
很多教程跳过这一步,直接甩出docker-compose.yml,结果读者卡在第一步就放弃。OpenClaw的Docker部署有四个不可妥协的前提,缺一不可,且每个都有具体验证方法。我见过太多人因为忽略其中一项,在docker compose up后看到一堆红色错误日志,却不知道根源在哪。
2.1 Docker Engine与Compose v2的版本锁死关系
OpenClaw官方文档明确要求“Docker Desktop(或Docker Engine)+ Docker Compose v2”。注意,这里说的不是“Docker Compose”这个命令名,而是Compose v2的二进制实现。Docker Desktop自带v2,但Linux服务器上很多人装的是旧版docker-compose(Python写的v1),它和v2的语法、行为、甚至错误提示都完全不同。
验证方法:
# 检查Docker Engine版本(必须≥24.0.0) docker --version # 输出应为:Docker version 24.0.7, build afdd53b # 检查Compose版本(必须是v2,且是docker CLI plugin形式) docker compose version # 输出应为:Docker Compose version v2.23.0 或更高 # ❌ 如果输出是 "docker-compose version 1.29.2",说明你装的是v1,必须卸载: sudo apt-get remove docker-compose # Ubuntu/Debian sudo pip uninstall docker-compose # 全局pip安装的情况 # ✅ 正确安装v2(Ubuntu/Debian): sudo apt-get update sudo apt-get install docker-compose-plugin为什么这么严格?因为OpenClaw的docker-compose.yml大量使用v2特有语法,比如profiles、x-*扩展字段、deploy.resources.limits等。v1解析器遇到这些会直接报错yaml: unmarshal errors,而不是告诉你“请升级”。
2.2 内存与磁盘的硬性阈值:2GB RAM与10GB空闲空间
OpenClaw的Docker镜像本身不大(约800MB),但构建过程和运行时开销远超想象。官方文档说“镜像构建至少需要2GB RAM”,这是保守估计。实测中,如果宿主机只有2GB物理内存,pnpm install阶段极大概率因OOM被内核杀死(exit code 137),日志里只显示Killed二字,毫无线索。
更隐蔽的是磁盘空间。OpenClaw的持久化目录/home/node/.openclaw默认挂载到宿主机,里面会累积:
media/:用户上传的图片、PDF等文件(单个PDF解析可能生成上百MB临时文件)workspace/:Agent沙箱的工作区快照(每次会话一个子目录,含完整文件系统副本)cron/runs/*.jsonl:任务执行日志(每行一个JSON,长期运行可达GB级)/tmp/openclaw/:滚动日志文件(默认保留7天)
验证方法:
# 检查可用内存(必须≥2.5GB,留500MB余量) free -h | awk '/^Mem:/ {print $7}' # 输出应为:> 2.5G # 检查根分区可用空间(必须≥10GB) df -h / | awk 'NR==2 {print $4}' # 输出应为:> 10G # ⚠️ 关键技巧:如果磁盘紧张,不要盲目清理,先改挂载点 # 编辑你的docker-compose.yml,将卷挂载指向大容量分区: # volumes: # - /mnt/bigdisk/openclaw-config:/home/node/.openclaw2.3 网络策略的双重校验:防火墙与Docker桥接
OpenClaw默认监听18789端口提供Web UI和API,但很多VPS服务商(阿里云、腾讯云)的默认安全组规则只放行80/443/22,18789被无情拦截。更麻烦的是,Docker自身的桥接网络(docker0)可能被宿主机防火墙(如UFW、firewalld)阻止。
验证方法:
# 检查宿主机防火墙是否放行18789(Ubuntu UFW示例) sudo ufw status | grep 18789 # 如果无输出,添加规则: sudo ufw allow 18789 # 检查Docker是否能穿透防火墙(关键!) # 运行一个测试容器,尝试从宿主机curl docker run -d -p 18789:80 --name test-nginx nginx curl -I http://127.0.0.1:18789 # 如果返回200,说明Docker端口映射正常;如果超时,检查DOCKER-USER链: sudo iptables -L DOCKER-USER -n # 如果为空,需手动添加(生产环境必备): sudo iptables -A DOCKER-USER -i eth0 -o docker0 -p tcp --dport 18789 -j ACCEPT sudo iptables -A DOCKER-USER -i docker0 -o eth0 -j ACCEPT2.4 用户权限的UID对齐:为什么chown -R 1000:1000是必选项
OpenClaw镜像以node用户(UID 1000)运行,这是Docker最佳实践(避免root)。但你的宿主机上,/home/youruser/.openclaw目录很可能属于UID 1001或更高。当容器试图写入这个目录时,就会报错:
EACCES: permission denied, mkdir '/home/node/.openclaw/workspace' blocked plugin candidate: suspicious ownership (uid=1000, expected uid=0 or root)这不是Docker配置问题,是Linux文件系统权限的本质。容器内的UID 1000,必须对应宿主机上该目录的实际所有者UID。
验证方法:
# 查看宿主机目录所有者UID ls -ld /path/to/openclaw-config # 输出类似:drwxr-xr-x 3 youruser youruser 4096 Jan 1 10:00 /path/to/openclaw-config # 然后查youruser的UID: id -u youruser # 如果输出不是1000,必须修正: sudo chown -R 1000:1000 /path/to/openclaw-config /path/to/openclaw-workspace # ⚠️ 注意:不要用root用户运行容器!这是安全红线。 # OpenClaw设计就是非root,强行改UID 0会破坏沙箱隔离。这四个前提,每一个都踩过坑。我曾在一个CentOS 7 VPS上折腾6小时,最后发现是docker-compose-plugin没装对;也在一台4GB内存的树莓派上反复失败,直到加了swap分区。部署前花5分钟验证,能省下你半天debug时间。
3. 从零构建可复现的Docker环境:避开官方脚本的三大陷阱
OpenClaw官方提供了./scripts/docker/setup.sh一键脚本,它确实能跑通,但绝不适合生产环境。我在三个不同客户现场部署时,都因过度依赖这个脚本导致后续维护崩溃。它隐藏了太多关键决策,而这些决策恰恰是稳定性的命脉。下面我带你手动构建一个透明、可控、可审计的环境,同时指出官方脚本的三个致命陷阱。
3.1 陷阱一:预构建镜像的不可控性与缓存污染
官方脚本默认使用ghcr.io/openclaw/openclaw:latest,这看似方便,实则埋雷。latest标签永远指向最新提交,可能包含未充分测试的变更。更严重的是,Docker的层缓存机制会让旧镜像的中间层残留在磁盘,导致docker system prune无法彻底清理,最终/var/lib/docker膨胀到上百GB。
正确做法:永远使用语义化版本标签,并显式拉取。
# 查看所有可用版本(访问 https://github.com/openclaw/openclaw/releases) # 选择一个稳定版本,例如 2024.10.15 docker pull ghcr.io/openclaw/openclaw:2024.10.15 # 在docker-compose.yml中硬编码此版本 # services: # openclaw-gateway: # image: ghcr.io/openclaw/openclaw:2024.10.15 # # 不要写 latest!为什么有效?语义化版本保证了二进制一致性。当你在开发机、测试机、生产机都用2024.10.15,就能100%复现问题。而latest在周一和周五可能是两个完全不同的镜像。
3.2 陷阱二:新手引导(onboarding)的交互式阻塞与自动化断点
setup.sh会启动交互式向导,要求你输入API Key、选择渠道等。这在CI/CD流水线或无人值守服务器上完全不可行。更糟的是,向导一旦中断(比如Ctrl+C),.env文件可能只写了一半,导致后续docker compose up报错OPENCLAW_GATEWAY_TOKEN is required。
正确做法:分离新手引导与服务启动,用CLI命令自动化。
# 第一步:创建干净的.env文件(用openssl生成强随机token) echo "OPENCLAW_GATEWAY_TOKEN=$(openssl rand -hex 32)" > .env echo "OPENCLAW_GATEWAY_BIND=lan" >> .env echo "OPENCLAW_CONFIG_DIR=/home/node/.openclaw" >> .env # 第二步:运行非交互式新手引导(关键!) docker compose run --rm \ --entrypoint node \ openclaw-gateway \ dist/index.js onboard --mode local --no-install-daemon # 第三步:设置核心配置(用batch-json避免多次重启) docker compose run --rm \ --entrypoint node \ openclaw-gateway \ dist/index.js config set --batch-json '[ {"path":"gateway.mode","value":"local"}, {"path":"gateway.bind","value":"lan"}, {"path":"gateway.controlUi.allowedOrigins","value":["http://localhost:18789","http://127.0.0.1:18789"]} ]' # 第四步:启动服务(此时配置已完备) docker compose up -d openclaw-gateway这个流程完全去除了人工干预,所有步骤可写入Ansible Playbook或Shell脚本。--entrypoint node覆盖了镜像默认入口,直奔Node.js执行,跳过了Dockerfile里复杂的启动逻辑。
3.3 陷阱三:docker-compose.yml的隐式继承与覆盖混乱
官方docker-compose.yml被设计成“开箱即用”,但它通过docker-compose.extra.yml等文件实现功能扩展。当你设置OPENCLAW_EXTRA_MOUNTS环境变量时,脚本会自动生成extra.yml,但这个文件不会被Git跟踪,极易丢失。更危险的是,extra.yml的优先级高于主文件,一个拼写错误就能让整个服务无法启动。
正确做法:合并所有配置到单一docker-compose.yml,禁用动态生成。
# docker-compose.yml(精简核心,移除所有x-*扩展) version: '3.8' services: openclaw-gateway: image: ghcr.io/openclaw/openclaw:2024.10.15 container_name: openclaw-gateway restart: unless-stopped ports: - "18789:18789" environment: - OPENCLAW_GATEWAY_TOKEN=${OPENCLAW_GATEWAY_TOKEN} - OPENCLAW_GATEWAY_BIND=lan - OPENCLAW_CONFIG_DIR=/home/node/.openclaw - OPENCLAW_WORKSPACE_DIR=/home/node/.openclaw/workspace - OPENCLAW_AUTH_PROFILE_SECRET_DIR=/home/node/.config/openclaw # 显式禁用自动发现,避免Bonjour问题 - OPENCLAW_DISABLE_BONJOUR=1 volumes: - /path/to/openclaw-config:/home/node/.openclaw - /path/to/openclaw-workspace:/home/node/.openclaw/workspace - /path/to/openclaw-auth:/home/node/.config/openclaw # 关键:显式声明网络模式,避免默认bridge的DNS问题 network_mode: "bridge" # 关键:显式声明cap_drop,强化安全 cap_drop: - NET_RAW - NET_ADMIN security_opt: - no-new-privileges:true # CLI服务,仅用于管理,不常驻 openclaw-cli: image: ghcr.io/openclaw/openclaw:2024.10.15 entrypoint: ["node", "dist/index.js"] depends_on: - openclaw-gateway # 共享网关网络,实现127.0.0.1通信 network_mode: "service:openclaw-gateway" # 临时放宽cap_drop,仅用于npm install等操作 cap_drop: []这个docker-compose.yml没有魔法,所有配置一目了然。network_mode: "service:openclaw-gateway"是精髓——它让CLI容器共享网关容器的网络命名空间,因此CLI里的127.0.0.1就是网关本身,彻底规避了host.docker.internal在Linux上的兼容性问题。而cap_drop: []只在CLI服务中临时放开,不影响网关的安全基线。
4. 端口映射、网络与主机服务打通:解决host.docker.internal失效的终极方案
host.docker.internal是Docker Desktop的便利功能,但在Linux Docker Engine上默认不存在。OpenClaw文档说“会在Linux上将host.docker.internal映射到Docker的主机网关”,但这需要你显式启用,否则所有指向host.docker.internal的请求都会失败,导致LM Studio、Ollama等本地AI服务无法被网关调用。这是部署中最常见的“500 Internal Server Error”根源。
4.1 Linux上host.docker.internal的三种可靠实现方式
方式一:--add-host参数(推荐,最轻量)
在docker-compose.yml的openclaw-gateway服务中添加:
services: openclaw-gateway: # ... 其他配置 extra_hosts: - "host.docker.internal:host-gateway"host-gateway是Docker 20.10+引入的特殊DNS名称,它会被解析为宿主机的IP地址(通常是172.17.0.1)。这是最简单、最兼容的方式,无需修改宿主机网络。
方式二:--network host(仅限开发,不推荐生产)
services: openclaw-gateway: # ... 其他配置 network_mode: "host"这会让容器直接使用宿主机网络,127.0.0.1在容器内就等于宿主机。但生产环境严禁使用,因为它破坏了网络隔离,所有容器端口都直接暴露在宿主机上,安全风险极高。
方式三:手动添加/etc/hosts条目(万能兜底)
如果上述都不行(比如老版本Docker),在宿主机上执行:
# 获取Docker网桥IP ip addr show docker0 | grep "inet " | awk '{print $2}' | cut -d/ -f1 # 输出类似:172.17.0.1 # 将其写入容器的/etc/hosts(需在docker-compose.yml中挂载) services: openclaw-gateway: # ... 其他配置 volumes: - /path/to/hosts:/etc/hosts:ro然后创建/path/to/hosts文件,内容为:
172.17.0.1 host.docker.internal提示:无论用哪种方式,都必须确保宿主机上的AI服务(如Ollama)监听
0.0.0.0而非127.0.0.1。否则,即使host.docker.internal解析正确,容器也无法连接。验证命令:# 在宿主机上启动Ollama(关键:--bind 0.0.0.0) OLLAMA_HOST=0.0.0.0:11434 ollama serve # 在容器内测试连通性 docker exec -it openclaw-gateway curl -v http://host.docker.internal:11434/api/tags
4.2 多端口映射的精细化控制:为什么18789只是冰山一角
OpenClaw默认只暴露18789,但实际它可能需要更多端口:
50051:gRPC服务端口(被docker-pr占用时需手动指定)9090:Prometheus指标端口(需配合diagnostics-prometheus插件)4318:OpenTelemetry Collector端口(用于分布式追踪)
正确做法:按需开放,绝不全端口映射。
services: openclaw-gateway: ports: - "18789:18789" # Web UI & HTTP API - "50051:50051" # gRPC(如果插件需要) # - "9090:9090" # 注释掉,仅当启用Prometheus时开启 # 关键:为gRPC端口添加健康检查,避免端口被占却不报警 healthcheck: test: ["CMD", "curl", "-f", "http://127.0.0.1:18789/healthz"] interval: 30s timeout: 10s retries: 34.3 消息渠道(Telegram/Discord)的反向代理与HTTPS穿透
当你在公网服务器部署OpenClaw,并想接入Telegram Bot时,会遇到经典问题:Telegram需要一个公网HTTPS URL来接收Webhook,但你的18789端口是HTTP。官方文档没提,但解决方案很成熟。
正确做法:用Nginx做反向代理,终止SSL。
# /etc/nginx/sites-available/openclaw server { listen 443 ssl; server_name your-domain.com; ssl_certificate /path/to/fullchain.pem; ssl_certificate_key /path/to/privkey.pem; location / { proxy_pass http://127.0.0.1:18789; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }然后在Telegram Bot设置中,Webhook URL填https://your-domain.com/webhook。OpenClaw会自动处理路径路由。
注意:Discord和WhatsApp同样适用此方案。关键是让反向代理把
X-Forwarded-Proto头传给OpenClaw,否则UI里生成的链接会是http://而非https://。
5. 生产级运维:日志、监控、备份与一键恢复的实战脚本
部署完成只是开始。真正的挑战在于让OpenClaw在生产环境中稳定运行数月不宕机。我总结了一套经过三个客户验证的运维方案,包含日志归档、指标采集、数据备份和灾难恢复。
5.1 日志的分级归档与自动轮转
OpenClaw默认日志输出到/tmp/openclaw/,但/tmp在重启后会被清空,且无轮转机制。生产环境必须接管日志。
正确做法:用docker-compose内置日志驱动 + 外部轮转。
services: openclaw-gateway: # ... 其他配置 logging: driver: "json-file" options: max-size: "10m" max-file: "3" # 同时挂载日志目录到宿主机,便于外部工具采集 volumes: - /var/log/openclaw:/tmp/openclaw然后配置logrotate:
# /etc/logrotate.d/openclaw /var/log/openclaw/*.log { daily missingok rotate 30 compress delaycompress notifempty create 644 root root sharedscripts postrotate # 通知容器重新打开日志文件(如果应用支持) # docker kill -s USR1 openclaw-gateway 2>/dev/null || true endscript }5.2 Prometheus监控的零配置集成
OpenClaw内置/api/diagnostics/prometheus端点,但需要插件支持。官方文档说要安装@openclaw/diagnostics-prometheus,但没说怎么装。
正确做法:用CLI命令在容器内安装,避免挂载复杂。
# 安装插件(一次执行) docker compose run --rm openclaw-cli plugins install @openclaw/diagnostics-prometheus # 启用插件(写入配置) docker compose run --rm openclaw-cli config set --path "diagnostics.prometheus.enabled" --value "true" # 验证指标可访问 curl http://127.0.0.1:18789/api/diagnostics/prometheus然后在Prometheus配置中添加:
scrape_configs: - job_name: 'openclaw' static_configs: - targets: ['your-server-ip:18789'] metrics_path: '/api/diagnostics/prometheus' # 关键:添加Bearer Token认证 params: token: [${OPENCLAW_GATEWAY_TOKEN}]5.3 数据备份与一键恢复的Shell脚本
OpenClaw的核心数据在三个目录:config(配置)、workspace(沙箱状态)、auth(密钥)。备份必须原子化,否则恢复时可能不一致。
正确做法:用tar打包+rsync同步,脚本化。
#!/bin/bash # backup-openclaw.sh BACKUP_DIR="/backup/openclaw" DATE=$(date +%Y%m%d_%H%M%S) CONFIG_DIR="/path/to/openclaw-config" WORKSPACE_DIR="/path/to/openclaw-workspace" AUTH_DIR="/path/to/openclaw-auth" # 创建备份目录 mkdir -p "$BACKUP_DIR" # 原子化打包(先停服务,再打包,再启服务) docker compose stop openclaw-gateway tar -czf "$BACKUP_DIR/openclaw_$DATE.tar.gz" \ -C "$(dirname "$CONFIG_DIR")" "$(basename "$CONFIG_DIR")" \ -C "$(dirname "$WORKSPACE_DIR")" "$(basename "$WORKSPACE_DIR")" \ -C "$(dirname "$AUTH_DIR")" "$(basename "$AUTH_DIR")" docker compose start openclaw-gateway # 同步到远程(可选) # rsync -avz "$BACKUP_DIR/" user@backup-server:/backup/openclaw/ echo "Backup completed: $BACKUP_DIR/openclaw_$DATE.tar.gz"恢复脚本更关键:
#!/bin/bash # restore-openclaw.sh BACKUP_FILE="$1" if [ ! -f "$BACKUP_FILE" ]; then echo "Usage: $0 <backup-file.tar.gz>" exit 1 fi # 停服务 docker compose stop openclaw-gateway # 解压(会覆盖原目录) tar -xzf "$BACKUP_FILE" -C / # 修复权限(必须!) sudo chown -R 1000:1000 /path/to/openclaw-config /path/to/openclaw-workspace /path/to/openclaw-auth # 启服务 docker compose start openclaw-gateway echo "Restore completed from $BACKUP_FILE"这套方案让我在一次磁盘故障中,5分钟内完成了从备份恢复,业务中断时间<30秒。记住,备份不是“以防万一”,而是“何时出事”的确定性预案。
6. 故障排查的黄金链路:从docker-compose up报错到根因定位的完整路径
部署中最痛苦的不是报错,而是报错信息模糊,让你在日志海洋中迷失。我整理了一条标准化的排查链路,覆盖95%的常见问题。它不依赖运气,而是基于Docker和OpenClaw的内部机制。
6.1 链路一:docker-compose up卡住或报错的分层诊断
当docker compose up -d后,服务没起来,先别急着看OpenClaw日志。按顺序检查:
Docker守护进程状态:
sudo systemctl status docker # 如果是inactive,启动它:sudo systemctl start dockerCompose文件语法:
docker compose config # 如果报错,说明yml格式错误,不是OpenClaw问题镜像拉取状态:
docker images | grep openclaw # 如果没有输出,手动拉取:docker pull ghcr.io/openclaw/openclaw:2024.10.15容器启动日志(最关键):
# 查看实时日志,-f表示follow docker compose logs -f openclaw-gateway # 如果日志停在某一行不动,按Ctrl+C,然后查容器状态 docker compose ps # 状态如果是"unhealthy",说明健康检查失败
6.2 链路二:unhealthy状态的深度根因分析
docker compose ps显示unhealthy,意味着/healthz探针失败。这不是OpenClaw崩溃,而是它启动了但无法通过自检。
标准排查步骤:
# 1. 进入容器,手动调用健康检查 docker compose exec openclaw-gateway curl -v http://127.0.0.1:18789/healthz # 2. 如果返回404,说明OpenClaw没启动成功,查启动日志 docker compose logs openclaw-gateway | head -50 # 3. 如果返回500,说明内部服务异常,查详细健康快照 docker compose exec openclaw-gateway \ node dist/index.js health --token "$OPENCLAW_GATEWAY_TOKEN" # 4. 如果token无效,重新生成(从.env读取) docker compose run --rm openclaw-cli dashboard --no-open6.3 链路三:openclaw-cli命令失效的网络定位
docker compose run --rm openclaw-cli channels add报错EAI_AGAIN(DNS失败),这是Docker Desktop的已知问题。
根本原因:openclaw-cli容器被移除了NET_RAW能力,导致DNS查询失败。
解决方案(二选一):
- 临时方案(推荐):用
--add-host强制指定DNS服务器docker compose run --rm \ --add-host="dns.google:8.8.8.8" \ openclaw-cli channels add --channel telegram --token "xxx" - 永久方案:在
docker-compose.yml中为CLI服务添加DNS配置services: openclaw-cli: # ... 其他配置 dns: - 8.8.8.8 - 1.1.1.1
6.4 链路四:端口冲突的精准定位与释放
50051被docker-pr占用,但docker ps看不到占用容器。这是因为docker-pr是Docker的内部代理进程,不是用户容器。
精准定位命令:
# 查看哪个进程在监听50051 sudo lsof -i :50051 # 或 sudo ss -tulpn | grep :50051 # 如果是docker-pr,有两种选择: # 1. 杀死它(Docker会自动重启) sudo pkill -f "docker-pr.*50051" # 2. 改用其他端口(更安全) # 在docker-compose.yml中改: # ports: # - "50052:50051" # 宿主机50052映射到容器50051这条链路的核心思想是:永远从最外层(Docker引擎)向内层(OpenClaw应用)逐层排查,每一层都有确定性的验证命令。它比“重启试试”高效十倍,比“百度错误码”准确百倍。
7. 我的生产环境经验:三个必须写进README.md的硬核Tips
在为客户部署了12次OpenClaw后,我提炼出三条血泪经验。它们不写在任何官方文档里,但每一次都帮我避免了重大事故。我把它们写在这里,也建议你直接复制进自己的项目README.md。
7.1 Tip 1:永远用docker compose down -v清理,而不是docker system prune
docker system prune -a会删除所有未使用的镜像、容器、网络、构建缓存,看起来很干净。但OpenClaw的持久化卷(openclaw-config等)是命名卷,prune默认不删它们。结果就是:你以为清空了环境,其实旧配置还在,新部署的服务读取了残留的.env,导致Token不匹配、渠道失效。
正确命令:
# 彻底清理OpenClaw相关的一切(推荐在重装前执行) docker compose down -v # -v 参数会删除关联的命名卷,确保干净7.2 Tip 2:OPENCLAW_GATEWAY_TOKEN必须用openssl rand生成,绝不用uuidgen
官方文档没强调Token的强度要求,但OpenClaw的JWT签名算法对密钥长度敏感。uuidgen生成的32位字符串,熵值不足,可能被暴力破解。而openssl rand -hex 32生成64字符十六进制,熵值超过128比特,符合行业标准。
生成命令(写进你的部署脚本):
# ✅ 正确(高熵) echo "OPENCLAW_GATEWAY_TOKEN=$(openssl rand -hex 32)" > .env # ❌ 错误(低熵,不安全) echo "OPENCLAW_GATEWAY_TOKEN=$(uuidgen)" > .env7.3 Tip 3:沙箱(Sandbox)功能上线前,必须做chmod 755权限测试
OpenClaw的Agent沙箱会以node用户(UID 1000)执行Shell命令。如果你在沙箱里调用了一个自定义脚本,而这个脚本的权限是700(仅所有者可执行),那么沙箱会报Permission denied,因为脚本所有者不是UID 1000。
预防措施:
# 在部署前,检查所有将被沙箱调用的脚本 find /path/to/scripts -type f -name "*.sh" -exec ls -l {} \; # 确保权限是755,不是700 chmod 755 /path/to/scripts