主题
11 — 应用服务(NapCat / Uptime Kuma)
部署时间:2026-11-08 05:00~05:13 CST 全部按
10-部署规范.md容器化;端口只绑 127.0.0.1,通过 SSH 隧道访问。
1. 容器总览
| 容器 | 镜像 | 状态 | 端口(仅 loopback) | 内存 |
|---|---|---|---|---|
tenodx-postgres | postgres:18-alpine | running + healthy | 5432 | 59 MB |
tenodx-uptime-kuma | louislam/uptime-kuma:2 (2.5.9) | running + healthy | 3001 | 118 MB |
tenodx-napcat | mlikiowa/napcat-docker:latest | running | 6099 / 3000 / 3002 | 201 MB |
- 共享网络:
tenodx-net - 全部
restart: unless-stopped - 宿主机内存占用:682 MB / 1.7 GB(Swap 用 15 MB)
- 磁盘:12 GB / 40 GB(31%,NapCat 镜像本身 2.16 GB)
公网暴露面未变:仍然只有 22/tcp(已实测)。
2. NapCat(QQ 机器人 / OneBot 11)
基本信息
| 项 | 值 |
|---|---|
| 镜像 | mlikiowa/napcat-docker:latest |
| 部署目录 | /opt/stacks/napcat/ |
| WebUI | http://127.0.0.1:6099/webui/(注意路径是 /webui/,根路径会 301 跳转过去) |
| OneBot HTTP | 127.0.0.1:3000 |
| OneBot WebSocket | 127.0.0.1:3002(容器内 3001,宿主机 3002 是为避开 Uptime Kuma 的 3001) |
| 数据卷 | tenodx-napcat-config → /app/napcat/configtenodx-napcat-qq → /app/.config/QQ |
⚠️ 安全权衡:这个容器必须是 privileged
NapCat 的 entrypoint 会做大量容器环境伪装,目的是让 QQ 认为运行在真实 PC 上:
删除 /.dockerenv / /.dockerinit / /run/.containerenv
伪造 /proc/1/cgroup → 去掉 docker/containerd 字样
伪造 /proc/self/mountinfo → overlay 改成 ext4
伪造 /proc/1/cmdline → /sbin/init
伪造 /proc/1/sched, status → 进程名改 systemd、NSpid 归 1
改写 /etc/hosts、DMI(厂商/型号/UUID)
隐藏 /var/run/docker.sock这些 mount --bind 操作需要 CAP_SYS_ADMIN,因此容器以 privileged: true 运行。
风险等级:高。 privileged 容器≈宿主机 root。官方 QQ 是闭源大型二进制, 一旦它被攻破,宿主机上的 PostgreSQL 数据也会暴露。
缓解措施(已做):不挂载 docker.sock、不使用 host 网络、
mem_limit: 1g限制资源、日志轮转 50 MB × 3。建议:若对隔离有更高要求,把 NapCat 迁到独立的小机器或 VPS 上。
配置项(/opt/stacks/napcat/.env,权限 600)
| 变量 | 说明 |
|---|---|
NAPCAT_ACCOUNT | QQ 号。留空 = 用二维码登录(首次登录的推荐方式) |
NAPCAT_WEBUI_TOKEN | WebUI 登录令牌,必填 |
NAPCAT_WEBUI_PREFIX | WebUI 路径前缀(本版本实际路径仍是 /webui/) |
ONEBOT_TOKEN | OneBot HTTP/WS 接口的鉴权 token |
🔑 登录流程(需要你本人操作)
已部署完毕,但 QQ 尚未登录,所以 OneBot 接口还没起来。步骤:
开隧道:
powershellpowershell -NoProfile -ExecutionPolicy Bypass -File .\server-info\scripts\tunnel.ps1 -Service napcat浏览器打开
http://127.0.0.1:16099/webui/输入 token(在服务器
/opt/stacks/napcat/.env的NAPCAT_WEBUI_TOKEN)页面会显示二维码 → 用手机 QQ 扫码登录
登录成功后,OneBot HTTP/WS 会自动开始监听 3000 / 3002
之后可以把自己的 QQ 号写进
.env的NAPCAT_ACCOUNT并重启, 让它用本地缓存的登录态自动上线(多数情况仍需手机确认)。
登录后要做的一件事:启用 OneBot 监控
OneBot 接口只在登录后才监听,所以那两个监控项部署时是暂停状态。 登录成功后执行:
bash
# 1) 把 monitors.json 里 NapCat OneBot HTTP 的 "active": false 改成 true
vi /opt/stacks/uptime-kuma/monitors.json
# 2) 同步
/opt/stacks/uptime-kuma/sync.sh常用命令
bash
cd /opt/stacks/napcat
docker compose ps
docker compose logs -f --tail 100 | grep -viE 'dbus|EGL|gpu|zygote' # 过滤容器噪音
docker compose restart日志里那些 64 位十六进制串是 NapCat 自身的完整性校验输出,不是错误。
3. Uptime Kuma(监控)
基本信息
| 项 | 值 |
|---|---|
| 版本 | 2.5.9(louislam/uptime-kuma:2) |
| 部署目录 | /opt/stacks/uptime-kuma/ |
| 访问 | http://127.0.0.1:3001(隧道映射到本机 13001) |
| 管理员 | admin,密码在 /opt/stacks/uptime-kuma/.env |
| 数据 | 卷 tenodx-uptime-data → SQLite /app/data/kuma.db |
| 启动参数 | UPTIME_KUMA_DB_TYPE=sqlite(跳过 2.x 的"选择数据库"向导) |
📋 监控清单(9 项,8 项启用)
| # | 名称 | 类型 | 目标 | 间隔 | 状态 |
|---|---|---|---|---|---|
| 1 | SSH 22 | port | host.docker.internal:22 | 60s | UP |
| 2 | PostgreSQL 18 | postgres | tenodx-postgres:5432 | 60s | UP |
| 3 | Uptime Kuma | http | 127.0.0.1:3001 | 60s | UP |
| 4 | NapCat WebUI | http | tenodx-napcat:6099/webui/ | 60s | UP |
| 5 | NapCat OneBot HTTP | http | tenodx-napcat:3000/ | 60s | ⏸ 暂停(待登录) |
| 6 | Outbound Internet | http | https://myip.ipip.net | 300s | UP |
| 7 | SOCKS5 proxy | push | 宿主 cron 推送 | 300s | UP |
| 8 | HTTP proxy (privoxy) | push | 宿主 cron 推送 | 300s | UP |
| 9 | Disk / usage | push | 宿主 cron 推送 | 600s | UP |
4. 🔧 监控维护流程(新增服务必读)
用户要求:"uptime 应该及时追加新服务的检测,所有服务都应该被监测,由你来添加,加入到定期维护内。" 以下就是这个机制的落地方式。
单一事实源
/opt/stacks/uptime-kuma/monitors.json ← 唯一的监控声明文件
/opt/stacks/uptime-kuma/sync.py ← 幂等同步脚本(新增/更新,不删除)
/opt/stacks/uptime-kuma/sync.sh ← 包装器:sync + 重启容器新增一个服务被监控,只需 3 步
bash
# ① 在 monitors.json 数组里追加一条
{
"name": "我的新服务",
"type": "http",
"url": "http://tenodx-xxx:8080/health",
"interval": 60,
"description": "说明用途"
}
# ② 同步(幂等,可反复执行)
/opt/stacks/uptime-kuma/sync.sh
# ③ 在 Uptime Kuma 界面确认状态变绿触发器:什么时候必须加监控
| 触发条件 | 动作 |
|---|---|
| 新增任何容器 | 立即在 monitors.json 加一条并 sync.sh |
| 新增宿主服务/端口 | 同上;若只绑 loopback,用 push 类型 + 加到 host-checks.sh |
| 改了端口或路径 | 更新对应条目后 sync.sh |
| 服务下线 | 把 "active" 改 false(不要删,保留历史) |
该选哪种监控类型
| 服务位置 | 选什么类型 | 目标地址写法 |
|---|---|---|
同 tenodx-net 的容器 | http / postgres / 原生类型 | 用容器名:tenodx-xxx:端口 |
监听 0.0.0.0 的宿主服务 | port / http | host.docker.internal:端口 |
| 只绑 127.0.0.1 的宿主服务 | push | 加到 host-checks.sh,由宿主 cron 推 |
5. ⚠️ 踩坑记录(这些坑会让监控静默失效)
坑 1:TCP 类型名是 port,不是 tcp
数据库 monitor.type 必须写 port。写 tcp 会得到 Unknown Monitor Type 的 DOWN,而且看起来像服务挂了。
源码依据:
/app/server/monitor-types/tcp.js→class TCPMonitorType { name = "port" }文件名和类型名不一致,很容易踩。
坑 2:容器里的 127.0.0.1 不是宿主机的
Uptime Kuma 的检查在自己容器内执行。写 127.0.0.1:5432 会得到 ECONNREFUSED,因为它连的是自己。
正解:用容器名(tenodx-postgres:5432)或 host.docker.internal。
坑 3:docker-proxy 会让 TCP 监控误报 UP
只要容器发布了端口,docker-proxy 就会在宿主机监听并先接受 TCP 握手, 哪怕容器内根本没有服务在听。所以对 NapCat 的 3000 用 port 类型会永远显示 UP。
正解:用 http 类型(会真实发请求,连不上就 DOWN)。
坑 4:push 的 msg 参数不能有空格
/api/push/<token>?status=up&msg=1080 reachable 里的空格会让 curl 失败(http 000), 推送静默丢失。用下划线:port_1080_ok。
坑 5:Uptime Kuma 2.x 有个"选数据库"启动向导
首次启动会停在 Waiting for user action...。设 UPTIME_KUMA_DB_TYPE=sqlite 跳过。 另外**空的 0 字节 kuma.db 会被误判为"已有库"**导致迁移不执行,必须删掉空文件。
坑 6:没有 monitor CRUD 的 REST API
api-router.js 只暴露 badge 接口。所以监控是通过 sync.py 直接写 SQLite 实现的, 写完必须重启容器才会加载。
6. 备份
| 内容 | 方式 | 频率 | 位置 |
|---|---|---|---|
| PostgreSQL 数据 | pg_dump | gzip | 每日 03:30 | /var/backups/postgres/ |
| 栈配置 + kuma.db + NapCat 配置 | tar.gz(sqlite .backup 保证一致) | 每日 03:35 | /var/backups/stacks/ |
bash
# 手动备份
/opt/stacks/postgres/backup.sh
/opt/stacks/backup-stacks.sh
# 恢复 Uptime Kuma 监控配置
tar -xzf /var/backups/stacks/stacks-XXXX.tar.gz -C /tmp
docker cp /tmp/uptime-kuma/kuma.db tenodx-uptime-kuma:/app/data/kuma.db
docker compose -f /opt/stacks/uptime-kuma/compose.yaml restart uptime-kuma⚠️ 备份仍只在本地,未异地化。建议后续加 OSS 同步。
7. 访问方式(安全组只开 22 的后果)
powershell
# 一次开全部(postgres / uptime / napcat)
powershell -NoProfile -ExecutionPolicy Bypass -File .\server-info\scripts\tunnel.ps1
# 只开监控
... -Service uptime
# 只开 NapCat 登录
... -Service napcat| 服务 | 本地地址 | 凭据位置(服务器) |
|---|---|---|
| Uptime Kuma | http://127.0.0.1:13001 | /opt/stacks/uptime-kuma/.env |
| NapCat WebUI | http://127.0.0.1:16099/webui/ | /opt/stacks/napcat/.env |
| PostgreSQL | psql -h 127.0.0.1 -p 15432 -U tenodx -d tenodx | /opt/stacks/postgres/.env |
| OneBot HTTP | http://127.0.0.1:13000 | /opt/stacks/napcat/.env |
8. 日常维护清单
| 频率 | 事项 |
|---|---|
| 每天 | 开隧道看 Uptime Kuma 是否全绿 |
| 每天 | 若新增了服务 → 立即加 monitors.json 并 sync.sh |
| 每周 | docker system df 看镜像/卷占用;docker image prune -f 清理 dangling |
| 每周 | 确认 /var/backups/ 有新增文件 |
| 每月 | apt update && apt upgrade(注意 hold 的 cloud-init) |
| 变更后 | 在 07-变更记录.md 追加一行 |
一键体检
bash
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
docker stats --no-stream
/opt/stacks/uptime-kuma/host-checks.sh
docker exec tenodx-uptime-kuma sqlite3 -header -column /app/data/kuma.db \
"select m.name, h.status, h.msg, datetime(h.time,'localtime') t from monitor m \
left join heartbeat h on h.id=(select max(id) from heartbeat where monitor_id=m.id) order by m.id;"