SnowLuma 在 Linux 上只通过 Docker 运行。镜像内置 Linux QQ + Xvfb + VNC + noVNC + supervisord,开箱即用;宿主机只需要 Docker。
镜像构建脚本与 Compose 模板在独立仓库 SnowLuma/SnowLuma.Docker.Framework。
| 项 | 值 |
|---|---|
| 镜像 | motricseven7/snowluma:latest (或具体 tag :v1.10.0) |
| 架构 | linux/amd64、linux/arm64 |
| 基础 | node:22-bookworm-slim |
| 内置 | Linux QQ、Xvfb、VNC、noVNC、supervisord、SnowLuma lite 发行包 |
镜像不在容器内重新编译 SnowLuma —— 它消费主仓 GitHub Release 的预编译 lite tarball,所以发版与镜像构建解耦。
| 端口 | 用途 |
|---|---|
5900 |
VNC(远程桌面,密码登录 QQ 用) |
6081 |
noVNC(浏览器版 VNC,无客户端访问) |
5099 |
SnowLuma WebUI |
3000 |
OneBot HTTP(默认) |
3001 |
OneBot WebSocket(默认) |
--cap-add=SYS_PTRACE 和 --security-opt seccomp=unconfined 仍然不能省。
SnowLuma 的 native addon 通过 ptrace 把 hook 注入到容器内的 QQ 进程。官方镜像会给 /usr/local/bin/node 设置 cap_sys_ptrace,所以 SnowLuma 即使用 snowluma 普通用户运行,也能在容器的 capability 边界内完成注入。
因此,新版官方镜像不需要再修改宿主机的 kernel.yama.ptrace_scope。只要启动容器时保留:
如果你想确认镜像内的 file capability 是否存在:
如果旧镜像仍要求你修改宿主机 sysctl,优先升级镜像;只有在无法升级的临时排障场景下,才考虑调整宿主机 kernel.yama.ptrace_scope。
--cap-add=SYS_PTRACE 和 --security-opt seccomp=unconfined 不能省。SnowLuma 的 native addon 通过 ptrace 把 hook 注入 QQ 进程,默认 seccomp profile 会拦截。
--shm-size=1g 是 QQ(基于 Chromium)的运行要求,容器默认 /dev/shm 太小会崩。
更推荐用 Compose。仓库 docker-compose.yml:
启动:
升级镜像:
| 变量 | 默认 | 说明 |
|---|---|---|
VNC_PASSWD |
vncpasswd |
VNC / noVNC 登录密码。改成自己的,不然别人也能进容器里看你 QQ。 |
TZ |
Asia/Shanghai |
容器时区。Dockerfile 预设,可通过环境变量覆盖。 |
SNOWLUMA_UID |
1000 |
容器内 snowluma 用户的 uid。和你挂载卷的宿主属主匹配。 |
SNOWLUMA_GID |
1000 |
容器内 snowluma 用户的 gid。 |
SNOWLUMA_WEBUI_PORT |
5099 |
WebUI 监听端口(容器内)。 |
SNOWLUMA_WEBUI_HOST_PORT |
5099 |
WebUI 宿主机映射端口(默认同容器内端口)。 |
SNOWLUMA_LOG_LEVEL |
info |
error / warn / info / debug。 |
SNOWLUMA_SCREEN |
1920x1080x24 |
Xvfb 分辨率 + 色深。 |
SNOWLUMA_HOOK_AUTOLOAD |
1 |
镜像默认开自动注入。设 0 切回手动 Load 流程。 |
SNOWLUMA_EXTRA_QQ_HOMES |
空 | 逗号或空格分隔的额外 QQ /app/... HOME 列表,用于多开账号自动启动。 |
SNOWLUMA_QQ_FLAGS |
--disable-gpu --disable-software-rasterizer --disable-gpu-compositing |
传给 Linux QQ 的启动参数。默认关闭 GPU / SwiftShader 软件渲染,防止内存泄漏。 |
VNC_PORT |
5900 |
VNC 宿主机映射端口。 |
NOVNC_PORT |
6081 |
noVNC 宿主机映射端口。 |
ONEBOT_HTTP_PORT |
3000 |
OneBot HTTP 宿主机映射端口。 |
ONEBOT_WS_PORT |
3001 |
OneBot WebSocket 宿主机映射端口。 |
环境变量优先级高于 runtime.json,所以 Docker 用环境变量覆盖最方便。
| 卷 | 容器路径 | 内容 |
|---|---|---|
snowluma-data |
/app/snowluma-data |
SnowLuma 配置、缓存、SDB 等。config/onebot.json 和 config/runtime.json 都在这里。 |
snowluma-qq-config |
/app/.config |
QQ 客户端配置。 |
snowluma-qq-data |
/app/.local/share |
QQ 用户数据(登录态、缓存等)。 |
升级镜像不要删这三个卷,否则会丢登录态和配置。
http://<IP>:6081/(noVNC),输入 VNC_PASSWD。http://<IP>:5099/ 访问 SnowLuma WebUI。首次启动会在日志里输出一次性密码:
只要密码字符串:
临时密码只在全新数据卷首次启动时输出一次。复用旧卷 / 重启都不会重新生成。
Linux QQ 自带单实例锁:在已有 QQ 跑着的桌面里直接再点一次 QQ 图标,只会把已有窗口聚焦,起不来第二个进程。锁文件落在 $HOME/.config/QQ/SingletonLock,所以解法是给第二个实例一个独立的 HOME。
SnowLuma 一侧不需要任何额外配置:HookManager 会遍历所有 QQ 主进程,新启动一个就自动注入一个,每个 UIN 拉一个独立 OneBotInstance,配置存到对应的 config/onebot_<uin>.json。
给每个额外账号准备一个独立卷,并把对应容器路径写进 SNOWLUMA_EXTRA_QQ_HOMES。列表支持逗号或空格分隔:
容器启动时会为每个额外 HOME 生成一个 supervisor program,使用 snowluma 用户、同一个 DISPLAY=:1 和同一组 SNOWLUMA_QQ_FLAGS 启动 QQ。这样不会出现手动 docker exec 默认 root 导致 SnowLuma 无法注入的问题。
查看进程状态:
如果只是临时多开,不想改 Compose,也可以手动启动。关键是不要用 root,要显式指定 snowluma 用户、DISPLAY 和独立 HOME:
如果 /app/qq-acct2 没有挂卷,容器重建后这个账号的登录态会丢;长期使用仍推荐上面的 Compose 方式。
HOME —— 别让两个 QQ 共用同一个 HOME,会冲突。--shm-size 主账号 1GB 够用,多开建议加到 2gb 或更高。get_login_info 都会出现新 UIN。fluxbox,不是 XFCE/GNOME 会话;~/.config/autostart/*.desktop 不一定会被读取。多开自启交给 supervisor 更稳。镜像默认开 SNOWLUMA_HOOK_AUTOLOAD=1:容器一启动就把 hook 注入 QQ 主进程(被动观察),扫码登录完成后 hook 自动切到工作模式。supervisor 让 QQ 崩溃自动重启时也走同样流程。
想保留传统的"WebUI 里手动 Load"流程:
或在 docker-compose.yml 改 SNOWLUMA_HOOK_AUTOLOAD: 0,或编辑持久卷里的 /app/snowluma-data/config/runtime.json 设 "hookAutoLoad": false。环境变量优先。
进容器:
查日志:
只看 SnowLuma 主进程日志(过滤掉 QQ 自己的输出):
进入 SnowLuma 数据目录:
修改 OneBot 配置:编辑 /app/snowluma-data/config/onebot_<uin>.json,重启容器:
宿主机端口被占用时,调宿主侧映射即可,容器内端口不变。例:把 OneBot HTTP 改为宿主的 8080:
或通过环境变量(Compose 模板已支持):
如果想用未发布的 SnowLuma 版本(比如本地分支):
或者直接让脚本从 release 拉:
多架构 manifest 合并请走 CI(.github/workflows/docker-image.yml);本地脚本只构建单平台。
SYS_PTRACE 能力和 seccomp=unconfined。仅在受信任的宿主上运行。vncpasswd 务必改掉,否则你的 QQ 桌面在公网上裸奔。