English | 繁體中文
Based on the qnap-dev/containerized-qpkg architecture, this package wraps the official RoonLabs Docker image (ghcr.io/roonlabs/roonserver) into an installable QPKG for QNAP App Center.
This package only contains management scripts and a status page (UI wrapper); it does not include any Roon software or images. When a user installs it in App Center, the package runs the container engine (docker CLI of Container Station) in the background to download the official image and build the container. The installation itself takes only a few seconds.
App Center installs QPKG (scripts & status UI only, < 1 MB)
│
▼
package_routines ──► Background: docker pull ghcr.io/roonlabs/roonserver:latest
│
▼
roon-server-docker.sh start ──► docker run --net=host -v <SSD>/RoonServer/data:/Roon ...
└───► busybox httpd container (port 18630) for status UI
The internal package name is
RoonServerDocker(displayed as "Roon Server (Docker)"). This is intentionally different from the QNAP Store package name "RoonServer" — identical names would cause App Center to misidentify it and force-overwrite it with the store version during updates.
| Item | Requirement |
|---|---|
| NAS Arch | x86_64 (amd64), official Roon image does not support ARM |
| QTS | 5.0 or above |
| Dependency | Container Station 3.0+ (QPKG_REQUIRE automatically checks this) |
| Memory | 8 GB or more recommended (Roon Labs recommendation) |
| Storage | SSD storage pool is strongly recommended for the Roon database |
- Download
RoonServerDocker_x.y.z_x86_64.qpkgfrom Releases. - (If you have installed the old 1.0.0 version of the "RoonServer" package, please remove it from App Center first.)
- App Center → Click "Install Manually" in the top-right corner → Choose the downloaded qpkg file. Since the package is unsigned, if App Center blocks it, go to "App Center → Settings → General" to allow installing unsigned applications.
- After installation, the image will download in the background (takes a few minutes depending on network speed), and the container will be created and started automatically.
You can check the download progress at
<installation path>/logs/pull.log, or click the App Center/desktop icon to open the status page (http://<NAS IP>:18630/, served by the package's internal busybox httpd container — no need to enable QTS "Web Server" service). - Open the Roon App on a computer/tablet connected to the same local network; it will automatically discover the Roon Server on your NAS.
Roon relies on local network multicast/broadcast (RAAT protocol) to discover streaming playback devices (Roon Ready, AirPlay, Chromecast) and remote control apps. Bridge/NAT networks will block multicast packets, rendering device discovery and remote control entirely non-functional.
Therefore, roon-server-docker.sh hardcodes --net=host, and checks the container's network mode on every startup. If it is altered via the Container Station UI, it will automatically recreate the container in host mode (your Roon database remains unaffected). This setting cannot be overridden by ROON_EXTRA_ARGS in roon.conf.
The Roon database and cache (mounted as /Roon inside the container) perform heavy small-block random reads/writes. Storing them on a mechanical hard drive (HDD) volume causes high latency, leading to stuttering audio playback, slow playlist/library loading, and sluggish searches. The package guides users in three ways:
- Startup Detection: The service script performs a best-effort check using
/sys/block/*/queue/rotational. If the data path is located on an HDD, it logs a QTS system warning event and displays a warning banner on the status page. - Web UI Instruction: The status page (accessible by clicking the app icon) contains a step-by-step migration guide.
- Configuration Comments: Comments in
roon.confspecify SSD recommendations in uppercase.
Configuration steps:
# Log in to the NAS via SSH, edit <QPKG Installation Path>/roon.conf
ROON_DATA_PATH="/share/CACHEDEV2_DATA/RoonServer/data" # Point to an SSD volume path
# To migrate an existing database:
/etc/init.d/roon-server-docker.sh stop
cp -a /share/CACHEDEV1_DATA/RoonServer/data/. /share/CACHEDEV2_DATA/RoonServer/data/
/etc/init.d/roon-server-docker.sh startHow to confirm which volume is on an SSD pool: Open QTS "Storage & Snapshots Manager" → Storage, and check the disk type of the member drives in the storage pool (must be a pure SSD pool; SSD "cache" does not count).
| Variable | Default | Description |
|---|---|---|
ROON_IMAGE |
ghcr.io/roonlabs/roonserver:latest |
Official image |
ROON_DATA_PATH |
<default volume>/RoonServer/data |
Roon database/cache → container /Roon, please use SSD |
ROON_MUSIC_PATH |
Auto-detects Multimedia/Music/Public shares | Music library → container /Music |
ROON_BACKUP_PATH |
(Empty = not mounted) | Backup → container /RoonBackups |
ROON_TZ |
Auto-detects QTS timezone | IANA timezone name |
ROON_STOP_TIMEOUT |
120 |
Seconds to wait for a clean database shutdown on stop |
ROON_UI_PORT |
18630 |
Status page port (App Center icon link follows this automatically) |
ROON_UI_IMAGE |
busybox:stable |
Mini httpd container image for the status page |
ROON_EXTRA_ARGS |
(Empty) | Extra docker run arguments (cannot override network mode) |
After making changes, run /etc/init.d/roon-server-docker.sh restart or restart the package from App Center.
The configuration file is preserved during upgrades and re-installations.
The status page includes a "Folder Settings" form where you can directly modify the mount paths for Music, Database, and Backup, with suggestions of existing shared folders on the NAS. Once saved, the host checks and applies the settings and recreates the container within 1 minute:
- Paths must be under
/share/<shared-folder-or-volume>/. Any music path containing special characters or paths that do not exist will be rejected and logged to system events; - The form settings are saved as a pending file by a minimal CGI script inside the UI container. Parsing and validation are done entirely by host-side scripts; the UI container itself has no access to docker or host settings;
- Changing the database path does not automatically migrate existing data (see the migration steps above).
/etc/init.d/roon-server-docker.sh status # Check status
/etc/init.d/roon-server-docker.sh restart # Restart
/etc/init.d/roon-server-docker.sh update # Pull new official image & rebuild container (database is kept)
/etc/init.d/roon-server-docker.sh pull # Only pull the imageUninstalling the package deletes the container but preserves the Roon database under ROON_DATA_PATH to prevent accidental loss of licenses and listening history.
# Requires Docker (any platform)
make # Outputs build/RoonServerDocker_<version>_x86_64.qpkg
# Or directly using QDK on Ubuntu
git clone https://github.com/qnap-dev/QDK && cd QDK && sudo ./InstallToUbuntu.sh install
cd <this-project> && qbuild --build-arch x86_64GitHub Actions builds the qpkg artifact on every push and automatically publishes a release when a v* tag is pushed.
├── qpkg.cfg # QPKG metadata (CS dependency, WebUI URL)
├── package_routines # Install/remove hooks: background pull, config & DB preservation
├── shared/
│ ├── roon-server-docker.sh # Service script: finds docker, enforces host network, SSD check, status UI
│ ├── roon.conf.default # User configuration template
│ └── web/index.html # Status page / guide (UI wrapper, served by busybox httpd)
├── icons/ # App Center icons
├── x86_64/ # qbuild architecture tag (this package is script-only)
├── Dockerfile / Makefile # QDK build files
└── .github/workflows/ # CI: Build and Release
| Symptom | Cause & Solution |
|---|---|
| App Center shows "Update available" and forces an update | You are using the old 1.0.0 version (internal name RoonServer, identical to the store package). Please remove the old version and install 1.1.0+ (internal name RoonServerDocker, which avoids conflicts). |
| Shows "No digital signature" | This package is not signed by QNAP; this is normal. Go to App Center settings to allow unsigned applications. |
| Click icon but status page doesn't open | The status page is served by the package's busybox httpd container on port 18630. Verify that the package is running. If the port is occupied, change ROON_UI_PORT in roon.conf and restart. |
| Roon App cannot find the server | Ensure the container network is in host mode (this app fixes it on every boot), that the NAS and remote are on the same subnet, and that the image download has finished (check the status page or logs/pull.log). |
| Image download stuck | SSH and run /etc/init.d/roon-server-docker.sh diag to check DNS/registry access; you can also run docker pull ghcr.io/roonlabs/roonserver:latest to observe errors, then restart. The status page displays real-time pull progress (1.1.1+). |
Roon gets UnexpectedError when adding SMB network shares |
This is expected: Roon runs inside a container and cannot (and does not need to) mount SMB. Use Roon "Settings → Storage → Add folder" and select /Music. To change the music path, use "Folder Settings" on the status page. |
| System log says "Music path does not exist" | The default music path guess was wrong (from 1.2.0, the app auto-detects Multimedia/Music/Public shares from smb.conf). Go to the status page "Folder Settings" and point the music library to your actual shared folder. |
The management scripts are licensed under the Apache License 2.0. Roon and Roon Server are products of Roon Labs LLC, and their software/images are subject to Roon Labs' own terms of service. This project is not affiliated with Roon Labs or QNAP.