Self-hosted service
mkbula/qbitwebui avatar
mkbula/qbitwebui

qbitwebui puts several qBittorrent instances behind one dashboard

A modern web interface for managing qBittorrent instances. Supports mobile view with PWA. Features cross seed and many more tools.

593 stars30 forksTypeScriptMIT

At a glance

What is it?
qbitwebui is a self-hosted web interface for qBittorrent built with React 19, Hono and Bun, with a mobile view, a PWA, Prowlarr integration, a file browser and an experimental cross seed feature. It is a front end for qBittorrent rather than a replacement, and it stores its own state in SQLite alongside the torrent client it drives.
Who is it for?
Adopt qbitwebui if you run more than one qBittorrent instance, or if you want a usable mobile interface to a single one, and you are willing to run a second web service next to the torrent client. Do not adopt it as a replacement for the qBittorrent web UI, since it is a front end to the same API, and treat the cross seed feature as experimental, as the README does.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 12 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

One dashboard over several torrent clients

qbitwebui is described as a modern web interface for managing qBittorrent instances, with a mobile view and PWA support, and the heading in the README calls it a modern web interface for managing multiple qBittorrent instances.

The multi-instance part is the differentiator. The feature list leads with it, followed by instance statistics giving an overview of all instances with status, speeds and torrent counts, and real-time monitoring that auto-refreshes torrent status, speeds and progress. Most qBittorrent web interfaces manage one instance, and anyone with a home seedbox and a remote box, or a family sharing one account, ends up juggling several browser tabs.

The rest of the list is closer to a mature torrent client front end. Torrent management covers adding via magnet or file, setting priorities and managing trackers and peers. Organisation includes filtering by status, category, tag or tracker, plus custom views. There are bulk actions with a context menu and keyboard navigation, customizable columns you can show, hide and drag to reorder, multiple colour themes, a file browser for browsing and downloading files from the downloads directory, RSS management with rules and folders, and a network agent offering speedtest, IP check and DNS diagnostics.

There is also Prowlarr integration, which lets you search indexers and send torrents straight to qBittorrent, and an automatic cross seed feature that the README marks as experimental.

The primary language is TypeScript, the licence is MIT, the default branch is master, the last push was on 2026-10-11, and the releases show v2.44.1 in May 2026, v2.44.2 in July and v2.45.0 in October. The documentation site is at mkbula.github.io/qbitwebui, with separate pages for the Docker setup and the full feature list.

React on the client, Hono on the server, Bun underneath

The tech stack line in the README is short and tells you the shape of the application: React 19, TypeScript, Tailwind CSS v4, Vite, TanStack Query, Hono, SQLite, Bun.

The dependency list in package.json fills in the details. On the server side, hono at 4.13.13 is the HTTP framework, and the project is marked private with the type module. jszip and tar-stream are there for archive handling, xml2js for XML parsing, and vaul is a drawer component library for the React side, alongside lucide-react for icons, colord and react-colorful for colour handling, which is what the themes feature is built on.

The runtime is Bun, and the package.json is explicit about it. The packageManager field pins [email protected] and the engines field requires bun >=1.3.2, and there is a preinstall script that runs npx only-allow bun, which blocks an install with npm or yarn outright rather than failing later. That is a firm constraint, and it is a reasonable one for a project that uses Bun's runtime, its bundler and its test runner.

The storage is SQLite, and the container image makes that explicit with two environment variables: DATABASE_PATH pointing at /data/qbitwebui.db and SALT_PATH pointing at /data/.salt, with a VOLUME declared at /data. The salt file is the interesting one, because it is the kind of detail that indicates passwords are hashed with a per-installation salt, and a salt that lives on the data volume so it survives a container rebuild.

The server scripts reflect the split of concerns. The dev script runs the server and the Vite dev client concurrently, the build runs tsc -b and then vite build, and the production start runs the server entry point directly with bun.

The Docker compose file and the flags that matter

The README's Docker example is the reference deployment, and half of it is commented out options, which tells you what the author expects people to change:

yaml
services:
  qbitwebui:
    image: ghcr.io/mkbula/qbitwebui:latest
    ports:
      - "3000:3000"
    environment:
      # Generate your own: openssl rand -hex 32
      - ENCRYPTION_KEY=your-secret-key-here
      # Uncomment to disable login (single-user mode)
      # - DISABLE_AUTH=true
      # Uncomment to disable registration (creates default admin account)
      # - DISABLE_REGISTRATION=true

The rest of the example covers the file browser and the volume:

yaml
      # Uncomment to allow HTTPS with self-signed certificates
      # - ALLOW_SELF_SIGNED_CERTS=true
      # Uncomment to enable file browser
      # - DOWNLOADS_PATH=/downloads
    volumes:
      - ./data:/data
      # Uncomment to enable file browser (read-only: browse & download only)
      # - /path/to/your/downloads:/downloads:ro
      # Or mount read-write to enable delete/move/copy/rename
      # - /path/to/your/downloads:/downloads
    restart: unless-stopped

The ENCRYPTION_KEY is the one you must not leave as a placeholder, and the comment tells you how to generate a real one with openssl rand -hex 32.

The file browser is a deliberate privilege decision. The comments spell out the difference between a read-only mount, which allows browsing and downloading, and a read-write mount, which additionally allows delete, move, copy and rename. Mounting the downloads directory read-write into a web service that is reachable from a phone is worth thinking about twice.

The Dockerfile in the repository is a two stage Bun build that ends with the same environment variables, exposes port 3000 and runs bun run src/server/index.ts, and the compose file publishes 3000 to the host.

The cross seed feature and where it came from

Cross seed is listed in the features as automatic cross seed directly in qbitwebui, with the parenthetical that it is experimental. The credits section then explains the provenance: big thanks to cross-seed, and a huge chunk of the qbitwebui cross seed implementation is basically taken from cross-seed directly, or ported and slightly adjusted, with the explicit statement that qbitwebui is in no way associated with or endorsed by cross-seed.

That is worth reading as an engineering fact rather than a formality. Cross seeding is the practice of finding a second torrent with the same content and downloading from both, so a seeder is not the single point of failure. It is a subtle piece of logic, because it depends on matching releases by name, size and content rather than by infohash.

The author's own recommendation is worth repeating: check cross-seed out if you want something very reliable. That is a maintainer telling you that the upstream tool is the better answer for the core job, and it is the sort of honesty that makes the rest of the feature list more credible.

The Prowlarr integration is the other feature that reaches outside qBittorrent. Sending a search result straight from an indexer into the client is a small feature that removes a lot of copy and paste from a seeding workflow, and it fits the self-hosted audience, since Prowlarr is part of the same Servarr ecosystem and appears in the repository topics.

Running it from source with Bun

Development is three commands, and the first one is the encryption key again:

bash
export ENCRYPTION_KEY=$(openssl rand -hex 32)

bun install
bun run dev

The dev script runs the Hono server in watch mode and Vite side by side, which is the standard split for a React application with a server: the client has hot module replacement, the server restarts on change, and the client talks to the API through the dev proxy rather than a separate origin.

The rest of the script list is a complete toolchain. check runs the TypeScript project build with no emit, lint runs eslint, format runs prettier over src, preview serves the built client, and the test scripts run vitest with a watch mode, a coverage variant, and a jsdom environment with the Testing Library packages for React and DOM.

The documentation has its own scripts too, docs:dev, docs:build and docs:preview, all driving VitePress, which tells you the docs site is part of the same repository and the same build tooling rather than a separate setup.

The repository layout supports this shape. There are separate tsconfig files for the app, the node side and the server, a vite.config.ts for the client build and a vitest.config.ts for the tests, a net-agent/ directory for the speedtest, IP check and DNS diagnostics feature, a __tests__/ directory, a public/ directory for static assets, and a docs/ directory.

The package is marked private, which is normal for an application rather than a library, and the releases are published as container images from ghcr.io/mkbula/qbitwebui.

What to check before you point this at a seedbox

The failure modes here are mostly about exposure rather than about features.

The first is that qbitwebui is a web service in front of a torrent client, and the qBittorrent API it talks to is an administrative interface. The compose example publishes port 3000 on the host with no reverse proxy and no TLS in front of it, which is fine on a home network and a problem on the public internet. The ALLOW_SELF_SIGNED_CERTS option exists for people who want to put HTTPS in front of it, and the sensible arrangement is a reverse proxy with real certificates and the dashboard behind it.

The second is the ENCRYPTION_KEY. It encrypts whatever the dashboard stores, and the placeholder value in the example is a placeholder. If you deploy with the example as written, your session secrets and stored credentials are protected by a key that is in a public repository. Generating a real one with openssl rand -hex 32 is one command.

The third is the account model. DISABLE_AUTH turns off login entirely for single-user mode, and DISABLE_REGISTRATION creates a default admin account instead. Both are reasonable on a private LAN and dangerous on a network you do not control, and the defaults are the safe ones, so leaving them commented is the right starting point.

The fourth is the file browser. The read-only mount is described as browse and download only, and the read-write mount adds delete, move, copy and rename. The read-only option is the one to enable first, because a torrent client already has write access to the data it downloads.

None of that is a criticism of the project. It is a description of what a self-hosted panel does: it puts a nicer, more capable interface in front of an administrative API, and it asks you to decide who may use it.

Editorial conclusion

Adopt qbitwebui if you run more than one qBittorrent instance, or if you want a usable mobile interface to a single one, and you are willing to run a second web service next to the torrent client. Do not adopt it as a replacement for the qBittorrent web UI, since it is a front end to the same API, and treat the cross seed feature as experimental, as the README does. Before you deploy, generate a real ENCRYPTION_KEY rather than the placeholder, decide whether the file browser should be mounted read-only, and check that exposing the dashboard does not put the qBittorrent API on the public internet.

Frequently asked questions

What is qbitwebui and what does it add over the qBittorrent web UI?

qbitwebui is a self-hosted web interface built with React 19, Hono and Bun that manages multiple qBittorrent instances from one dashboard, with real-time monitoring, instance statistics, a file browser, RSS management, a network agent for speedtest and DNS diagnostics, and a mobile PWA view.

How do I deploy qbitwebui with Docker?

Use the compose example in the README, which runs the ghcr.io/mkbula/qbitwebui:latest image on port 3000 with a data volume mounted at /data. The environment block shows the options for ENCRYPTION_KEY, DISABLE_AUTH, DISABLE_REGISTRATION, ALLOW_SELF_SIGNED_CERTS and DOWNLOADS_PATH.

Is the cross seed feature in qbitwebui reliable?

The README lists it as experimental, and the credits section says a huge chunk of the implementation is taken from or ported from the cross-seed project. The author recommends checking cross-seed out directly if you want something very reliable.

What does qbitwebui need to run from source?

Bun, since the package pins [email protected], requires it as an engine and blocks other package managers with an only-allow bun preinstall script. You export an ENCRYPTION_KEY, run bun install, and then bun run dev, which starts the Hono server and the Vite client together.

Official sources

  1. License: MIT
  2. mkbula/qbitwebui on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/mkbula-qbitwebui.svg)](https://hysenlabs.com/projects/mkbula-qbitwebui)

Was this useful?