Open self-hosted Stremio streaming server (libtorrent, inbound peering) + bundled web player
3.6K
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 run β¦ β that's the whole setup. No building, no config files.STREMIOSRV_LIBRARY_UI=true to try it.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:
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).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.)
It's light β direct play (most content) barely touches the CPU; the GPU only matters for transcoding.
| Resource | Minimum | Recommended | Notes |
|---|---|---|---|
| CPU | 2 cores, x86-64 | 4+ cores | amd64 only. Transcoding (clients that can't direct-play) is the only heavy load. |
| RAM | 1 GB | 2 GB+ | Engine + buffers + nginx; transcoding adds ~0.5β1 GB. |
| Disk | ~3 GB + cache | SSD, cache β₯ largest file | Image ~1.5 GB; download cache defaults to 18 GiB (tune with STREMIOSRV_CACHE_SIZE). Keep free space β₯ your biggest single file. |
| GPU | none | Intel VAAPI / NVIDIA NVENC | Optional β only speeds up transcoding; a missing/broken GPU never blocks startup. |
| Network | any | wired + 6881 forwarded | Wired beats Wi-Fi for 4K; forward port 6881 for the full swarm (see below). |
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:11470on 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 aserverVersiongate β 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 fromdocker logs stremio). A nonβdefault--webui-urlskips the localhost injection and loads the player from this box;--developmentalso skips the unused bundled server. Add the flag to your shortcut and launch from it each time. It must be the trusted:12470URL β 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
:12470URL in a browser, or install it as an app.TVs are unaffected β Samsung/LG accept the
:12470URL 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.
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.)
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:
FIREWALL_OUTBOUND_SUBNETS to your LAN CIDR(s) so the player and admin stay reachable.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. NoteGiBis binary whileGB/Gare decimal (64Gis ~4.4 GiB less than64GiB), and a lowercasebdoes not mean bits: these are bytes, and the rate limits are bytes per second.
| Setting | Default | What it does |
|---|---|---|
IPADDRESS | (unset) | Your server IP β auto trusted TV cert via *.stremio.rocks. Unset β self-signed. |
SERVER_URL | auto | URL 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_SIZE | 19327352832 (18 GiB) | Download-cache budget in bytes (LRU-evicted). Keep it above your largest file. |
STREMIOSRV_CACHE_EVICT_GRACE | 1800 | Seconds 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_DAYS | 365 | How 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_INTERVAL | 60 | Seconds 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_TIMEOUT | 300 | Seconds 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_AGE | 600 | Grace 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_BYTES | 268435456 (256 MiB) | Playhead buffer β bigger absorbs more swarm jitter (fewer rebuffers). |
STREMIOSRV_STREAM_PIECE_TIMEOUT | 30 | Seconds 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_TIMEOUT | 120 | Same, 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_PORT | 6881 | BitTorrent 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_CONNECTIONS | 400 | Max peer connections. |
STREMIOSRV_DOWNLOAD_RATE_LIMIT | 0 | Cap download throughput in bytes/sec (0 = unlimited). E.g. 12500000 β 100 Mbit/s. |
STREMIOSRV_UPLOAD_RATE_LIMIT | 0 | Cap upload throughput in bytes/sec (0 = unlimited). Handy so seeding doesn't saturate your line. |
STREMIOSRV_IDLE_DOWNLOAD_RATE_LIMIT | 1048576 (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_STREAMS | 0 | Max concurrent playbacks (distinct torrents being streamed). A new play past the cap gets 503. 0 = unlimited. |
STREMIOSRV_SEED_ON_COMPLETE | true | Keep 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_MINUTES | 0 | Stop 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_HOURS | 24 | How 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_PICKING | false | Experimental. 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_NEXT | false | Next-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_FRACTION | 0.05 | How much of the next episode to fetch, as a fraction of its size. |
STREMIOSRV_PREFETCH_NEXT_MAX_BYTES | 134217728 (128 MiB) | Ceiling on that head, so a very large episode doesn't pull 200 MB. |
STREMIOSRV_PREFETCH_TRIGGER_FRACTION | 0.90 | How far into the current episode the trigger sits. |
STREMIOSRV_LIBRARY_UI | false | Opt-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_HTTP | false | Allow 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. |
DOMAIN | localhost | CN for the self-signed cert (when not using IPADDRESS). |
CERT_FILE | certificates.pem | Bring-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β .
The stock Stremio streaming server is closed-source and, in practice:
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.
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β .
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.
Content type
Image
Digest
sha256:e96745f7eβ¦
Size
1.5 GB
Last updated
23 minutes ago
docker pull androshack/stremio-libtorrent-server