Sign inSign up

androshack/stremio-libtorrent-server

By androshack

β€’Updated 23 minutes ago

Open self-hosted Stremio streaming server (libtorrent, inbound peering) + bundled web player

Image
0

3.6K

androshack/stremio-libtorrent-server repository overview

⁠🎬 stremio-libtorrent-server

⁠Your own Stremio streaming server β€” open, fast, and yours. One command to run it. πŸš€

Self-host the complete Stremio experience β€” the web player and a powerful, open BitTorrent streaming engine β€” in a single container on your own hardware. It's a full torrent client, not just a streamer: it downloads whole files and can pin favorites to keep & seed. Point any Stremio client (browser, Android TV, Tizen, webOS, desktop) at it and press play.

No subscription. No tracking. No black box. 100% free and open β€” our gift to the community. πŸ’›

Sharing back with the community. πŸ’› This is a real torrent client, so a title you started keeps downloading to completion and seeding (uploading) back to other Stremio users even after you close the player β€” that's how you help keep the swarm fast and healthy for everyone. Unpinned titles are cleared automatically; pin the ones you'd like to keep sharing. Prefer to limit it? Cap up/down bandwidth in the settings any time β€” your box, your call.

Docker Hub License: MIT


⁠✨ Why you'll love it

  • πŸš€ Install in one command. docker run … β€” that's the whole setup. No building, no config files.
  • πŸ“Ί Just works on TVs. Automatic trusted HTTPS (a real Let's Encrypt cert) that smart TVs actually accept β€” zero certificate headaches.
  • ⚑ Faster, more reliable. Unlike the closed stock server, this one accepts inbound peers and fetches playhead-first, so streams start quicker and hold up on thin swarms.
  • πŸŽ›οΈ Truly yours to control. Real dials for cache, buffering, peers, and transcode β€” tune deeply, or never touch a thing.
  • πŸ–₯️ Hardware transcode, optional. Intel VAAPI / NVIDIA NVENC when you expose a GPU to the container (opt-in β€” see Advanced⁠), with graceful CPU fallback β€” and a missing GPU never stops it from starting.
  • 🧩 Your addons, your choice. It's neutral infrastructure: it streams whatever a Stremio addon hands it. It bundles no content and is not a source.
  • πŸ“š A real torrent client, if you want one. Turn on the optional library page and the server stops being a passthrough: queue a download before you sit down, see which episodes of a pack are actually on the disk, and keep the ones you want protected from the cache evictor β€” and it seeds what it keeps, like any decent client should. It also publishes itself as a Stremio addon, so what is on the box shows up as a row on your board and as a "play the local copy" entry beside every other source β€” on your LAN only, and off unless you turn the library on β€” see Watch your library inside Stremio⁠ for the four steps. Off by default; set STREMIOSRV_LIBRARY_UI=true to try it.
  • πŸ”“ Open source. Read it, change it, trust it.

β πŸš€ Quick Start β€” anyone can do this

Architecture: the published image is linux/amd64 (x86-64) only. It runs on any normal PC/server/NAS. ARM hosts (Raspberry Pi, most ARM TV boxes, Apple Silicon) aren't supported by the prebuilt image β€” build from source on those.

1. Install Docker⁠. 2. Copy one command below β€” whichever matches your hardware β€” and replace YOUR_SERVER_IP with your machine's LAN IP (e.g. 192.168.1.50). Not sure which? Use the first one β€” it works on everything. (The GPU options only speed up the occasional video that needs converting; they're not required.)

πŸ’» No GPU β€” works everywhere (start here)

docker run -d --name stremio --restart unless-stopped \
  -e IPADDRESS=YOUR_SERVER_IP \
  -p 8080:8080 -p 12470:12470 -p 6881:6881/tcp -p 6881:6881/udp \
  -v stremio-data:/root/.stremio-server \
  androshack/stremio-libtorrent-server

🟦 Intel / AMD GPU (VAAPI) β€” same, plus --device /dev/dri

docker run -d --name stremio --restart unless-stopped \
  -e IPADDRESS=YOUR_SERVER_IP \
  --device /dev/dri:/dev/dri \
  -p 8080:8080 -p 12470:12470 -p 6881:6881/tcp -p 6881:6881/udp \
  -v stremio-data:/root/.stremio-server \
  androshack/stremio-libtorrent-server

🟩 NVIDIA GPU (NVENC) β€” plus --gpus all (first install the NVIDIA Container Toolkit⁠ on the host)

docker run -d --name stremio --restart unless-stopped \
  -e IPADDRESS=YOUR_SERVER_IP \
  --gpus all \
  -p 8080:8080 -p 12470:12470 -p 6881:6881/tcp -p 6881:6881/udp \
  -v stremio-data:/root/.stremio-server \
  androshack/stremio-libtorrent-server

🟦🟩 Both Intel + NVIDIA β€” both flags

docker run -d --name stremio --restart unless-stopped \
  -e IPADDRESS=YOUR_SERVER_IP \
  --gpus all --device /dev/dri:/dev/dri \
  -p 8080:8080 -p 12470:12470 -p 6881:6881/tcp -p 6881:6881/udp \
  -v stremio-data:/root/.stremio-server \
  androshack/stremio-libtorrent-server

3. Open it:

  • 🌐 In a browser (same network): http://YOUR_SERVER_IP:8080 β€” browser playback covers MP4/H.264; for MKV/HEVC content use the desktop or TV apps (browsers can't decode those).
  • πŸ”’ Trusted HTTPS (and TVs): run docker logs stremio and use the printed URL β€” it looks like https://192-168-1-50.519b6502d940.stremio.rocks:12470 (replace 192-168-1-50 with your internal IP, dots written as dashes).

Sign into Stremio, add your addons, press play. 🍿 (Prefer a file? Grab compose.hub.yaml⁠ β†’ IPADDRESS=YOUR_SERVER_IP docker compose -f compose.hub.yaml up -d.)


⁠🧰 Minimum hardware

It's light β€” direct play (most content) barely touches the CPU; the GPU only matters for transcoding.

ResourceMinimumRecommendedNotes
CPU2 cores, x86-644+ coresamd64 only. Transcoding (clients that can't direct-play) is the only heavy load.
RAM1 GB2 GB+Engine + buffers + nginx; transcoding adds ~0.5–1 GB.
Disk~3 GB + cacheSSD, cache β‰₯ largest fileImage ~1.5 GB; download cache defaults to 18 GiB (tune with STREMIOSRV_CACHE_SIZE). Keep free space β‰₯ your biggest single file.
GPUnoneIntel VAAPI / NVIDIA NVENCOptional β€” only speeds up transcoding; a missing/broken GPU never blocks startup.
Networkanywired + 6881 forwardedWired beats Wi-Fi for 4K; forward port 6881 for the full swarm (see below).

β πŸ“Ί On your TV

Smart TVs insist on a trusted HTTPS connection β€” a self-signed cert won't do. Set IPADDRESS and this server fetches a real Let's Encrypt certificate for you automatically (via Stremio's *.stremio.rocks magic DNS, which maps that long URL back to your server's IP β€” even on your LAN). In the TV's Stremio app, set the Streaming Server URL to the …stremio.rocks:12470 address shown by docker logs stremio.

Note β€” the Stremio desktop app (v6). The desktop shell launches its own bundled streaming server and re‑points itself at 127.0.0.1:11470 on every start β€” it injects a ?streamingServerUrl= parameter that overwrites the saved URL β€” so simply setting the Streaming Server URL doesn't stick. (This is the shell's behaviour, not a serverVersion gate β€” that part is already correct.) Two ways to use this box from the desktop:

  • Best β€” launch with a flag (native player, full MKV/HEVC): start Stremio with --development --webui-url=<your …stremio.rocks:12470 URL> (the trusted URL from docker logs stremio). A non‑default --webui-url skips the localhost injection and loads the player from this box; --development also skips the unused bundled server. Add the flag to your shortcut and launch from it each time. It must be the trusted :12470 URL β€” a self‑signed cert is refused. After signing into your account, relaunch via the shortcut (login resets the URL).
  • Zero‑install (MP4/H.264 only): open the :12470 URL in a browser, or install it as an app.

TVs are unaffected β€” Samsung/LG accept the :12470 URL directly and it sticks.

Styled subtitles on the TV. A Stremio TV app built on stremio-video 0.0.97 or later can draw a file's own ASS/SSA subtitles with their styling and fonts, instead of as plain text. Turn on the player's ASS subtitles styling setting: each styled track then shows as a second entry, marked (styled), next to the TV's plain one. The server reads only the stretch being watched, a minute at a time, and the TV's own playback keeps priority over it. Older TV apps keep their plain subtitles.


⁠🌍 Want the full swarm? Forward one port.

A lot of BitTorrent's speed comes from peers reaching you β€” and home routers block that by default. For maximum peers and throughput, forward port 6881 (TCP and UDP) on your router to your server. It works fine without forwarding β€” you'll just reach fewer peers on sparse torrents. (Unlike the stock server, this one actually listens for inbound peers, so the forward genuinely pays off.)


β πŸ” Run behind a VPN

Tunnel only the streaming server's BitTorrent traffic through a VPN (kill-switch + optional port-forwarding) using gluetun⁠, while your LAN keeps reaching the player/admin directly:

WIREGUARD_PRIVATE_KEY=... WIREGUARD_ADDRESSES=10.2.0.2/32 IPADDRESS=<your-LAN-IP> \
  docker compose -f compose.vpn.yaml up -d

Notes:

  • The VPN's kill-switch is on by default β€” if the tunnel drops, torrent traffic stops (no IP leak).
  • Inbound peers / seeding need a provider that supports port-forwarding (e.g. ProtonVPN, PIA, AirVPN). Without it you still stream, but with outbound-only connectivity.
  • Set FIREWALL_OUTBOUND_SUBNETS to your LAN CIDR(s) so the player and admin stay reachable.

β πŸ”§ Advanced β€” tune it your way

Everything is a plain -e NAME=value environment variable:

Sizes and rates accept units. 64GiB, 512MiB, 1.5GiB, 2MiB β€” or a plain byte count, which is what these have always taken and still do. Note GiB is binary while GB/G are decimal (64G is ~4.4 GiB less than 64GiB), and a lowercase b does not mean bits: these are bytes, and the rate limits are bytes per second.

SettingDefaultWhat it does
IPADDRESS(unset)Your server IP β†’ auto trusted TV cert via *.stremio.rocks. Unset β†’ self-signed.
SERVER_URLautoURL the web player targets. Set for a custom domain. /proxy also counts a web page on this host, at any port, as the server's own.
STREMIOSRV_CACHE_SIZE19327352832 (18 GiB)Download-cache budget in bytes (LRU-evicted). Keep it above your largest file.
STREMIOSRV_CACHE_EVICT_GRACE1800Seconds a torrent stays safe from eviction after it was last served. Raise it if a player buffers long enough between range requests that the title being watched ages out.
STREMIOSRV_RESUME_RETENTION_DAYS365How long a fast-resume record is kept for a title that has left the cache. The record carries the torrent's metadata, so re-playing an evicted title starts without fetching it from the swarm again β€” this only bounds the directory. A title still cached, kept, or downloading is exempt at any age. 0 keeps everything.
STREMIOSRV_TRANSCODE_GC_INTERVAL60Seconds between transcode housekeeping passes: end encoders nobody is reading, then sweep the directories they leave behind. transcode/ is exempt from cache eviction, so this is the only thing that reclaims it.
STREMIOSRV_TRANSCODE_IDLE_TIMEOUT300Seconds a transcode may go unread before its ffmpeg is ended. A player that crashes, refuses the stream, or loses its connection never calls /destroy, and the encoder left behind holds a GPU as firmly as a wanted one. Raise it if you pause for long stretches β€” resuming after a reap re-transcodes from the start; 0 disables the reaper.
STREMIOSRV_TRANSCODE_GC_MAX_AGE600Grace before an unclaimed transcode directory is deleted. A job with a live ffmpeg is kept no matter how old. Raise it only if you pause transcoded playback for long stretches.
STREMIOSRV_READAHEAD_BYTES268435456 (256 MiB)Playhead buffer β€” bigger absorbs more swarm jitter (fewer rebuffers).
STREMIOSRV_STREAM_PIECE_TIMEOUT30Seconds a request waits for one piece mid-stream before ending the stream (the player then re-requests). Raise it on a slow or thinly-peered swarm where the piece does arrive, just late β€” but it cuts both ways: when the piece is never coming, this is how long playback freezes before the retry that would have recovered it.
STREMIOSRV_STREAM_FIRST_PIECE_TIMEOUT120Same, for the first piece of a request β€” a cold start: the beginning of playback, or a seek into a region nothing has downloaded yet.
STREMIOSRV_BT_LISTEN_PORT6881BitTorrent peer port (TCP and UDP, IPv4 and IPv6). The one to forward. If you change it, publish the same port β€” the compose files and docker/launch.sh follow this var automatically; a hand-rolled docker run must use matching -p <port>:<port>/tcp -p <port>:<port>/udp (mapping to a different container port silently kills inbound peering).
STREMIOSRV_BT_MAX_CONNECTIONS400Max peer connections.
STREMIOSRV_DOWNLOAD_RATE_LIMIT0Cap download throughput in bytes/sec (0 = unlimited). E.g. 12500000 β‰ˆ 100 Mbit/s.
STREMIOSRV_UPLOAD_RATE_LIMIT0Cap upload throughput in bytes/sec (0 = unlimited). Handy so seeding doesn't saturate your line.
STREMIOSRV_IDLE_DOWNLOAD_RATE_LIMIT1048576 (1 MiB/s)Cross-torrent playback priority. While anything is being streamed, every other (idle) torrent is capped to this many bytes/sec so the torrent you're watching wins the bandwidth. 0 disables it (idle torrents compete freely).
STREMIOSRV_MAX_STREAMS0Max concurrent playbacks (distinct torrents being streamed). A new play past the cap gets 503. 0 = unlimited.
STREMIOSRV_SEED_ON_COMPLETEtrueKeep seeding after a torrent finishes (full torrent-client behaviour). false = stop seeding + drop peers the moment it completes. Pinned items always keep seeding.
STREMIOSRV_MAX_SEED_MINUTES0Stop seeding this many minutes after completion (0 = seed forever). Applies on top of SEED_ON_COMPLETE.
STREMIOSRV_EXTRA_TRACKERS(empty)Extra trackers appended to every torrent (on top of the built-in defaults). Comma/space/newline-separated udp:///http(s):///ws(s):// URLs.
STREMIOSRV_TRACKER_LIST_URL(empty)Optional URL of a community tracker list (e.g. the raw ngosang/trackerslist⁠ trackers_best.txt). Fetched in a background thread to keep the list current β€” best-effort, never blocks startup or playback; offline falls back to the last cached list, then the built-in defaults. Empty = fully static.
STREMIOSRV_TRACKER_LIST_REFRESH_HOURS24How often the background tracker-list source re-fetches (only when a URL is set).
STREMIOSRV_DHT_BOOTSTRAP_NODES(empty)Your own DHT entry points, host:port,host:port. Empty keeps libtorrent's built-in routers. Only used on a first boot β€” after that the server rejoins via its saved routing table (see below).
STREMIOSRV_ADAPTIVE_PICKINGfalseExperimental. While playing, relax strict sequential download to parallel once enough is buffered ahead of the playhead (harvests more swarm throughput), re-tightening to in-order when the buffer drains or on a seek β€” the playhead window stays deadline-rushed, so continuity is protected. Off by default; needs on-box tuning.
STREMIOSRV_PREFETCH_NEXTfalseNext-episode prefetch (opt-in). Once you are into the last 10% of an episode and that episode is fully downloaded, quietly pull the start of the next episode in the same torrent so pressing Next starts instantly. Only applies to multi-episode packs β€” see below.
STREMIOSRV_PREFETCH_NEXT_FRACTION0.05How much of the next episode to fetch, as a fraction of its size.
STREMIOSRV_PREFETCH_NEXT_MAX_BYTES134217728 (128 MiB)Ceiling on that head, so a very large episode doesn't pull 200 MB.
STREMIOSRV_PREFETCH_TRIGGER_FRACTION0.90How far into the current episode the trigger sits.
STREMIOSRV_LIBRARY_UIfalseOpt-in download manager at /library on the same origin as the web player: browse your Stremio library, download a title in full, and manage what is on disk as titles rather than folder names. Off by default β€” it is an authenticated page, so enabling it is a deliberate choice. See docs/library-ui.md⁠.
STREMIOSRV_LIBRARY_ADDON_ALLOW(unset)Which client addresses count as your own network. They may reach the library addon, and /proxy (which plays addon streams that need their own request headers) fetches any address for them but a link-local or cloud-metadata one, while other clients β€” and web pages on other sites β€” may fetch public addresses only. A web page counts as the server's own, not another site, when it was opened on an IP address in these ranges, or on the server's own host or SERVER_URL's. Unset means loopback, private ranges, link-local, IPv6 ULA and carrier-grade NAT (so a private tunnel still works). Comma-separated CIDRs to replace that list. Clients can look local when they are not: behind a reverse proxy every client arrives from the proxy's address, and on a host with IPv6 whose container network has none, Docker forwards IPv6 clients from its bridge gateway. In either case list your own LAN ranges here explicitly.
STREMIOSRV_LIBRARY_OWNER(unset)Which Stremio account may use it β€” the account id or its email. Unset = the first account to sign in claims the server.
STREMIOSRV_LIBRARY_ALLOW_HTTPfalseAllow the library UI without TLS. Its session cookie is Secure, so plain HTTP is refused unless you set this β€” only do so on a trusted LAN or behind a VPN.
DOMAINlocalhostCN for the self-signed cert (when not using IPADDRESS).
CERT_FILEcertificates.pemBring-your-own cert (full-chain + key) filename in the data volume.

Trackers & peer discovery. Every torrent is announced to a curated set of public trackers (baked-in defaults) plus DHT, LSD and PEX β€” so a bare infohash finds peers even when the magnet carries no tracker, exactly like the stock Stremio server. Extend it two ways: add your own with STREMIOSRV_EXTRA_TRACKERS, or point STREMIOSRV_TRACKER_LIST_URL at a maintained list (e.g. ngosang/trackerslist⁠) to keep the set current β€” that fetch runs in a background thread and never blocks startup or playback (offline β†’ last cached list β†’ the built-in defaults). The bigger peering win, though, is inbound connectivity: forward STREMIOSRV_BT_LISTEN_PORT (6881) so you reach the whole swarm, not just what trackers hand back.

Your node remembers the network. Joining the DHT needs an entry point, and with nothing saved that means a handful of bootstrap routers run by other people β€” every reboot, forever. So the server writes its DHT routing table to <cache>/dht.state (every 30s, and on shutdown) and restores it on start. A machine that has been online even once rejoins through hundreds of peers it already knows, with nobody else's server in the path. That matters most for a box that sits powered off for months and then gets plugged back in. A corrupt or missing file is not an error β€” it just falls back to a normal cold start. Set STREMIOSRV_DHT_BOOTSTRAP_NODES if you would rather not use the built-in routers for that first boot either.

Next-episode prefetch (opt-in, off by default) pulls the head of the next episode in a pack so Next starts instantly β€” see the full description on GitHub⁠.

⁠🧠 Why it exists

The stock Stremio streaming server is closed-source and, in practice:

  • outbound-only β€” it never listens for inbound peers, so you only reach the connectable half of a swarm;
  • it hides the torrent levers β€” no real control over piece picking, connectivity, or cache.

This opens it up: inbound connectivity + playhead-first piece picking for faster starts and better reliability on sparse swarms, plus hardware transcode for clients that can't direct-play β€” all in an image you run yourself. It is content-neutral infrastructure: it streams whatever infohash a Stremio addon hands it, and bundles or surfaces nothing.

β πŸ—οΈ Under the hood

One image, two source repos. The runtime image is built FROM a GPU/ffmpeg base (the companion fork) and layers the open server on top:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ stremio-docker-dual  (companion fork, MIT) ──────────────┐
β”‚ jellyfin-ffmpeg (NVENC/VAAPI) Β· nginx Β· bundled Stremio web player        β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–²β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                 β”‚ FROM
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ stremio-libtorrent-server  (this repo) ──────────────────┐
β”‚ FastAPI + libtorrent engine Β· nginx serves web player + proxies the API   β”‚
β”‚ β†’ one container: web player + open engine on a single origin              β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Companion fork: andrewhack/stremio-docker⁠ (builds the stremio-docker-dual image; see its NVIDIA-GPU.md⁠ for GPU/Proxmox setup).

Modules: api/ (Stremio HTTP API) Β· torrent/ (libtorrent + piece-picker) Β· stream/ (Range file server) Β· transcode/ (ffmpeg NVENC/VAAPI β†’ HLS) Β· config.py Β· health.py. Protocol reference: docs/protocol-map.md⁠.

How the TV HTTPS URL works (*.stremio.rocks), and the shared third-party hostname it relies on, are explained in the README on GitHub⁠.

β πŸ“œ License & spirit

MIT β€” built on the MIT-licensed stremio-docker⁠ fork.

This is not a commercial product, and we don't monetize it. It's our contribution to the people who just want their own open, private streaming server. Use it, share it, make it better. πŸ’›

Keep it legal: this is neutral infrastructure for content you have the right to stream.

Tag summary

Content type

Image

Digest

sha256:e96745f7e…

Size

1.5 GB

Last updated

23 minutes ago

docker pull androshack/stremio-libtorrent-server