最近帮一个做SaaS的团队把OpenClaw部署到了他们的Ubuntu云服务器上,顺手把飞书机器人也接上了。这事听起来简单,实际做起来环节不少:云服务器初始化、Docker runtime、OpenClaw配置、飞书开放平台应用创建、channel对接、消息联调,每一步都有各自的坑。前后折腾了两天,我把完整的部署过程和排查经验写成这篇东西,给准备在Ubuntu云服务器上跑OpenClaw、并且打算接飞书机器人当团队助手的同学做个参考。这篇内容适合有一定Linux基础、用过Docker、但对OpenClaw和飞书开放平台不大熟悉的人,如果你是从零开始,照着每一步来做也能把服务跑起来。
1. 部署前先把架构和需求理清楚
1.1 OpenClaw到底是个什么东西
直接用大白话说,OpenClaw是一个开源的AI Agent运行时框架。它做的事情可以理解成“消息渠道的中枢”:你可以把飞书群、微信、Discord这些IM渠道接到同一个Agent上,用户在各个群里发消息,OpenClaw收到之后调用大模型进行处理,再把结果回复到对应的会话里。它还能挂工具、定时任务、工作流这些能力,不过这次部署我们主要用它的IM接入和Agent对话部分。
选OpenClaw而不是自己从零写机器人,最大的原因是省事。飞书机器人看着简单,真正要自己处理消息回调、会话状态、消息分段、重试机制、多轮上下文,工作量不小。OpenClaw把这些做了抽象,配置层面只需要指定channel类型和对应的凭证,剩下的事框架内部消化。另一个好处是它支持多种大模型后端,不同团队用的模型不一样,今天用千问,明天想换DeepSeek,改配置就能切换,不需要改代码。
1.2 为什么选Ubuntu云服务器而不是本机跑
这个选择其实经历过纠结。最初考虑过直接在团队成员的本机跑Docker,省一台服务器钱,但很快放弃了。本机跑有几个现实问题:一是机器关机或休眠服务就断了,飞书机器人变成“时灵时不灵”状态,体验很差;二是IP不固定,飞书如果配的是Webhook回调,一旦家里网络变化就可能收不到事件;三是日志、数据散落在个人电脑上,后面想迁移或者多人协作很麻烦。
Ubuntu云服务器这边,一台2核4G的小规格实例就能跑得很稳。Ubuntu 22.04 LTS系统在服务器领域用得最多,软件源、Docker兼容性、各种运维脚本的适配都最成熟,文档和遇到问题时能找到的参考也最多。另外一个很重要的点是云服务器可以设置开机自启、进程守护,配合Docker的restart策略,基本上做到“配置一次,长期跑”。
1.3 整体信息流与组件关系
整个系统拆开看其实就四个角色:用户、飞书、OpenClaw、大模型。用户在飞书群里@机器人发消息,飞书通过长连接或者Webhook把消息事件推给OpenClaw,OpenClaw带着上下文请求大模型接口,拿到生成结果后进行格式化处理,再由飞书channel调API把消息发回会话。OpenClaw在这条链路里相当于一个调度中枢,它自己不产生内容,但负责“把对的消息送到对的地方”。
理解这条信息流很重要,后面排查问题全靠它。比如“用户在飞书发了消息但机器人没反应”,问题可能出在飞书事件订阅配置、OpenClaw的channel鉴权、大模型接口调用失败这三个环节中任意一个。有了这条链路图,排查时就能按顺序一步步验证,而不是瞎猜。
2. 前置环境准备与飞书应用配置
2.1 云服务器初始化
我这次用的是腾讯云和阿里云都测试过的通用流程,选Ubuntu 22.04 LTS镜像。创建实例时有个容易被忽略的点:数据盘。OpenClaw运行会产生会话数据、日志、配置,如果全放到系统盘,后续系统盘满了会很被动。我一般建议系统盘40G起步,单独挂一块20G数据盘,挂载到 /opt 或者直接作为OpenClaw的数据目录。
服务器创建完成后,第一件事是更新系统包并装基础工具:
sudo apt update && sudo apt upgrade -y sudo apt install -y curl wget git ufw接着配置防火墙。OpenClaw的管理控制台默认监听一个本地端口,常见是18693,具体看版本,这个端口建议限制来源IP,不要直接对全公网放行。如果公司出口IP固定,就在安全组里只放行这个IP:
sudo ufw allow 22/tcp sudo ufw allow 18693/tcp from 你的公司出口IP sudo ufw enable提示:生产环境千万不要把OpenClaw控制台的端口暴露到0.0.0.0并且不加认证,否则别人扫到端口就能访问你的管理界面,轻则被改配置,重则泄露对话记录。
然后创建运行用户和数据目录。不建议直接用root跑容器,虽然方便,但权限范围太宽,后面万一容器被攻破,影响面会很大:
sudo useradd -r -m -s /bin/bash openclaw sudo mkdir -p /opt/openclaw sudo chown -R openclaw:openclaw /opt/openclaw2.2 安装Docker运行时
建议装Docker Engine而不是桌面版Docker Desktop,因为服务器上没有图形界面,Docker Desktop没有意义还占资源。官方安装脚本一行搞定:
curl -fsSL https://get.docker.com | sudo sh sudo systemctl enable --now docker装完后把openclaw用户加进docker组,这样后面操作容器不用每次sudo:
sudo usermod -aG docker openclaw如果你的服务器在国内,拉取官方镜像可能比较慢,可以给Docker配置镜像加速。编辑 /etc/docker/daemon.json,把 registry-mirrors 配置成可用的镜像源,改完重启Docker。这一步属于常规优化,如果你的网络本身没问题可以跳过。
2.3 在飞书开放平台创建机器人应用
飞书这边流程比较繁琐,但也最不能出错。先访问飞书开放平台,创建一个企业自建应用,应用名称比如“团队助手”。创建后进入应用配置页面,需要做四件事:
第一,在“添加应用能力”里找到“机器人”,开启机器人能力。开启后应用会获得一个机器人,之后在飞书里搜索应用名就能找到它。
第二,配置权限。在权限管理里搜索下面这些权限并开通:
- im:message(读取消息)
- im:message.p2p_msg:readonly(接收单聊消息)
- im:message.group_msg(接收群消息)
- im:chat(获取群信息)
- im:message:send_as_bot(以机器人身份发消息)
这些权限是OpenClaw这类机器人跑起来的最低要求。权限多了其实无所谓,但少了肯定不行,缺一个就可能导致某个消息场景收不到或者发不出。
第三,配置事件订阅。这里强烈建议选“长连接模式”,也就是WebSocket方式,而不是Webhook。Webhook需要公网可访问的回调地址,还要配置URL验证,调试起来麻烦;长连接只要服务器能主动连上飞书就行,不需要暴露额外端口。选长连接后把需要订阅的事件勾上,至少勾选 im.message.receive_v1(接收消息事件)。
第四,在“凭证与基础信息”里拿到App ID和App Secret,在“事件订阅”里拿到Verification Token。这三个值是后面OpenClaw配置飞书channel时必须要用的。
注意:App Secret要当成密码对待,不要提交到Git仓库,也不要贴在飞书群里。建议写进OpenClaw的环境变量或者config文件里,文件权限设为600。
飞书这边配完之后,还要“创建版本并发布”,等管理员审核通过。这个步骤经常有人漏掉,结果配置全是对的但机器人死活不工作,原因就是应用没有发布到企业。
3. OpenClaw部署与飞书channel接入实操
3.1 获取镜像并启动容器
OpenClaw的部署形式有好几种,官方文档推荐Docker Compose方式,因为它可以一次性把核心服务和依赖启动好。如果只是简单跑一个实例,单容器也够用。我这次是先用单容器跑通,后面再补systemd守护。
先写一个docker-compose.yml文件:
version: "3" services: openclaw: image: openclaw/openclaw:latest container_name: openclaw restart: unless-stopped ports: - "18693:18693" volumes: - /opt/openclaw:/data environment: - TZ=Asia/Shanghai启动:
cd /opt/openclaw docker compose up -d启动后OpenClaw会在 /data 目录下生成默认配置文件和初始数据。如果希望在启动前就把配置写好,也可以先手动创建配置目录,把config.yaml放进去再启动容器。
实操心得:使用固定版本标签而不是latest。我见过几次latest更新后配置格式不兼容导致服务起不来,而且每次image pull的镜像内容可能不一样,出问题后很难复现。固定到具体版本号,比如openclaw/openclaw:0.6.x,生产环境更稳。
3.2 大模型接入配置
OpenClaw本身不带模型,它需要对接一个大模型API。模型选择会直接决定回复质量和成本,我这次先接的是通义千问,主要是内网环境访问稳定。
config.yaml里LLM部分大概长这样:
llm: provider: openai-compatible base_url: "https://dashscope.aliyuncs.com/compatible-mode/v1" api_key: "sk-你的密钥" model: "qwen-plus"如果你用的是DeepSeek,把base_url和model换成对应的就可以。OpenClaw支持多种provider的原因是它用了统一的OpenAI兼容协议,很多国内模型服务商都提供这个协议,这样不同模型之间切换的成本就很低。
提示:不要把API Key硬编码在config.yaml里提交到仓库。可以用环境变量注入,比如在docker-compose.yml里写 ${DASHSCOPE_API_KEY},然后在宿主机上用env文件管理。
3.3 飞书channel的核心配置项
飞书channel的配置是这次部署的重头戏。在config.yaml的channels部分新增feishu配置:
channels: feishu: app_id: "cli_xxxxxxxx" app_secret: "你的AppSecret" verification_token: "你的VerificationToken" lark_host: "https://open.feishu.cn" receive_id_type: "chat_id"有几个字段需要解释。lark_host默认就是这个地址,一般不用改。receive_id_type这个字段决定消息发到群里还是单聊里用什么ID类型,大多数场景保持chat_id即可。app_id和app_secret就是前面从飞书开放平台拿到的值。
配置完成后重启容器让配置生效:
docker compose restart openclaw查看启动日志,看飞书channel是否初始化成功:
docker logs -f openclaw日志里如果出现类似“feishu channel connected”的信息,说明长连接建立成功。如果一直在报鉴权失败,优先检查App Secret是否复制完整、有没有多余空格、应用是否已发布。
3.4 消息联通性验证
配置完成不等于能用,一定要做完整链路验证。我的验证步骤很固定,五步走:
第一,在飞书里搜索应用名,找到机器人,先给机器人发一条单聊消息“你好”。如果能在日志里看到收到事件,说明事件接收链路是通的。
第二,等OpenClaw回复。正常情况几秒到十几秒会有回复,具体取决于大模型响应速度。如果日志显示调用了LLM没有报错,但飞书没有消息,大概率是发送消息权限或者receive_id_type配置问题。
第三,把机器人拉进一个测试群,在群里@机器人发消息,验证群聊场景。这一步容易踩坑:机器人拉进群之后,群里消息事件不一定默认推送,需要在飞书后台事件订阅里确认是否勾选了群消息相关事件。
第四,测试连续对话。连续发几条消息,确认上下文是否连贯。OpenClaw会根据会话保存上下文,如果每次回复都是“失忆”状态,检查会话文件目录是否有写入权限。
第五,测试异常输入,比如发一段很长的文字让它总结,或者问一个它不该回答的问题。这一步主要是看崩溃恢复能力,以及长文本处理效果。
4. 运行期坑点与排查实录
4.1 session file locked并发锁冲突
这个报错是我这次部署遇到最头疼的问题。日志里反复出现:
agent failed before reply: session file locked (timeout 60000ms)意思是有个会话文件被锁住了,60秒内没拿到锁,OpenClaw放弃了这次回复。出现这个问题的原因通常是同一份数据目录被多个OpenClaw进程同时使用,常见于两个场景:一是docker compose restart时旧容器还没完全退出新容器就启动;二是在宿主机上同时手动跑了另一个OpenClaw实例,两边用同一个 /data 目录。
解决办法是先确认进程数量:
docker ps | grep openclaw ps aux | grep openclaw | grep -v grep确保只有一个OpenClaw实例在跑。如果确认只有一个实例但仍然出现锁报错,可能是上次异常退出留下了残留锁文件。找到会话目录下的.lock文件,在确认没有进程占用后删掉,然后重启服务。
实操心得:这个锁机制本身是为了防止同一个会话被并发写坏,设计上没问题,但排查时要先怀疑“是不是有第二个进程”,再怀疑“残留锁文件”。直接删锁文件前一定要确认没有活跃进程,否则可能造成会话数据损坏。
4.2 飞书长回复被截断
OpenClaw在飞书里输出长内容时容易被截断,这个现象在群里特别明显。原因是飞书对单条消息长度有限制,超长的回复会被截断或者发送失败。我在群里问技术方案,OpenClaw一口气输出一大段Markdown,结果开头还在“整体架构”,结尾突然变成“(内容被截断)”。
解决思路有两个方向。一个是让模型控制输出长度,在OpenClaw的prompt里加一句“回答尽量精简,单次回复不超过500字”,简单粗暴但有效。另一个是配置消息分段发送,OpenClaw如果支持把长回复按段拆分发送到会话里,体验会好很多,但要确认你用的版本是否支持。
提示:如果团队经常需要OpenClaw输出长文档,与其让它直接发到飞书,不如让它生成一个链接或者把内容写到知识库/文档里再发个链接,这样既解决截断问题,也方便沉淀。
4.3 机器人能发消息但收不到用户消息
这个问题的现象是:OpenClaw主动发消息(比如定时任务)能正常发送,但用户在飞书里给机器人发消息,机器人完全没反应。日志里也看不到收到事件的记录。
这种情况十有八九是事件订阅没配好。检查三处:一是飞书后台事件订阅里是否勾选了 im.message.receive_v1;二是长连接是否成功建立,日志里应该有connected相关输出;三是应用是否已经发布版本并审核通过。
还有一个小坑:如果团队成员同时用飞书的国内版和海外版,事件推送的域名不同,配置文件里lark_host如果默认指向国内飞书,海外版的事件就到不了。这种情况需要根据实际使用的飞书版本调整lark_host。
4.4 日志、重启与日常维护
OpenClaw跑起来之后,日常维护主要围绕日志和数据备份。
日志查看是排查问题的第一手段:
docker logs -f openclaw日志量大的时候建议加上时间过滤,或者用docker logs的--since参数查看最近一段时间的日志。Docker默认的json-file日志驱动会无限增长,建议在daemon.json里配置日志轮转:
{ "log-driver": "json-file", "log-opts": { "max-size": "20m", "max-file": "3" } }数据备份方面,OpenClaw的配置、会话数据都在/opt/openclaw下,定期打包备份这个目录即可:
tar czf openclaw-backup-$(date +%Y%m%d).tar.gz /opt/openclaw恢复时先停掉容器,解压覆盖数据目录,再启动容器,so easy。如果配合云服务器的快照功能定期做整机快照,抗风险能力还会更强。
关于自动重启,docker compose文件里已经有了restart: unless-stopped,这意味着宿主机重启后容器会自动拉起来。但有个细节:如果容器内部因为某种原因不断崩溃,Docker的restart策略会不断尝试重启,这种场景下要看日志而不是一昧重启,否则会陷入“起不来->重启->又挂”的循环里。
最后再分享几个我跑这套环境的心得。第一,飞书后台的权限和事件订阅配置是整个接入过程最容易出错的地方,出问题先回到飞书后台检查这三项:应用有没有发布、权限有没有开通、事件订阅有没有勾对。第二,OpenClaw的日志就是最好的老师,遇到任何诡异问题第一步都是开日志,用时间线把事件推进和日志输出对起来,比东猜西猜高效得多。第三,不要把生产环境的配置改得太花哨,能简则简,一个干净的config文件、一个固定的镜像版本、一个完整的数据备份,这三样东西能让这套系统稳定跑很久。我这个实例上线到现在已经连续运行了两周,中间只因为云服务器升级重启过一次,Docker自动拉起来后一切照旧。如果你也在折腾OpenClaw和飞书机器人,遇到问题欢迎留言交流,我看到都会回复。