Docker
Docker Compose
services:
qui:
image: ghcr.io/autobrr/qui:latest
container_name: qui
restart: unless-stopped
ports:
- "7476:7476"
volumes:
- ./qui:/config
#environment:
# Run as this user/group and chown /config (set both or neither).
# Alternative to the standard "user:" option, see the Permissions docs.
#PUID: "1000"
#PGID: "1000"
# Permission mask for new files and directories, for example 002 for group write
#UMASK: "002"
docker compose up -d
Docker Compose (Postgres)
services:
postgres:
image: postgres:16-alpine
container_name: qui-postgres
restart: unless-stopped
environment:
POSTGRES_USER: qui
POSTGRES_PASSWORD: qui
POSTGRES_DB: qui
volumes:
- ./postgres:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"]
interval: 10s
timeout: 5s
retries: 5
qui:
image: ghcr.io/autobrr/qui:latest
container_name: qui
restart: unless-stopped
depends_on:
postgres:
condition: service_healthy
ports:
- "7476:7476"
volumes:
- ./qui:/config
environment:
QUI__DATABASE_ENGINE: postgres
QUI__DATABASE_DSN: postgres://qui:qui@postgres:5432/qui?sslmode=disable
docker compose -f docker-compose.postgres.yml up -d
Standalone
docker run -d \
-p 7476:7476 \
-v $(pwd)/config:/config \
ghcr.io/autobrr/qui:latest
macOS container
On macOS, Apple Container runs the same image. Create the host folders first, then use container in place of docker:
container run -d \
-p 7476:7476 \
-v $(pwd)/config:/config \
ghcr.io/autobrr/qui:latest
Permissions
By default, the container runs as root. You can run qui as a different user in two ways. Use one or the other, not both.
With either method, qui needs write access to more than /config. Cross-seed hardlink and reflink mode create files in their base directory, and orphan scan deletes files from your scan paths. Those paths live on the data volumes (see Local filesystem access). Run qui as the user that owns that data, or as a member of its group.
user: (standard Docker)
Set user: in compose, or --user in docker run. Docker starts the container as that user.
services:
qui:
image: ghcr.io/autobrr/qui:latest
user: "1000:1000"
volumes:
- ./qui:/config
ports:
- "7476:7476"
If you use this method, make sure that the host folder mounted at /config is writable for that user:
chown -R 1000:1000 ./qui
PUID/PGID (automatic ownership)
Set both PUID and PGID environment variables. If you set only one variable, the container refuses to start. The entrypoint then:
- Creates a user and a group with those IDs
- Corrects the owner of every file under
/configthat does not match those IDs - Runs qui as that user
The result matches user:, but the entrypoint corrects the ownership of /config for you. If /config still contains root-owned files from an earlier run, or if the host folder has the wrong owner, this fixes the ownership.
services:
qui:
image: ghcr.io/autobrr/qui:latest
environment:
PUID: "1000"
PGID: "1000"
volumes:
- ./qui:/config
ports:
- "7476:7476"
docker run -d \
-e PUID=1000 \
-e PGID=1000 \
-p 7476:7476 \
-v $(pwd)/config:/config \
ghcr.io/autobrr/qui:latest
Do not combine user: with PUID/PGID. If the container does not start as root, the entrypoint cannot create users or change ownership. If you switch to PUID/PGID, remove any user: or --user setting first.
The entrypoint walks /config only, never your data volumes. As a result, a wrong PUID cannot chown your media library. A switch from root needs one manual step for the same reason. If qui already created hardlink or reflink trees as root, chown those directories once yourself:
find /data/cross-seed -type d -exec chown 1000:1000 {} +
Chown the directories only. Hardlinked files share their inode with the source download. If you run a recursive chown -R, that command also changes the owner of your library files. qui needs write access to the directories only.
UMASK
Optional. The qui binary reads UMASK at startup and applies it to new files and directories, such as cross-seed hardlink and reflink trees. If the value is not valid octal in the range 000 to 777, qui logs a warning and keeps the inherited umask.
The binary applies UMASK, not the entrypoint. As a result, UMASK works with both methods above. If you start a non-root container with user: or --user, UMASK also works.
Common values:
022: owner read/write, group and others read-only (typical default)002: owner and group read/write, others read-only (group-writable)077: owner only, no access for group and others (private)
Two exceptions:
- Regardless of
UMASK, qui always creates security-sensitive files (the database,config.toml, backup manifests) with owner-only mode (0600). - Hardlinked files share the inode with the source file. They keep the owner and permissions of the original download. See Directory permissions and umask.
Local filesystem access
Orphan scan, hardlinks, reflinks, and path-based automation rules require access to the same filesystem paths that qBittorrent uses.
Mount the same paths that qBittorrent uses. The paths must match exactly:
volumes:
- ./qui:/config
- /data/torrents:/data/torrents # Must match qBittorrent's path
After you mount the paths, enable Local Filesystem Access on each instance in qui's Instance Settings.
Unraid
The release workflow builds images for linux/amd64, linux/arm64, and ARM v6/v7, and publishes them to ghcr.io/autobrr/qui. The container runs on Unraid without extra steps.
Deploy from the Docker tab
- Open Docker → Add Container
- Set Name to
qui - Set Repository to
ghcr.io/autobrr/qui:latest - Keep the default Network Type (
bridgeworks for most setups) - Add a port mapping: Host port
7476→ Container port7476 - Add a path mapping: Container Path
/config→ Host Path/mnt/user/appdata/qui - Enable Advanced View (top right)
- Set Icon URL to
https://raw.githubusercontent.com/autobrr/qui/main/web/public/icon.png - Set WebUI to
http://[IP]:[PORT:7476] - Add environment variables
PUID=99andPGID=100. The entrypoint then corrects the ownership of/configand runs qui as uid 99 (nobodyon Unraid). If Extra Parameters contains--user, remove it first. If qui ran as root before, fix your data directories once (see Permissions) - (Optional) add environment variables for advanced configuration (for example
QUI__BASE_URL,QUI__LOG_LEVEL,TZ) - Click Apply to pull the image and start the container
By default, the /config mount stores config.toml, logs, the tracker icon cache, and other runtime assets. If you use the default SQLite engine, qui stores qui.db there too. An absolute logPath or a custom dataDir moves those files. config.toml always stays in /config (see the configuration reference). Point the mount at your appdata share so your configuration survives upgrades.
qui logs to stdout by default. Read the logs under Docker → qui → Logs. If you configure a relative log file path, qui writes it under /config.
Updating
- Pull a newer
latestimage with Unraid's Check for Updates action - If you pinned a version tag, edit the repository field to the new tag
- Restart the container after the image update to load the new binary
Updating
docker compose pull && docker compose up -d