Skip to content

11 — 应用服务(NapCat / Uptime Kuma) ​

部署时间:2026-11-08 05:00~05:13 CST 全部按 10-部署规范.md 容器化;端口只绑 127.0.0.1,通过 SSH 隧道访问。


1. 容器总览 ​

容器镜像状态端口(仅 loopback)内存
tenodx-postgrespostgres:18-alpinerunning + healthy543259 MB
tenodx-uptime-kumalouislam/uptime-kuma:2 (2.5.9)running + healthy3001118 MB
tenodx-napcatmlikiowa/napcat-docker:latestrunning6099 / 3000 / 3002201 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/
WebUIhttp://127.0.0.1:6099/webui/(注意路径是 /webui/,根路径会 301 跳转过去)
OneBot HTTP127.0.0.1:3000
OneBot WebSocket127.0.0.1:3002(容器内 3001,宿主机 3002 是为避开 Uptime Kuma 的 3001)
数据卷tenodx-napcat-config → /app/napcat/config
tenodx-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_ACCOUNTQQ 号。留空 = 用二维码登录(首次登录的推荐方式)
NAPCAT_WEBUI_TOKENWebUI 登录令牌,必填
NAPCAT_WEBUI_PREFIXWebUI 路径前缀(本版本实际路径仍是 /webui/)
ONEBOT_TOKENOneBot HTTP/WS 接口的鉴权 token

🔑 登录流程(需要你本人操作) ​

已部署完毕,但 QQ 尚未登录,所以 OneBot 接口还没起来。步骤:

  1. 开隧道:

    powershell
    powershell -NoProfile -ExecutionPolicy Bypass -File .\server-info\scripts\tunnel.ps1 -Service napcat
  2. 浏览器打开 http://127.0.0.1:16099/webui/

  3. 输入 token(在服务器 /opt/stacks/napcat/.env 的 NAPCAT_WEBUI_TOKEN)

  4. 页面会显示二维码 → 用手机 QQ 扫码登录

  5. 登录成功后,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 项启用) ​

#名称类型目标间隔状态
1SSH 22porthost.docker.internal:2260sUP
2PostgreSQL 18postgrestenodx-postgres:543260sUP
3Uptime Kumahttp127.0.0.1:300160sUP
4NapCat WebUIhttptenodx-napcat:6099/webui/60sUP
5NapCat OneBot HTTPhttptenodx-napcat:3000/60s⏸ 暂停(待登录)
6Outbound Internethttphttps://myip.ipip.net300sUP
7SOCKS5 proxypush宿主 cron 推送300sUP
8HTTP proxy (privoxy)push宿主 cron 推送300sUP
9Disk / usagepush宿主 cron 推送600sUP

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 / httphost.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 Kumahttp://127.0.0.1:13001/opt/stacks/uptime-kuma/.env
NapCat WebUIhttp://127.0.0.1:16099/webui//opt/stacks/napcat/.env
PostgreSQLpsql -h 127.0.0.1 -p 15432 -U tenodx -d tenodx/opt/stacks/postgres/.env
OneBot HTTPhttp://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;"

TenoDX · 内部文档