本来只是想搞个能自动回复的小玩意。

起手

大概是去年年底的事。群里聊天偶尔会冷场,我就想——搞个bot吧,能自动回复点什么的那种,活跃一下气氛。

框架选了 NoneBot2,Python 生态,太久没接触这方面的内容了,只能天天用空余时间先啃文档。

然后就开始了。

Windows Server:青铜时代

最初的运行环境是一台 Windows Server。

是的,我在 Windows 上跑群聊机器人。现在回想起来,真是无敌了。

一开始还好,pip install 装依赖,python bot.py 跑起来,能跑能回复,完美。但问题很快就来了:

依赖地狱。 这台 Windows 机器上的 Python 环境逐渐变成了一个不可考的黑箱。为了跑通各种功能,我前前后后装了一大堆东西——pandas、pypinyin、thefuzz、brotli……每装一个新的,都有概率打破原来的平衡。最刺激的一次是 psutil 版本冲突,某个系统状态插件对它的版本有精确要求,稍有偏差服务就跑不起来。

异步的学费。 NoneBot2 是异步框架,而我从同步编程过来的。刚开始写的时候经常忘记 await,或者在异步函数里调了个同步的阻塞操作,然后整个 Bot 就卡住了——不报错,不崩溃,就是不动。

NoneBot2 的机制坑。 最经典的是 FinishedException。这是框架用来正常结束会话的内部异常,但我写了个全局的 try-except 把它吞掉了。结果就是:本来应该正常结束的指令,走了一条完全不可预期的错误处理路径。Debug 这个问题的那个晚上,我盯着堆栈看了很久。

还有一次,处理文件消息的时候直接 AttributeError——File 对象缺少属性。顺着报错堆栈往上扒了半天,才发现是上游数据结构的一个边界情况没有处理。

Docker 迁移:白银时代

在 Windows Server 上反复折腾环境的第 N 次之后,以及二号机在docker顺利跑起来,吃上细糠之后,我下定决心把一号机也迁移到 Docker。

真的比 Win 方便太多了。

把整个 Bot 环境打包成镜像,docker-compose up -d,完事。不用再操心 Python 版本、包冲突、系统依赖——容器里是什么就是什么,干净、可复现、可回滚。

但迁移过程本身也不是一帆风顺:

  • Volume 挂载翻车:容器内的目录映射写错,导致配置文件读不到,数据一重启就蒸发。反复排查目录权限和路径问题,Permission Denied 看到想吐。
  • 文件找不到的幽灵 Bug:代码在本地跑得好好的,一进 Docker 就 FileNotFoundError。图片等静态资源根本没有被正确挂载进容器,Bot 进程看到的是一片虚无。最终靠 pathlib 重写了路径逻辑才彻底解决。
  • 网络不通:Webhook 和反向 WebSocket 连接怎么都连不上,花了不少时间才搞清楚 Docker bridge 网络模式下端口暴露的正确姿势。
  • 启动阶段的 KeyError:容器一起,日志直接报 KeyError: 'profile_at_startup.enable'——配置文件里少了一个配置项,初始化直接中断。

所有这些问题解决之后,那种感觉——就像是从泥地搬进了新房。

felislab.cc:有了个家

2026 年 2 月,我拿了台闲置的云服务器,注册了 felislab.cc 这个域名,打算搭个博客当门面。

Nginx 是我的新对手。

为了让 Halo 博客通过域名访问,我需要配反向代理。听起来简单:把 80/443 端口的请求转发到 Halo 的服务端口就行。

实际上:

  • proxy_pass 地址少个斜杠 → 502 Bad Gateway
  • proxy_pass 端口多写一个 → 502 Bad Gateway
  • 什么都没改但 Nginx 就是不启动 → conflicting server name,虚拟主机配置冲突
  • Nginx 日志路径不存在 → 服务拒绝启动

我翻了无数遍 error.log

SSL 证书也是一段故事。为了那个小绿锁,申请证书、配置 Nginx、做 HTTP 到 HTTPS 的 301 跳转。然后浏览器告诉我:Too many redirects

无限重定向循环。

最后发现是 X-Forwarded-Proto 请求头没配对,Nginx 和 Halo 在 HTTPS 的判断上产生了分歧:一个觉得已经是 HTTPS 了,另一个觉得不是,于是互相跳转,永无止境。

现在

回头看看,从去年年底到现在才三个月出头。从一台 Windows Server 上磕磕绊绊地跑起第一个 Bot,到现在 Docker 化部署、云服务器、域名、HTTPS、多个功能模块并行——

说实话,当初只是想给群里加点乐子。

但写代码这件事,一旦开始,就真的停不下来了。