On Linux, Docker is the recommended and the only officially supported path: Docker deployment bundles Linux QQ + Xvfb + VNC + noVNC + supervisord + ptrace permissions + hot-update freeze, ready to go. This page replicates by hand what the image does — for advanced users who can't or won't use Docker. It has many steps and many footguns, and it depends heavily on your distro and kernel settings. If you just want it running, go back to Docker deployment.
This page is the manual version of the official image's start.sh: install Node, install Linux QQ, bring up a headless X desktop, grant ptrace to node, freeze QQ's hot-update, run SnowLuma, scan-login. The commands below target Ubuntu 24.04 (Noble); package names and paths differ on other distros — translate accordingly.
Manual deployment is the same things the image does, in order:
.deb) plus its Electron / CJK dependencies.cap_sys_ptrace to node without root (the hook injects via ptrace).-lite linux tarball, run node ./index.mjs.SnowLuma needs Node.js ≥ 22. In 2026, Node 24 ("Krypton") is Active LTS and 22 ("Jod") is in Maintenance LTS — for a fresh install go with 24. The lite distribution has no bundled runtime, so this step is mandatory.
Using the official NodeSource repo (Debian/Ubuntu):
Or install Node 24 via nvm / your preferred version manager. Node release details: https://nodejs.org/en/about/previous-releases.
If you downloaded the full tarball (which bundles a Node runtime), you can skip this step — but the full package is much larger. This page follows the more common lite flow throughout.
The official Linux QQ download page is JS-rendered, so don't hard-code a version — grab the current .deb for your arch from https://im.qq.com/linuxqq/download.html:
QQ installs to /opt/QQ/, with the launcher at /opt/QQ/qq.
Install the Electron / CJK runtime deps. On Ubuntu 24.04 it's libasound2t64, not libasound2:
Without fonts-noto-cjk, Chinese text in QQ renders as tofu boxes.
Login is QR-scan only — there is no CLI login, so you must be able to see the QQ window to scan it. On a headless server, Xvfb provides a virtual screen, fluxbox lets QQ's login dialog map properly, and x11vnc + noVNC project that screen into a browser.
Install (Ubuntu 24.04 package names):
Start the virtual screen and set DISPLAY (the image uses :1):
Start a window manager (otherwise the login dialog may be borderless / unfocusable):
Start VNC (set a password — it lands in ~/.vnc/passwd):
Start noVNC (browser-based VNC, no client needed). On Ubuntu the launcher is at /usr/share/novnc/utils/novnc_proxy:
Then open http://<your-ip>:6081/vnc.html in a browser, connect with the VNC password you just set, and you'll see the :1 virtual desktop.
Never expose VNC (5900) / noVNC (6081) / WebUI (5099) / OneBot (3000, 3001) raw on the public internet. Bind them to localhost behind a firewall, an SSH tunnel, or an authenticated reverse proxy. Always set a strong VNC password — otherwise your QQ desktop is wide open.
SnowLuma's native addon uses ptrace to inject the hook into the QQ process. Rather than run as root, give the node binary a file capability:
Verify:
setcap caveats (read these):
readlink -f resolves the symlink behind which node; the capability does not follow symlinks.setcap after every Node upgrade.setcap fails on some overlay / tmpfs mounts.ptrace_scope: 0 / 1 / 2 all work with the file capability, but 3 disables ptrace entirely. Check with cat /proc/sys/kernel/yama/ptrace_scope.
:::QQ has a silent hot-update channel that quietly rewrites bytes in the background and breaks your version-pinned native hook. (The "Update now" full-package dialog in the UI is click-gated and never fires headless, so you only need to block the silent channel.) Black-hole the patch host:
Now QQ can't fetch silent patches, the version stays stable, and the hook won't be swapped out from under you.
Download the -lite linux tarball for your arch from the GitHub Releases: https://github.com/SnowLuma/SnowLuma/releases
On first run it creates its config in the data dir (config/onebot.json, config/runtime.json, etc.) and logs a one-time WebUI admin password — note it down, it appears only on a brand-new data dir's first boot.
:::info
Default services: OneBot HTTP 0.0.0.0:3000, OneBot WS 0.0.0.0:3001, WebUI 0.0.0.0:5099. See Configuration for details. Environment variables override runtime.json.
Keep SnowLuma running (foreground or another session), then launch QQ under the same DISPLAY=:1 with the documented flags:
Then:
http://<your-ip>:6081/vnc.html, connect over VNC, and you'll see QQ's QR code.runtime.json.hookAutoLoad defaults on; set false or SNOWLUMA_HOOK_AUTOLOAD=0 to revert to manual Load in the WebUI).http://<your-ip>:5099/ for the WebUI and log in with the bootstrap password from the logs.Multiple accounts need no extra config: SnowLuma walks every QQ main process, injects each, and spins up one OneBot instance per UIN with its own config/onebot_<uin>.json. The key to running more than one is giving each QQ instance its own HOME (QQ ships a single-instance lock).
The manual flow is sensitive to your environment. These bits depend heavily on your machine:
libasound, the X tools, and the noVNC launcher path.ptrace_scope=3 disables ptrace injection entirely.&-backgrounded processes above die when your shell exits. For long-running setups, manage Xvfb, fluxbox, x11vnc, noVNC, QQ, and SnowLuma under systemd / supervisor / tmux.If any step gets stuck in your environment, the easiest path remains Docker deployment — the image has already smoothed over all of this.