日期:2026-11-14 环境:NAS(Debian 12,x86_64)· Docker · QQ Linux 3.2.28-48517 结果:Nekolux 完整跑通(注入 → 账号识别 → OneBot → 插件)
[Hook] login detected: PID=40 UIN=3816829185
[Bridge] friends loaded: count=7
[Bridge] groups loaded: count=5
[Bridge] member warmup: 505 members, 0 failed
[OneBot] session started: UIN=3816829185
[OneBot.HTTP] listening 0.0.0.0:3000/
[OneBot.WS-Server] listening 0.0.0.0:3001/
# 外部调用
get_group_list → 5 个群
get_login_info → {"user_id":3816829185,"nickname":"沈知意"}
demo_echo → {"echo":"nas-test","from":"demo-plugin"}
ptrace_scope=1 导致注入静默失败(最致命)现象:
[Hook] awaiting login: PID=28
[Hook] pipe connected: PID=28
看起来一切正常,但永远等不到登录。没有任何错误日志。
根因(strace 抓到):
ptrace(PTRACE_SEIZE, 29, NULL, 0) = -1 EPERM (Operation not permitted)
kernel.yama.ptrace_scope = 1 的规则是「只允许父进程跟踪子进程」。而我们的进程树是:
entrypoint.sh (PID 1)
├─ QQ (PID 29) ← 兄弟
└─ Nekolux (PID 319) ← 兄弟
兄弟进程之间不能 ptrace,所以注入被内核拒绝。Nekolux 失败后不重试也不报错,只停在 awaiting login。
修复:
sysctl -w kernel.yama.ptrace_scope=0
或者永久写入 /etc/sysctl.d/99-nekolux.conf:
kernel.yama.ptrace_scope = 0
注意:这是宿主内核参数,容器内改不了(除非
--privileged+/proc/sys可写)。 在 NAS 上直接改宿主即可,所有容器共享同一个内核。
现象:
[59:...] Missing X server or $DISPLAY
[59:...] The platform failed to initialize. Exiting.
docker restart 时 Xvfb 还没起来,QQ 就启动了。
根因:entrypoint 里的等待循环没有严格检查,20 次后不管成功失败都继续。
修复(entrypoint.sh):
XVFB_OK=0
for _ in $(seq 1 60); do
if DISPLAY=:99 xdpyinfo >/dev/null 2>&1; then
XVFB_OK=1
break
fi
sleep 0.5
done
[ "$XVFB_OK" -ne 1 ] && { echo "FATAL: Xvfb not ready"; exit 1; }
同时给 QQ 加一次重试。
现象:容器重启后 QQ 需要重新扫码。
根因:napcat 镜像的 /app/.config/QQ 是 VOLUME(匿名卷)。docker rm -f 后新建容器会挂一个新的空卷。
修复:显式挂载到宿主目录。
-v /astrbot/unified/qq-config:/app/.config/QQ
容器内 127.0.0.1:3000 外部访问不到。改配置:
{ "networks": { "httpServers": [{ "host": "0.0.0.0", ... }] } }
文件:/app/nekolux/config/onebot_<uin>.json
apt-get install 报 Unmet dependencies。先修:
RUN apt-get update || true; \
DEBIAN_FRONTEND=noninteractive apt-get -f install -y || true; \
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
xvfb x11vnc openbox x11-utils strace
国内 NAS 拉不动。用 npmmirror:
https://registry.npmmirror.com/-/binary/node/v24.22.1/node-v24.22.1-linux-x64.tar.xz
main 指向 ./loadNapCat.js(进程内加载 NapCat)。Nekolux 是进程外 hook,必须还原:
RUN sed -i 's#"main"[[:space:]]*:[[:space:]]*"[^"]*"#"main": "./application.asar/app_launcher/index.js"#' \
/opt/QQ/resources/app/package.json
/memfd:nnp-resident-dispatch (deleted)
加载后立即 unlink。这是反检测设计——磁盘上找不到注入文件。
strace 显示它遍历 /proc:
openat("/proc", O_DIRECTORY)
openat("/proc/1/comm")
openat("/proc/28/comm")
openat("/proc/28/cmdline")
openat("/proc/28/maps")
先读 comm 匹配进程名,再读 cmdline + maps 判断是否主进程。
nnphook::linux_backend::RuntimeTargets
MSFCoreService send features missing or ambiguous
MSFCoreService packet-state callback/RTTI chain unresolved
靠 ELF 符号 + RTTI 链在运行时定位,不是硬编码偏移。这是跨 QQ 版本的来源。
# 1. 宿主准备(关键)
sudo sysctl -w kernel.yama.ptrace_scope=0
mkdir -p /astrbot/unified/{data,config,qq-config}
# 2. 构建镜像
cd /tmp/unified-build
docker build -t unified:local .
# 3. 启动
docker run -d --name unified \
--cap-add SYS_PTRACE \
--security-opt seccomp=unconfined \
--shm-size 1gb \
-e VNC_PASSWORD=<密码> \
-e NEKOLUX_LOG_LEVEL=info \
-e UNIFIED_PLUGIN_ALLOW=demo-plugin \
-p 5099:5099 -p 5902:5900 -p 3100:3000 -p 3101:3001 \
-v /astrbot/unified/data:/app/data \
-v /astrbot/unified/config:/app/nekolux/config \
-v /astrbot/unified/qq-config:/app/.config/QQ \
unified:local
# 4. VNC 扫码登录
# VNC: <host>:5902
# 5. 验证
curl -X POST http://<host>:3100/ \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <token>' \
-d '{"action":"get_login_info","params":{}}'
| 现象 | 检查 |
|---|---|
awaiting login 但 QQ 已登录 |
cat /proc/sys/kernel/yama/ptrace_scope 必须是 0 |
| QQ 启动即退 | docker logs unified \| grep "X server" |
| 重启后要重新扫码 | 检查 /app/.config/QQ 是否挂到宿主 |
| 外部连不上 3000/3001 | 检查 onebot_<uin>.json 的 host 是否为 0.0.0.0 |
COMPONENT_LOAD_FAILED |
同上,ptrace_scope 或 QQ 未就绪 |
| 路径 | 说明 |
|---|---|
unified/docker/Dockerfile |
镜像定义(含 apt 修复、QQ 入口还原) |
unified/docker/entrypoint.sh |
启动编排(Xvfb 严格等待 + QQ 重试) |
tools/nas-run-unified.sh |
容器启动脚本(含全部挂载) |
tools/nas-onebot.py |
通过 SSH 调 OneBot action 的辅助脚本 |
tools/nas-run.py |
通过 SSH 在 NAS 执行命令 |