A compact BitTorrent client implemented in Rust, with console, terminal, and built-in web interfaces. The CLI builds as one executable; macOS is also distributed as a native app bundle. It is still prerelease software, so keep a backup of important data.
Works on macOS 11 or newer and Linux. Windows support is partial (builds, but NAT-PMP gateway detection is not implemented).
- BitTorrent protocol — v1, v2, and hybrid metainfo with SHA-1/SHA-256 verification
- Magnet links — v1 metadata fetching via peers and DHT; verified HTTP sources for v2
- Trackers — HTTP and UDP (BEP 15)
- DHT — Distributed Hash Table (BEP 5) with K-bucket routing and node persistence
- PEX — Peer Exchange
- LPD — Local Peer Discovery (BEP 14)
- uTP — Micro Transport Protocol (BEP 29)
- MSE/PE — Message Stream Encryption for obfuscated connections
- NAT-PMP & UPnP — automatic port mapping
- Web seeds — HTTP/HTTPS seeding (BEP 19)
- Web UI — built-in browser interface
- IP filtering — blocklist support
- Torrent creation — create
.torrentfiles from local paths - Selective download — per-file priority
- Rate limiting — global and per-torrent bandwidth control
- Sequential mode — download pieces in order for streaming
- Watch folder — auto-load torrents from a directory
- Move on complete — relocate finished downloads
- Session persistence — resume state across restarts
The full build has five direct Rust dependencies:
native-tls— HTTPS tracker supportlibc— safe Unix file-opening flagsgetrandom— operating-system entropy for protocol identifiers, temporary names, and MSEnum-bigint— MSE Diffie-Hellman (optional,msefeature)num-traits— bigint helpers (optional,msefeature)
Everything else — bencode, SHA-1/SHA-256, HTTP, peer protocol, DHT, uTP, UPnP, NAT-PMP, and the
web UI — is implemented in the repository. Exact dependency versions are recorded in
Cargo.lock.
Rust 1.89 or newer is required.
Linux source builds also need pkg-config and the OpenSSL development package provided by the
distribution (commonly libssl-dev on Debian/Ubuntu or openssl-devel on Fedora/RHEL).
cargo build --release
The release profile is optimized for size (opt-level = "z", LTO, one codegen unit, and stripped
symbols) while retaining integer-overflow checks. Binary size varies by platform and toolchain;
current builds are typically around 1–2 MiB.
To build without peer-stream encryption (omits the MSE bigint dependencies):
cargo build --release --no-default-features --features udp_tracker,dht,utp,lpd,natpmp,upnp,webseed
| Platform | Status |
|---|---|
| macOS 11+ (x86_64, aarch64) | Fully supported |
| Linux x86_64 | Fully supported and CI-tested |
| Linux aarch64 | Source-supported; runtime is not continuously tested in CI |
| Windows | Builds, but NAT-PMP gateway detection unavailable |
Platform-specific capabilities are compile-time gated. MSE private keys use the operating system's cryptographic random-number provider.
rustorrent [options] [file.torrent]
The client prints progress to stdout and runs until stopped with Ctrl+C. Session state is saved
under <download-dir>/.rustorrent/ and is resumed on restart. Only one torrent path and one magnet
may be supplied at process startup; add further torrents through the web UI or a watch folder.
rustorrent ubuntu.torrentOutput:
[ubuntu-25.10-desktop-amd64.iso]
peers: 12/30 down: 4.2 MB/s up: 128.0 KB/s progress: 23.4% eta: 18:32
rustorrent --magnet "magnet:?xt=urn:btih:4b07d0071f9ceb21af6b8ba05b3a3c6f507e3fb2&dn=LibreOffice&tr=http://tracker.example.org:6969/announce"For v1 magnets the client fetches metadata from explicit peers, trackers, and DHT. A v2-only or
hybrid magnet currently needs a verified xs/as HTTP source containing the complete .torrent,
including its piece layers.
For hybrid .torrent sessions, peer handshakes support the BEP 52 v2 upgrade, but tracker, DHT,
and LPD discovery currently announce the v1 swarm identifier rather than discovering the v1 and
v2 swarms independently.
rustorrent --download-dir ~/Downloads ubuntu.torrentrustorrent --ui --watch ~/watch --download-dir ~/downloadsAdd torrents through the web UI or copy .torrent files into the watch directory. Torrents saved
in an existing session are also restored automatically.
rustorrent --sequential movie.torrentPieces are downloaded in order so a media player can start playback before the download finishes.
# Limit download to 5 MB/s, upload to 1 MB/s
rustorrent --download-rate 5242880 --upload-rate 1048576 ubuntu.torrent
# Per-torrent limit
rustorrent --torrent-download-rate 2621440 file1.torrentValues are bytes per second. k, m, and g suffixes use powers of 1024; 0 and unlimited
both mean unlimited.
# Prefer encrypted connections (default)
rustorrent ubuntu.torrent
# Require encryption — refuse unencrypted peers
rustorrent --encryption require ubuntu.torrent
# Disable encryption
rustorrent --no-encryption ubuntu.torrentrustorrent --download-dir ~/incomplete --move-completed ~/complete ubuntu.torrentWhen a torrent finishes, its files are moved from ~/incomplete to ~/complete.
The move is recorded transactionally and the torrent resumes seeding from the destination.
rustorrent --watch ~/watch --download-dir ~/downloadsThe client periodically scans ~/watch for new .torrent files and adds them automatically. Processed files are moved to a processed/ subdirectory.
rustorrent --preallocate ubuntu.torrentAllocates the full file size on disk before downloading. Avoids fragmentation on HDDs.
rustorrent --port 51413 ubuntu.torrentDefault listen port is 6881. The client uses NAT-PMP and UPnP to automatically map the port on your router when possible.
rustorrent --blocklist blocklist.txt ubuntu.torrentThe blocklist file contains one IP range per line in the format start-end or a single IP per line.
rustorrent --no-utp ubuntu.torrentForces the client to use TCP only. Useful if uTP causes issues with your network.
# Use presets instead of hand-tuning every peer knob
rustorrent --peer-profile conservative ubuntu.torrent
rustorrent --peer-profile balanced ubuntu.torrent
rustorrent --peer-profile aggressive ubuntu.torrent
# Allow more peers globally and per torrent
rustorrent --max-peers 500 --max-peers-torrent 80 ubuntu.torrent
# Limit torrents restored or added through the UI/watch folder
rustorrent --ui --max-active 2Profiles adjust --max-peers, --max-peers-torrent, --numwant, and the magnet metadata peer discovery limit:
| Profile | Global peers | Per torrent | Tracker numwant |
Magnet metadata peers |
|---|---|---|---|---|
conservative |
80 |
12 |
50 |
20 |
balanced |
200 |
30 |
200 |
80 |
aggressive |
500 |
80 |
500 |
160 |
balanced is the default and matches the previous behavior. If you also pass --max-peers, --max-peers-torrent, or --numwant, those explicit flags override the preset.
The web UI exposes the same setting in the Transfer panel.
# Buffer 16 MB of writes before flushing to disk
rustorrent --write-cache 16777216 ubuntu.torrentReduces disk I/O by batching writes. Useful for slow disks or when downloading many pieces simultaneously.
rustorrent --create ./my-project \
--tracker http://tracker.example.com:6969/announce \
--output my-project.torrent
# Custom piece length (default: 262144 bytes)
rustorrent --create ./my-project \
--tracker http://tracker.example.com:6969/announce \
--output my-project.torrent \
--piece-length 262144rustorrent --config rustorrent.conf ubuntu.torrentExample config:
peer_profile = conservative
download_rate = 5m
upload_rate = 1mCommand-line values override environment variables, which override the config file. Unknown config keys are rejected so misspellings do not silently change behavior.
Or set the environment variable:
export RUSTORRENT_CONFIG=~/.config/rustorrent.conf
rustorrent ubuntu.torrent
# Or set the preset directly
export RUSTORRENT_PEER_PROFILE=conservative
rustorrent ubuntu.torrent# Enable web UI on default port 8080
rustorrent --ui ubuntu.torrent
# Custom port
rustorrent --ui 9090 ubuntu.torrent
# IPv6 loopback
rustorrent --ui-addr '[::1]:8080' ubuntu.torrentOpen http://127.0.0.1:8080 in your browser. The UI lets you add/remove torrents, see progress,
manage files, and configure settings. The built-in server accepts loopback bind addresses only;
for remote access, use an authenticated SSH tunnel or HTTPS reverse proxy rather than exposing
the UI directly to a network.
The web UI also includes a qBittorrent-compatible search panel. It can install raw *.py search
plugins, run searches through the bundled Python runtime, and add results with one click. This
requires Python 3.9 or newer. Community plugins from the
qBittorrent unofficial search plugin wiki
can be installed directly from the UI. Search plugins are executable third-party code: review and
trust a plugin before installing it.
| Flag | Default | Description |
|---|---|---|
[file.torrent] |
One torrent file to add at startup | |
--magnet <link> |
Add a magnet link | |
--download-dir <dir> |
. |
Download directory |
--port <port> |
6881 |
Listen port for incoming peers |
--ui [port] |
off | Enable web UI (default port: 8080) |
--ui-addr <addr> |
127.0.0.1:8080 |
Web UI bind address |
--tui |
off | Use the interactive terminal interface |
--sequential |
off | Download pieces in order |
--preallocate |
off | Preallocate disk space |
--encryption <mode> |
prefer |
disable, prefer, or require |
--no-encryption |
Shorthand for --encryption disable |
|
--utp / --no-utp |
on | Enable or disable uTP |
--peer-profile <name> |
balanced |
Peer preset: conservative, balanced, or aggressive |
--max-peers <n> |
200 |
Global peer limit |
--max-peers-torrent <n> |
30 |
Per-torrent peer limit |
--max-active <n> |
4 |
Max concurrent active torrents |
--numwant <n> |
200 |
Peers to request from tracker |
--retry-interval <secs> |
60 |
Tracker re-announce interval |
--download-rate <rate> |
0 |
Global download limit; accepts k/m/g suffixes |
--upload-rate <rate> |
0 |
Global upload limit; accepts k/m/g suffixes |
--torrent-download-rate <rate> |
0 |
Per-torrent download limit; accepts suffixes |
--torrent-upload-rate <rate> |
0 |
Per-torrent upload limit; accepts suffixes |
--write-cache <size> |
0 |
Write cache size; accepts suffixes (0 = disabled) |
--move-completed <dir> |
Move finished downloads to this directory | |
--watch <dir> |
Watch directory for new .torrent files |
|
--blocklist <path> |
IP blocklist file | |
--proxy <url> |
Proxy peer TCP and HTTP(S) trackers; disables every unsupported direct network path | |
--geoip-db <path> |
Load a CSV IPv4-range/CIDR-to-country database | |
--seed-ratio <ratio> |
0 |
Stop seeding at this ratio (0 = disabled) |
--max-seed-time <minutes> |
0 |
Stop seeding after this duration (0 = disabled) |
--on-complete <script> |
Run a script after a torrent completes | |
--super-seed |
off | Enable super-seeding for completed torrents |
--rss <url> |
Add an RSS/Atom feed; may be repeated | |
--rss-rule <feed:pattern> |
Add an RSS matching rule; may be repeated | |
--rss-interval <seconds> |
900 |
RSS polling interval |
--throttle <name:down_kbps:up_kbps> |
Define a named throttle group | |
--ratio-group <name:ratio:action> |
Define a ratio group (stop, pause, or none) |
|
--schedule <seconds:command> |
Run a supported scheduler command periodically | |
--log <path> |
Append logs to a file | |
--daemon |
off | Fork into the background on Unix and enable the web UI |
--pid-file <path> |
Write the running process ID after startup locking | |
--create <path> |
Create a torrent from this file or directory | |
--tracker <url> |
required | HTTP(S) or UDP tracker used with --create |
--output <file> |
<source>.torrent |
Output file used with --create |
--piece-length <bytes> |
262144 |
Piece length used with --create |
--config <path> |
Config file path (env: RUSTORRENT_CONFIG) |
Scheduler commands are pause_all, resume_all, stop_ratio_reached,
throttle_down:<bps>, and throttle_up:<bps>. Completion scripts receive TORRENT_NAME,
TORRENT_DIR, TORRENT_HASH, and TORRENT_SIZE environment variables. A completion script is
claimed durably before it is launched, so it is attempted at most once and is not replayed when an
already-complete torrent is stopped or resumed.
Proxy mode is deliberately fail-closed. Peer TCP and HTTP(S) trackers use the configured SOCKS5 or HTTP proxy. Inbound peers, DHT, LPD, uTP, UDP trackers, port mapping, web seeds, RSS polling, search downloads, and magnet HTTP sources are disabled so they cannot silently bypass it. The proxy server's own hostname is resolved by the local operating system; use a literal proxy IP if even that DNS lookup must not leave the host.
The Rustorrent code is licensed under MIT. The bundled qBittorrent-compatible search
runtime retains BSD-3-Clause terms, so the distributed package is subject to both; see
Third-Party Notices. Exact Rust dependency versions and license texts
are included in Third-Party Licenses; CI regenerates that file from
Cargo.lock and rejects drift.

