building from source - degoya/rDownloader GitHub Wiki
Most people run a release archive or the container image — see Installation. This page is for contributors and for anyone who wants to build rDownloader themselves: the prerequisites, a local run, the build for every platform, the plugin components and the checks a change is expected to pass.
One Rust binary carries the whole service:
Rust server
├── Axum REST / SSE / MCP
├── Embedded Vue web app
├── SQLite persistence and a prioritized scheduler
├── HTTP / Usenet / torrent / FTP / SFTP / WebDAV and plugin-transfer runners
├── Media / gallery / stream runners
├── LinkGrabber, subscriptions, feeds and hotfolders
├── Bandwidth, power, capacity and notification services
├── Automation and compatibility adapters
├── Post-processing pipeline
├── Wasmtime plugin host
└── Encrypted secret vault
The desktop capture agent rdownloader-capture is a second, small binary; plugins are signed
WebAssembly components built separately (see Plugin components below).
| Tool | Version | Notes |
|---|---|---|
| Rust | 1.99.0 (pinned), Edition 2024 |
rust-toolchain.toml installs Rustfmt, Clippy, llvm-tools and the targets wasm32-unknown-unknown (the plugins, without WASI) and x86_64-pc-windows-msvc automatically on the first cargo invocation. |
| Node / pnpm | 24.15.0 or later / 12 | Only needed for the web frontend. The floor is jsdom's, the web tests' environment, which declares ^24.15.0 for Node 24; web/package.json holds it (engines). web/package.json pins the pnpm version (packageManager), and corepack enable provides exactly that one. |
| C toolchain | platform-specific | See the platform sections below. |
| cargo-nextest | 0.9.146 | The test runner of scripts/check.sh and CI: cargo install cargo-nextest --version 0.9.146 --locked. |
| sqlx-cli | 0.9.0 |
cargo sqlx prepare --check, the offline query data: cargo install sqlx-cli --version 0.9.0 --locked --no-default-features --features sqlite-unbundled. |
| wasm-tools | 1.261.0 | Makes the plugin components and reads their imports; scripts/build-plugins.sh insists on exactly this one, because it decides the components' bytes: cargo install wasm-tools --version 1.261.0 --locked. |
| cargo-xwin | 0.23.1 | The Windows cross-build and scripts/check.sh --windows: cargo install cargo-xwin --version 0.23.1 --locked. |
| shellcheck | 0.11.0 | The script lint of scripts/check.sh and CI: uv tool install shellcheck-py==0.11.0.1, or the distribution's package. |
| actionlint | 1.7.12 | The workflow lint beside it: the release binary on PATH. |
Only Rust, Node and a C toolchain are needed to build and run rDownloader; the other tools are
for the plugin components, the cross-build and the checks. Each version has one source the
scripts read: Rust is channel in rust-toolchain.toml, wasm-tools WASM_TOOLS_VERSION in
scripts/lib/plugin-stamp.sh, Node engines.node in web/package.json, the others
scripts/lib/tool-versions.sh. scripts/tool-versions.sh --check holds every copy in the workflows, the actions, the SDK's CI
template and the Dockerfile to those sources, and the checks run it.
Build the web frontend before the first cargo build. The interface is embedded into the
binary at compile time from web/dist, so without it the build of rd-api fails:
pnpm --dir web install --frozen-lockfile
pnpm --dir web run buildRelease builds use --locked, so exactly the versions from Cargo.lock are used. Results land
under target/release/, or target/<TARGET>/release/ when --target is passed.
A second profile, release-test, builds much faster at the cost of slightly larger and slower
binaries. It is for test packages — scripts/package-linux.sh --profile release-test,
scripts/package-windows.sh --profile release-test, or RD_PACKAGE_PROFILE=release-test for
both — and for the packager rd-pack. A package's VERSION.txt names the profile; a release is
always built with release. Results land under target/release-test/.
pnpm --dir web install --frozen-lockfile
pnpm --dir web run build
cargo run -p rdownloader -- serve \
--database data/rdownloader.sqlite3 \
--downloads downloads \
--listen 127.0.0.1:8710The interface is then at http://localhost:8710; the first visit sets up the administrator
password (see First run). Under WSL2 on Windows 11 the same address works from the
Windows browser.
Plugin-related switches of serve:
-
--trusted-plugin-key KEY_ID=BASE64_PUBLIC_KEY(repeatable) trusts an additional release key. -
--plugin-development-modeaccepts unsigned packages. It is for local development only and relaxes nothing else. -
--plugin-allow-local-targetslets installed transfer backends dial loopback and private-network addresses — a second, separate switch, likewise for local development only.
On startup the installed signatures are verified again; see Installing and trust.
Needs a C compiler and linker, for example build-essential on Debian and Ubuntu. No further
system libraries: TLS uses rustls, and SQLite is bundled.
pnpm --dir web install --frozen-lockfile && pnpm --dir web run build
cargo build --locked --release -p rdownloader -p rd-capture
./target/release/rdownloader --versionA binary runs only on a glibc at least as new as the one of the system that built it; the official Linux release is built on Ubuntu 24.04 (glibc 2.39).
Needs the Xcode Command Line Tools (xcode-select --install). The release artefacts are built
separately for Intel (x86_64-apple-darwin) and Apple Silicon (aarch64-apple-darwin); locally
the host target is enough:
pnpm --dir web install --frozen-lockfile && pnpm --dir web run build
cargo build --locked --release -p rdownloader -p rd-captureFor the other target: rustup target add <TARGET>, then
cargo build --locked --release --target <TARGET> -p rdownloader -p rd-capture.
Needs the Visual Studio Build Tools with the Desktop development with C++ workload (MSVC
compiler, Windows SDK including rc.exe) and Rust through rustup with the
stable-x86_64-pc-windows-msvc toolchain.
pnpm --dir web install --frozen-lockfile
pnpm --dir web run build
cargo build --locked --release --target x86_64-pc-windows-msvc -p rdownloader -p rd-capture
& target/x86_64-pc-windows-msvc/release/rdownloader.exe --version
& target/x86_64-pc-windows-msvc/release/rdownloader-capture.exe --versionThe MSVC runtime is linked statically, so the executables need no Visual C++ redistributable.
Both binaries embed a long-path manifest, so the Windows SDK resource compiler rc.exe must be on
the PATH.
Needs cargo-xwin, LLVM/Clang, LLD, NASM, CMake and Ninja. cargo-xwin downloads the MSVC CRT
and the Windows SDK itself on its first run.
sudo apt-get install -y clang cmake lld llvm nasm ninja-build
cargo install cargo-xwin --version 0.23.1 --locked
rustup target add x86_64-pc-windows-msvc
pnpm --dir web install --frozen-lockfile && pnpm --dir web run build
cargo xwin build --locked --release --target x86_64-pc-windows-msvc \
-p rdownloader -p rd-capturescripts/package-windows.sh puts the executables into the (ignored) folder artifacts/windows/;
from Windows they are reachable via
\\wsl.localhost\<Distro>\home\<user>\projects\rDownloader\artifacts\windows.
docker/Dockerfile is a multi-stage build with two targets over one runtime stage in
debian:trixie-slim (glibc 2.41):
| Target | Binary | Used by |
|---|---|---|
runtime (default) |
compiled in the image: the frontend in node:24-bookworm-slim, the binary in rust:1.99.0-bookworm
|
scripts/docker.sh build only |
prebuilt |
copied from dist/docker/linux-<arch>/rdownloader in the build context |
CI, the release workflow, a docker build of your own |
Both targets take the bundled plugins from dist/plugins, which only scripts/build-plugins.sh
fills: run it before either, or the image ships no bundled plugins at all. scripts/docker.sh
warns before it builds, and the service logs no bundled plugin packages found at startup.
Beside rdownloader the runtime carries the external tools the service calls — ffmpeg, yt-dlp,
streamlink, gallery-dl, apprise, 7-Zip with its RAR codec and par2. The desktop capture agent is
not included.
scripts/build-plugins.sh # otherwise the image ships no bundled plugins
scripts/docker.sh build # the runtime target; caps cargo, names the build, works around the Docker Desktop credential helperTo use the prebuilt target yourself, put a Linux binary built on a system with glibc 2.41 or
older where it expects one. A missing binary, one for the wrong architecture or one linked against
a newer glibc fails the image build:
scripts/build-plugins.sh
mkdir -p dist/docker/linux-amd64
cp target/release/rdownloader dist/docker/linux-amd64/
docker build --file docker/Dockerfile --target prebuilt --tag rdownloader:local .
scripts/docker-smoke.sh rdownloader:localFor a multi-arch image, put the arm64 binary into dist/docker/linux-arm64/ as well:
docker buildx build --file docker/Dockerfile --target prebuilt \
--platform linux/amd64,linux/arm64 --tag rdownloader:local .Running the image is described in Docker and NAS.
The plugins are WebAssembly components without WASI: cargo build links each plugin's core
module and wasm-tools component new turns it
into the component. scripts/build-plugins.sh does both, with exactly the wasm-tools version CI
uses:
cargo install wasm-tools --version 1.261.0 --locked
scripts/build-plugins.sh --components-only ddownloadThe results are under target/wasm32-unknown-unknown/release/rd_plugin_<name>.wasm. A plugin must
import nothing outside rdownloader:plugin, above all no wasi: interface;
scripts/check-plugin-imports.sh enforces that with wasm-tools, and the build runs it on every
component.
scripts/build-plugins.sh --components-only builds every bundled component that is missing or
stale, unsigned, which is what the tests need; --development packages them unsigned into
dist/dev-plugins for a service started with --plugin-development-mode. Signed packages need the
project's release key.
Packaging, verifying and signing do not need the service: the publishing commands —
plugin package|verify|conformance|new|index — also come in the small
rd-pack binary (cargo build --profile release-test -p rd-pack), with the same arguments as
rdownloader's and without a web build. Writing a plugin of your own starts at
Developing a plugin.
scripts/check.sh runs the checks that matter for a change and only those — it prints what it
skipped and why — and scripts/check.sh --full runs everything. The individual commands:
cargo fmt --all --check
cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo nextest run --workspace
SQLX_OFFLINE=true cargo sqlx prepare --check --workspace
pnpm --dir web run typecheck # incremental; typecheck:full is the CI one, oxlint included
pnpm --dir web run lint # oxlint alone
pnpm --dir web run test
pnpm --dir web run build # does not type-check; see typecheck:full
scripts/build-extension.shThe web interface is linted with oxlint, pinned as a development dependency in
web/package.json and configured in web/.oxlintrc.json. It runs its default rule set over
web/src with --deny-warnings as the last step of typecheck:full, so scripts/check.sh and
CI fail on any finding. A rule is switched off in the configuration only with its reason; a single
justified exception is an oxlint-disable-next-line <rule> -- <reason> comment on the line before.
The browser extension is not linted.
What they need:
-
cargo sqlx prepare --checkthe SQLx CLI andcargo nextestthe Nextest CLI, each at the version in Prerequisites. The supply-chain check iscargo deny checkagainstdeny.toml. -
scripts/build-extension.sh:zipandunzip, because the two archives are the extension's release artefact. -
cargo nextest run --workspaceneeds the bundled plugin components to exist, sincecargo testnever builds for the wasm target: build them withscripts/build-plugins.sh --components-only. A contract test whose component is missing fails and names the command.scripts/build-plugins.sh --list-missingnames the missing ones. A checkout without the wasm toolchain leaves those tests out withcargo nextest run -P no-components --workspace, which counts them as skipped, not passed.
Legal test files for manual download checks are listed in
testfile/README.md.
How a pull request reaches the project is in
CONTRIBUTING.md.
A v*.*.* tag runs .github/workflows/release.yml. It builds both binaries for Linux x86-64 and
aarch64, Windows x86-64 and macOS x86-64 and aarch64, packs them with the portable launchers,
LICENSE and README.md (the macOS archives with the NZB helper app), and publishes a GitHub
release with an SPDX SBOM, SHA256SUMS signed with Sigstore and the plugin repository index
rdownloader-plugin-index.json. The signed plugin packages are a second release on the same
commit, plugins-vX.Y.Z (never marked latest), with its own signed SHA256SUMS; the index points
into it. The multi-arch container image is built
from the two Linux binaries (target prebuilt) and pushed to ghcr.io/degoya/rdownloader as
v<version> and, for the newest tag only, latest, with provenance and SBOM, signed with
cosign.
- Installation — release archives, the container, autostart
- Developing a plugin
- Troubleshooting