这台斐讯 N1【1】 是我很久以前在拼多多买的,带原装电源大约一百元。
买来后,我把它刷成了软路由【2】,用来做 VPN 代理。N1 有千兆网口【3】,功耗也低,放在家里长期通电没有什么负担。
实际用了没多久,我还是回到了原来的习惯。电脑和手机上各自安装代理软件【4】,切换节点、修改规则、临时开关都更方便。软路由上的代理逐渐用得少了,N1 也被断电收了起来。
后来我看到了 AstrBot【5】。
AstrBot 可以接入 QQ,再调用大模型【6】生成回复,还能通过插件【7】增加各种功能。我不想为了一个 QQ 机器人一直开着电脑,便想起了那台闲置的 N1。
我重新给它接上电源,安装 Armbian【8】,准备让它长期运行 AstrBot。
从 AstrBot 开始
安装 Armbian 后,我通过 SSH【9】 管理 N1,并在上面部署 Docker【10】。
N1 的内置 eMMC【11】 只有 8GB。系统安装完成后,继续把 Docker 镜像和容器数据放在根分区里,很快就会遇到空间问题。
我接入了一块杂牌 8GB U 盘,格式化为 ext4【12】,挂载到:
/mnt/data
Docker 和 containerd【13】 的数据目录也迁到了这块盘里。系统继续留在 eMMC,镜像、容器和持久化数据都放在 /mnt/data。
AstrBot 本身负责机器人逻辑和模型调用,QQ 接入交给 NapCat【14】。两者都运行在 Docker 中,通过 OneBot v11【15】 反向 WebSocket 连接:
ws://astrbot:6199/ws
这里的 astrbot 是 Docker Compose【16】 中的服务名。NapCat 和 AstrBot 位于两个容器中,NapCat 容器里的 127.0.0.1 只会指向 NapCat 自己,连接另一个容器需要使用 Docker 网络中的服务名。
配置完成后,我在 QQ 中发送消息,AstrBot 能够收到,模型生成的内容也能通过 NapCat 返回 QQ。
N1 重新开机后的第一个用途,就这样确定了下来。
随后我安装了 Portainer【17】,用网页管理 Docker;又安装了 Glances【18】,用来查看 CPU、内存、Swap【19】、磁盘和温度。
N1 的内存大约只有 2GB。我给系统增加了 Swap,把 swappiness 调整为 10,也限制了系统日志的最大占用,避免日志长期增长后挤满 eMMC。
散热方面,我接了一个普通 USB 风扇。没接风扇时,温度大约在 53℃;接上后降到了 39℃左右,之后通常维持在 40℃上下。
第一块数据盘很快满了
那块杂牌 8GB U 盘在系统中实际可用约 7.3GB。
AstrBot、NapCat 和 Portainer运行一段时间后,Docker 镜像、容器层和持久化数据已经占用了 5GB 多,剩余空间只剩一两 GB。
继续使用并不会立即出问题,但已经不适合再增加服务。Docker 所在的磁盘一旦写满,镜像拉取、日志写入和程序保存配置都有可能失败。
我手里有一块一直在用的 64GB Kingston U 盘,便先拿来给 N1 过渡。
这块盘原本有自己的用途,我之后还要继续使用。当时没有准备其他存储设备,只能先解决 N1 空间不足的问题。
我把 64GB U 盘接入 N1,临时挂载到 /mnt/newdata,再将原来 /mnt/data 中的内容复制过去。复制完成后,新盘接管 /mnt/data,Docker 的数据路径保持不变。
挂载配置使用 UUID【20】,没有直接写 /dev/sda1。USB 设备的盘符会受到接口和识别顺序影响,换一个接口后,原来的 /dev/sda1 可能会变成 /dev/sdb1,UUID 则不会跟着变化。
换盘后,Docker、Portainer、AstrBot、NapCat 和 Glances 都能正常启动。数据盘的可用空间也从一两 GB 增加到了四十多 GB。
随后,AstrBot 的插件状态出现了异常。
插件开关无法保存
在 AstrBot 的 WebUI 中启用插件后,日志能够看到启用操作。刷新页面或者重启容器,插件又会恢复成未启用状态。
我先检查了当时安装的插件。
mnemosyne 存在明确的依赖冲突。插件要求的 psutil 版本低于 AstrBot 当前环境使用的版本,继续安装可能影响 AstrBot 的核心依赖。
qzone 和 qzone_ultra 同时存在,注册了大量相同指令。
另一个插件目录被改成了:
antipromptinjector.disabled
我原本以为增加 .disabled 后缀后,AstrBot 就不会继续加载。实际运行时,它仍然会扫描 plugins 目录中的子目录。最后只能把这个目录移到 plugins 之外。
这些插件问题逐个处理后,启用状态仍然无法保存。
我测试了 /AstrBot/data 的写入权限,文件可以正常创建和删除。数据目录中还有数据库、WAL【21】、plugins.json 和其他插件配置。
当时的排查方向开始转向旧数据本身。数据库、WAL 或插件配置之间可能存在状态不一致,但现有日志没有明确记录 SQLite 文件损坏,也没有足够的检查结果能够确认根因。
我能够确定的现象只有一个:迁移后的旧 AstrBot 环境无法可靠保存插件状态。
继续排查需要同时处理数据库、插件残留和依赖冲突。我停止了 AstrBot 和 NapCat,删除旧容器、旧 Docker 网络和原来的项目目录,重新创建了一套环境。
重装时盖掉了 NapCat 的启动文件
AstrBot 重新启动得很顺利,NapCat 却一直报错:
bash: entrypoint.sh: No such file or directory
我检查 Compose 配置时发现,自己给 NapCat 添加了这一项:
volumes:
- ./napcat_data:/app
宿主机上的 napcat_data 是一个空目录。它被挂载到容器的 /app 后,镜像原本放在 /app 中的文件全部被遮住,NapCat 启动时自然找不到 entrypoint.sh。
删掉这项挂载后,NapCat恢复运行。
NapCat 重装后需要重新扫码登录 QQ。登录完成后,我再次配置了到 AstrBot 的 WebSocket 连接。
启动过程中,NapCat 日志出现过连接拒绝。继续查看 AstrBot 日志后发现,AstrBot 当时还没有完成启动,6199 端口尚未开始监听。
过了一会儿,NapCat 自动重连,AstrBot 日志中出现了 /ws 连接成功和 OneBot v11 适配器已连接的记录。
我在 QQ 中发出测试消息,AstrBot 能够收到,机器人也重新恢复了回复。
旧插件没有一次性装回去。每次只安装一个,重启 AstrBot,查看日志,再确认插件启用状态是否能够保留。
服务慢慢多了起来
AstrBot 和 NapCat 稳定后,我又部署了 SillyTavern【22】。
SillyTavern 的配置和数据放在:
/mnt/data/sillytavern
第一次从电脑访问时,页面返回 403。查看日志后,发现电脑的局域网地址不在白名单【23】中。
我尝试过关闭白名单,SillyTavern 在监听局域网地址、又没有其他认证保护时会触发安全检查。最后仍然保留白名单,只加入需要访问的几台设备。
当时 N1 上已经有 AstrBot、NapCat、SillyTavern 和 Portainer。每个服务都有单独的端口,排查问题时还要登录 SSH 查看容器日志。
我在 /mnt/data/docker/n1-tools 中又部署了四个工具:
Homepage
Uptime Kuma
File Browser
Dozzle
Homepage【24】 用来集中放置服务入口。以前需要记住各个端口,后来先打开 Homepage,就能进入 AstrBot、NapCat、SillyTavern、Portainer 和其他页面。
Uptime Kuma【25】 定时检查服务是否在线。能正常返回网页的服务使用 HTTP 检测,只提供端口的服务则使用 TCP 检测。
Dozzle【26】 用来查看 Docker 日志。机器人没有回复时,可以直接查看 AstrBot 和 NapCat;其他服务启动失败,也能在页面中找到对应容器的输出。
File Browser【27】 负责查看和下载数据盘中的文件。
它第一次启动时,读取到了一个空的 settings.json,日志提示 JSON 解析失败。删除这个空文件后,第二次启动又因为数据库文件权限不足而失败。调整目录和数据库文件权限后,File Browser 才正常完成初始化。
File Browser 映射了整个 /mnt/data。Docker、SillyTavern 和备份目录都能直接看到,运行中的目录也不能随意移动或删除。
到这时,N1 上已经有 8 个 Docker 容器:
astrbot
napcat
sillytavern
portainer
uptime-kuma
dozzle
filebrowser
homepage
原来的 1GB Swap 也已经使用了不少。我没有关闭原 Swap,而是另外增加了一个 1GB Swap 文件,总容量变成 2GB。
服务数量没有再继续增加。
给 N1 买一块长期使用的数据盘
64GB Kingston 在 N1 上运行了一段时间后,我买了一块新的 32GB SanDisk U 盘。
之前的 64GB U 盘只是临时借给 N1 使用,我自己还要拿回来。新的 32GB U 盘专门留给 N1,长期挂载在 /mnt/data。
当时数据盘中实际使用约 15GB,32GB 的容量足够容纳。
这次迁移前,我先停止 Docker、Docker Socket【28】 和 containerd。检查系统时,仍然能看到 containerd-shim-runc-v2 进程和 overlay【29】 挂载,说明部分容器文件系统还在使用 /mnt/data。
我重新启动 Docker,先通过 Docker 正常停止所有容器,再停止 Docker、Socket 和 containerd。确认相关进程和 overlay 挂载全部消失后,才开始复制。
新 U 盘出厂时是 FAT32【30】。Docker 数据中包含 Linux 权限、属主、软链接、ACL【31】 和扩展属性【32】,我把它重新格式化为 ext4,再挂载到 /mnt/newdata。
数据复制完成后,两块盘的文件数量都是:
342399
两边显示的已用空间相差几百 MB。不同 ext4 文件系统的块分配、inode【33】 和稀疏文件【34】占用会产生差异,只看容量无法判断文件是否缺失。
我又使用校验模式检查了一遍,命令没有输出。
随后修改 /etc/fstab,让新盘的 UUID 接管 /mnt/data。Docker Root Dir【35】、容器配置和持久化数据全部保留。
第一次启动 Docker 时,只有 Portainer 自动运行。Portainer 使用 always 重启策略,其他容器大多使用 unless-stopped。
迁移前,我手动停止过这些容器。Docker 保留了人工停止状态,因此它们没有自动恢复。手动启动后,8 个容器全部运行,File Browser、Uptime Kuma 和 Homepage 的健康检查【36】也通过了。
确认新盘运行正常后,我关闭 N1,拔掉 64GB U 盘,再把新的 32GB U 盘插到原来的 USB 接口。
重新开机后,新盘的设备名从 /dev/sdb1 变成了 /dev/sda1。系统仍然按照 UUID 将它挂载到 /mnt/data,Docker 和容器数据没有受到影响。
64GB U 盘也终于可以拿回来继续使用。
从 Wi-Fi 换回网线
N1 早期接过网线,后来因为摆放位置改用了 Wi-Fi。无线地址为 192.168.x.17,一段时间内,各个服务都通过这个地址访问。
数据盘和容器稳定后,我重新接上网线。
接线后,系统同时保留了有线和无线连接。有线连接的路由优先级更高,外网流量已经通过 eth0 传输。
网卡状态显示:
Speed: 1000Mb/s
Duplex: Full
Link detected: yes
我在 N1 上运行 iperf3【37】,使用 Windows 电脑进行双向测试。
Windows 到 N1 约为 941Mbps,N1 到 Windows 约为 946Mbps,TCP 重传为 0。外网下载约为 938 至 946Mbps,上传约为 38Mbps。
个别测速节点会超时,或者返回明显异常的下载结果。更换节点后,速度恢复正常。
有线连接通过测试后,我关闭了无线自动连接。路由器按照 N1 有线网卡的 MAC 固定分配 192.168.x.91,N1 内部继续使用 DHCP【38】。
Homepage 和 Uptime Kuma 中仍然保存着旧的无线地址。
我先备份 Homepage 配置,再把服务入口统一改成新的有线地址。Uptime Kuma 的监控项则通过网页逐个修改。
修改完成后,我重启了 N1。
重新连接时,有线地址正常,无线保持断开,Docker、containerd 和 8 个容器全部恢复运行。Homepage、Uptime Kuma 和 File Browser 的健康检查也都通过了。
现在的 N1
目前 N1 上运行着 8 个 Docker 容器:
portainer
sillytavern
astrbot
napcat
homepage
uptime-kuma
filebrowser
dozzle
系统中还有 SSH、Docker、containerd 和 Glances Web。
Armbian 和系统服务运行在 eMMC 中,Docker 与业务数据存放在 32GB U 盘的 /mnt/data 中。有线网络作为日常连接,无线配置仍然保留,但不会自动连接。
平时我会先打开 Homepage,再进入需要的服务。Uptime Kuma 记录在线状态,Dozzle 查看容器日志,File Browser 用来下载文件和备份,Glances 显示温度、内存和磁盘,Portainer负责管理 Docker。
当初因为 AstrBot,我重新给这台闲置的 N1 接上了电源。
现在它运行着 8 个 Docker 容器,长期留在家里的局域网中。

Comments NOTHING