Skip to content
 
 

Repository files navigation

crates.io crates.io docs.rs

rqbit - bittorrent client in Rust

rqbit is a bittorrent client written in Rust. Has HTTP API and Web UI, and can be used as a library.

Also has a desktop app built with Tauri.

Usage quick start

Optional - start the server

Assuming you are downloading to ~/Downloads.

rqbit server start ~/Downloads

Download torrents

Assuming you are downloading to ~/Downloads. By default it'll download to current directory.

rqbit download [-o ~/Downloads] 'magnet:?....' [https?://url/to/.torrent] [/path/to/local/file.torrent]

Web UI

Access at http://localhost:3030/web/. See screenshot below (torrent names and speeds are simulated).

Desktop app

The desktop app is a thin wrapper on top of the Web UI frontend.

Download it in Releases for OSX and Windows. For Linux, build manually with

cargo tauri build

It looks similar to the Web UI (screenshot above).

Streaming support

rqbit can stream torrent files and smartly block the stream until the pieces are available. The pieces getting streamed are prioritized. All of this allows you to seek and live stream videos for example.

You can also stream to e.g. VLC or other players with HTTP URLs. Supports seeking too (through various range headers). The streaming URLs look like http://IP:3030/torrents/<torrent_id>/stream/<file_id>

Integrated UPnP Media Server

rqbit can advertise managed torrents to LAN, e.g. your TVs and stream torrents there (without transcoding). Seeking to arbitrary points in the videos is supported too.

Usage from CLI

rqbit --enable-upnp-server server start ...

mDNS advertising

rqbit can advertise its HTTP API on your LAN via mDNS/DNS-SD, so you can open the Web UI at http://rqbit.local:3030/web/ from any device without knowing the server's IP.

Usage from CLI (requires a non-loopback listen address):

rqbit --enable-mdns --http-api-listen-addr 0.0.0.0:3030 server start ...

IPv6

rqbit supports IPv6. By default it listens on all interfaces in dualstack mode. It can work even if there's no IPv6 enabled.

Shell completions

Assuming bash, add this to your ~/.bashrc. Modify for your shell of choice.

eval "$(rqbit completions bash)"

Socks proxy support

rqbit --socks-url socks5://[username:password]@host:port ...

Tunnel mode

rqbit tunnel is an encrypted TCP tunnel between a reachable VPS server and an enrolled client. The carrier uses a private BitTorrent v2 (BEP 52) info-hash and MSE/PE on the wire; Noise IK authenticates and encrypts every tunnel frame. The managed server relays authorized client traffic to destination hosts.

Managed-server quickstart: see scripts/tunnel/README.md. The server is a root-owned systemd service, not a foreground rqbit server start command.

Honest scope: this blends at the protocol level. A long-lived, high-throughput connection to one IP is still distinguishable by traffic analysis; it does not hide traffic shape.

Install the VPS server

Extract a trusted Linux release bundle and run its bootstrap script from the bundle directory. It automatically uses the bundled rqbit-tunnel and rqbit, never an executable selected from PATH:

cd rqbit-tunnel-x86_64-unknown-linux-gnu
SERVER_IP="$PUBLIC_SERVER_IPV4" ./server-quickstart.sh

It discovers a public IPv4 address only as a best effort. Set SERVER_IP to the VPS's reachable numeric public IPv4 address when known. The generated server binds peer_listen to 0.0.0.0:PEER_PORT and writes that public endpoint separately as advertised_peer for enrollment bundles; this also works when the VPS uses 1:1 NAT.

The installation creates root-owned /etc/rqbit-tunnel, /var/lib/rqbit-tunnel, /var/lib/rqbit-tunnel/enrollments, and /run/rqbit-tunnel; server.key is mode 0600. On refresh, the installer stops an active managed service and waits for its control socket to disappear before replacing files and starting it again; the protected configuration, key, and database stay intact. If the unit is inactive while a control-socket path exists, it aborts rather than starting beside an unknown server.

It then runs daemon-reload, enables and starts the service, and requires both an active systemd unit and local server users list --json health before opening the TUI. Automation must opt out explicitly:

# Set PUBLIC_SERVER_IPV4 to the VPS's real reachable public IPv4 address.
SERVER_IP="$PUBLIC_SERVER_IPV4" ./server-quickstart.sh --skip-tui

The service command is exactly:

/opt/rqbit-tunnel/rqbit-tunnel server run --config /etc/rqbit-tunnel/server.json

SSH administration

The Unix control socket is local to the VPS at /run/rqbit-tunnel/server.sock; no management port is exposed. From an SSH terminal:

ssh -t admin@your-vps 'sudo /opt/rqbit-tunnel/rqbit-tunnel server tui'

The dashboard refreshes state every second; F5 requests an immediate refresh. It adds users only through an explicit name/export-path flow and displays a confirmation before writing an enrollment bundle. The service sandbox can write only its managed paths, so choose a path below /var/lib/rqbit-tunnel/enrollments, not /root or /home. The CLI supports the same operations for automation:

sudo /opt/rqbit-tunnel/rqbit-tunnel server users list --json
sudo /opt/rqbit-tunnel/rqbit-tunnel server users add \
  --name alice --export /var/lib/rqbit-tunnel/enrollments/alice.rqbt
sudo /opt/rqbit-tunnel/rqbit-tunnel server users disable USER_ID
sudo /opt/rqbit-tunnel/rqbit-tunnel server users delete USER_ID
sudo /opt/rqbit-tunnel/rqbit-tunnel server settings show --json

Disable immediately removes the user's admission key and ends active carrier sessions; an explicit later enable restores that same user's access. Delete does the same and removes the record, so the old bundle stays revoked even if a later user is created.

Operate an enrolled client

Transfer a server-issued enrollment bundle over an authenticated channel, then run the client as a managed service rather than a detached foreground process. The complete platform procedures are in scripts/tunnel/README.md.

On Linux, extract the signed release bundle and run sudo ./install-client.sh. On Windows, run .\install-client.ps1 from an Administrator PowerShell. Each bootstrap installs a stable launcher plus an immutable versioned payload; all service commands must go through that launcher:

sudo /opt/rqbit-tunnel/launcher client import --bundle /secure-transfer/alice.rqbt
sudo /opt/rqbit-tunnel/launcher client config set --socks-listen 127.0.0.1:1080
sudo /opt/rqbit-tunnel/launcher client service install
sudo /opt/rqbit-tunnel/launcher client service start
/opt/rqbit-tunnel/launcher client service status --json
sudo /opt/rqbit-tunnel/launcher client service enable-autostart

Run client service restart after a configuration change. client service disable-autostart removes future boot activation only; use client service stop separately to terminate a live client. The delivered client-run.sh, client-run.ps1, and client-run.bat provide the same interactive flow.

The dashboard's u action checks the pinned, signed GitHub Release manifest only after confirmation, then asks again before installing the displayed version. It has no background updater; a failed local health check restores the previous release. A release that requires a newer launcher ABI requires a matching manual bundle installation.

Run the per-user tray through launcher tray, never from the service account. It opens the dashboard on click and reports gray (local IPC unavailable), red (service failed), yellow (reconnecting/no carrier), or green (live carrier). Linux exits successfully with tray unavailable if its desktop has no supported tray backend. The Linux service and CLI payload do not load desktop libraries; GTK/AppIndicator runtime dependencies apply only to the separate rqbit-tunnel-tray companion.

Traffic counters

upload means client → VPS → destination: TCP payload counts after a successful destination write and UDP after a successful destination send. download means destination → VPS → client: TCP counts after the client confirms its local SOCKS write, while UDP counts once queued toward the client because it has no delivery acknowledgement. Totals exclude tunnel framing, cryptographic overhead, cover traffic, rejected requests, failed writes, and unsent queue contents.

Counters refresh live in memory and attempt a SQLite flush at least once per second (and synchronously during graceful shutdown). After successful flushes, a power loss can omit no more than the last unflushed second. If SQLite remains unwritable, pending deltas stay in memory and a power loss can lose every delta since the last successful flush; totals are not per-byte crash-durable.

Security boundaries

  • Enrollment bundles are unencrypted transferable secrets. Each export contains a client private key; any holder can use the tunnel until the user is disabled or deleted. Export only on an explicit TUI/CLI action to a protected path.
  • Client SOCKS defaults to loopback. The default server-issued bundle configures 127.0.0.1:1080. A non-loopback listener is rejected unless the operator passes --allow-unauthenticated-lan-socks true; this creates an unauthenticated open proxy for every reachable host. Use it only behind a trusted network boundary. The client dashboard keeps a persistent critical warning while that setting is enabled.

Watching a directory for .torrents

rqbit server start --watch-folder [path] /download/path

Systemd socket activation

rqbit can be started on-demand via systemd socket activation by installing the service and socket systemd units into $XDG_CONFIG_HOME/systemd/user/ (~/.config/systemd/user) and customizing them to your needs. If the associated rqbit.conf file is installed in $XDG_CONFIG_HOME/rqbit/rqbit.conf (~/.config/rqbit/rqbit.conf), it will be used to configure rqbit when started via the provided systemd unit.

Performance

Anecdotally from a few reports, rqbit is faster than other clients they've tried, at least with their default settings.

Memory usage for the server is usually within a few tens of megabytes, which makes it great for e.g. RaspberryPI.

I've got a report that rqbit can saturate a 20Gbps link, although I don't have the hardware to confirm.

Installation

There are pre-built binaries in Releases.

Homebrew

rqbit can be installed using Homebrew.

brew install rqbit

Cargo

If you have the Rust toolchain installed then you can use the following.

cargo install rqbit

Docker

Docker images are published at ikatson/rqbit

Build

Just a regular Rust binary build process.

cargo build --release

The "webui" feature requires npm installed.

Some useful options

Run rqbit --help to see all available CLI options.

-v

Increase verbosity. Possible values: trace, debug, info, warn, error.

--list

Will print the contents of the torrent file or the magnet link.

--overwrite

If you want to resume downloading a file that already exists, you'll need to add this option.

-r / --filename-re

Use a regex here to select files by their names.

Features (not exhaustive)

Supported BEPs

Some supported features

  • Sequential downloading (the default and only option)
  • Resume downloading file(s) if they already exist on disk
  • Selective downloading using a regular expression for filename
  • DHT support. Allows magnet links to work, and makes more peers available.
  • HTTP API
  • Pausing / unpausing / deleting (with files or not) APIs
  • Stateful server
  • Web UI
  • Streaming, with seeking
  • UPNP port forwarding to your router
  • UPNP Media Server
  • mDNS advertising
  • Fastresume (no rehashing)
  • Download / upload rate limiting
  • Prometheus metrics at /metrics and /torrents/<id_or_infohash>/peer_stats/prometheus

HTTP API

By default it listens on http://127.0.0.1:3030.

curl -s 'http://127.0.0.1:3030/'

{
  "apis": {
    "GET /": "list all available APIs",
    "GET /dht/stats": "DHT stats",
    "GET /dht/table": "DHT routing table",
    "GET /metrics": "Prometheus metrics",
    "GET /stats": "Global session stats",
    "GET /stream_logs": "Continuously stream logs",
    "GET /torrents": "List torrents",
    "GET /torrents/playlist": "Playlist for supported players",
    "GET /torrents/{id_or_infohash}": "Torrent details",
    "GET /torrents/{id_or_infohash}/haves": "The bitfield of have pieces",
    "GET /torrents/{id_or_infohash}/metadata": "Download the corresponding torrent file",
    "GET /torrents/{id_or_infohash}/peer_stats": "Per peer stats",
    "GET /torrents/{id_or_infohash}/peer_stats/prometheus": "Per peer stats in prometheus format",
    "GET /torrents/{id_or_infohash}/playlist": "Playlist for supported players",
    "GET /torrents/{id_or_infohash}/stats/v1": "Torrent stats",
    "GET /torrents/{id_or_infohash}/stream/{file_idx}": "Stream a file. Accepts Range header to seek.",
    "GET /web/": "Web UI",
    "POST /rust_log": "Set RUST_LOG to this post launch (for debugging)",
    "POST /torrents": "Add a torrent here. magnet: or http:// or a local file.",
    "POST /torrents/create": "Create a torrent and start seeding. Body should be a local folder",
    "POST /torrents/resolve_magnet": "Resolve a magnet to torrent file bytes",
    "POST /torrents/{id_or_infohash}/add_peers": "Add peers (newline-delimited)",
    "POST /torrents/{id_or_infohash}/delete": "Forget about the torrent, remove the files",
    "POST /torrents/{id_or_infohash}/forget": "Forget about the torrent, keep the files",
    "POST /torrents/{id_or_infohash}/pause": "Pause torrent",
    "POST /torrents/{id_or_infohash}/start": "Resume torrent",
    "POST /torrents/{id_or_infohash}/update_only_files": "Change the selection of files to download. You need to POST json of the following form {\"only_files\": [0, 1, 2]}"
  },
  "server": "rqbit",
  "version": "9.0.0-beta.1"
}

Basic auth

For HTTP API basic authentication set RQBIT_HTTP_BASIC_AUTH_USERPASS environment variable.

RQBIT_HTTP_BASIC_AUTH_USERPASS=username:password rqbit server start ...

Add torrent through HTTP API

curl -d 'magnet:?...' http://127.0.0.1:3030/torrents

OR

curl -d 'http://.../file.torrent' http://127.0.0.1:3030/torrents

OR

curl --data-binary @/tmp/xubuntu-23.04-minimal-amd64.iso.torrent http://127.0.0.1:3030/torrents

Supported query parameters, all optional:

  • overwrite=true|false
  • only_files_regex - the regular expression string to match filenames
  • output_folder - the folder to download to. If not specified, defaults to the one that rqbit server started with
  • list_only=true|false - if you want to just list the files in the torrent instead of downloading

Code organization

  • crates/rqbit - main binary
  • crates/librqbit - main library
  • crates/librqbit-core - torrent utils
  • crates/bencode - bencode serializing/deserializing
  • crates/buffers - wrappers around binary buffers
  • crates/clone_to_owned - a trait to make something owned
  • crates/sha1w - wrappers around sha1 libraries
  • crates/peer_binary_protocol - the protocol to talk to peers
  • crates/dht - Distributed Hash Table implementation
  • crates/upnp - upnp port forwarding
  • crates/upnp_serve - upnp MediaServer
  • desktop - desktop app built with Tauri
  • librqbit-utp - uTP protocol
  • librqbit-dualstack-sockets - cross-platform IPv6+IPv4 listeners with canonical IPs

Motivation

This project began purely out of my enjoyment of writing code in Rust. I wasn’t satisfied with my regular BitTorrent client and wanted to see how much effort it would take to build one from scratch. Starting with the bencode protocol, then the peer protocol, it gradually evolved into what it is today.

Donations and sponsorship

If you love rqbit, please consider donating through one of these methods. With enough support, I might be able to make this my full-time job one day — which would be amazing!

  • Github Sponsors
  • Crypto
    • ETH (Ethereum) 0x68c54b26b5372d5f091b6c08cc62883686c63527
    • XMR (Monero) 49LcgFreJuedrP8FgnUVB8GkAyoPX7A9PjWfKZA1hNYz5vPCEcYQ9HzKr3pccGR6Lc3V3hn52bukwZShLDhZsk57V41c2ea
    • XNO (Nano) nano_1ghid3z6x41x8cuoffb6bbrt4e14wsqdbyqwp5d8rk166meo3h77q7mkjusr

About

BitTorrent tunnel (Socks5) via rqbit (Rust BitTorrent client)

Topics

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages