Self-hosted Stremio addon. Simply query your Jackett and stream torrents instantly via WebTorrent.
1.6K
Self-hosted Stremio addon — query your Jackett and stream torrents instantly via an embedded BitTorrent client. Static Go binary, ~20 MB Docker image, no debrid, no qBittorrent, no volumes.
docker compose up -d
http://<server-ip>:7000/configure.192.168.0.15) — the page auto-converts it to an HTTPS URL (https://192-168-0-15.local-ip.medicmobile.org:7001) so Stremio clients on other devices can reach it with a valid TLS cert.No domain, no cert management, no per-device trust setup. HTTPS uses a wildcard cert from local-ip.medicmobile.org (see HTTPS details for how it works and its tradeoffs).
Stremio app
│ GET /{config}/manifest.json
│ GET /{config}/stream/{type}/{id}.json
▼
[Go net/http + Stremio addon]
│
├─ Resolve IMDB id → titles via TMDB (24 h cache)
├─ Search Jackett in parallel across title variants
├─ Parse + sort torrents (quality > source > hdr > seeders)
└─ Return streams pointing back to /stream/{config}/{torrentId}/{fileIdx}
│ GET /stream/:config/:torrentId/:fileIdx
▼
[anacrolix/torrent singleton]
│
├─ Download .torrent via Jackett (with passkeys)
├─ Sequential priority, critical first pieces
├─ Wait for torrent metadata, then serve via http.ServeContent (Range-aware)
└─ Clean up idle torrents, respect maxConcurrentTorrents
scratch base, <50 ms startup, ~30 MB RSS.torrent URLs with passkeys; DHT / LSD / µTP disabled/<config>/configure URL5070)docker run -d --name jackstream \
-p 7000:7000 -p 7001:7001 \
--restart unless-stopped \
ghcr.io/lborruto/jackstream:latest
services:
jackstream:
image: ghcr.io/lborruto/jackstream:latest
container_name: jackstream
ports:
- "7000:7000" # HTTP (configure page + localhost Stremio)
- "7001:7001" # HTTPS (for Stremio clients on other LAN devices)
restart: unless-stopped
git clone https://github.com/lborruto/jackstream.git
cd jackstream
go build -o jackstream ./cmd/jackstream
./jackstream
Requires Go 1.24+. All deps are stdlib except github.com/anacrolix/torrent (fetched automatically on build).
http://<server-ip>:7000/configure from any device on your LAN.http://<server-ip>:9117) and its API key.192.168.0.15). The page auto-converts it to a valid HTTPS URL (see HTTPS details).Your inputs are saved to localStorage so reloading /configure re-populates the form. You can also bookmark http://<server-ip>:7000/<base64>/configure to carry the full config between browsers.
All optional. Defaults produce the same behavior as earlier versions.
| Setting | Effect |
|---|---|
| Preferred audio language | Sort boost for matching audio (FRENCH / MULTI / VOSTFR / ENG). FRENCH also boosts MULTI releases; same for ENG. Does not hide non-matching results. |
| Min / Max quality | Hard filter. Drops results above/below the chosen tier. |
| Min size (MB) | Drops "fake" low-size releases. |
| Max size (GB) | Drops oversized releases (useful for slow connections / small disks). |
| Blacklist keywords | Comma-separated list (case-insensitive, word-boundary). Drops results whose title matches any keyword — e.g. CAM, HDCAM, TELESYNC. |
All filters are stored in the base64-encoded addon URL, so different Stremio installs can use different filter profiles against the same backend.
jackstream ships a pre-baked TLS cert + key from https://local-ip.medicmobile.org — a community service that issues a public *.local-ip.medicmobile.org Let's Encrypt certificate and operates a DNS server where <dashed-ip>.local-ip.medicmobile.org resolves to <ip>. This gives you valid HTTPS for any LAN IP with zero setup.
The HTTPS listener binds on port 7001 alongside the HTTP listener on 7000. Stremio clients hit the HTTPS URL; the TCP connection still goes directly to your LAN host.
./scripts/refresh-certs.sh before building a new image to pull fresh certs.Mount a cert + key and point the addon at them:
services:
jackstream:
image: ghcr.io/lborruto/jackstream:latest
ports:
- "7000:7000"
- "7001:7001"
environment:
- HTTPS_CERT_PATH=/certs/fullchain.pem
- HTTPS_KEY_PATH=/certs/privkey.pem
volumes:
- /path/to/your/certs:/certs:ro
restart: unless-stopped
Works with Caddy-issued certs, mkcert, Let's Encrypt, or anything else.
Set HTTPS_DISABLED=1 to skip the HTTPS listener (HTTP-only). Useful if you front the addon with Caddy / Nginx / Traefik that already terminates TLS.
The cert expires every ~60 days (Let's Encrypt rotation). Before a rebuild:
./scripts/refresh-certs.sh
git commit -am "chore: refresh bundled local-ip cert"
Does it work with private trackers?
Yes — Jackett proxies the .torrent URL so announce URLs carry passkeys. DHT and LSD are disabled in the BitTorrent client to avoid leaking infohashes to the public swarm.
Why did I see "Stream session expired"? The in-memory torrent map has a 2 h TTL. Go back to the source list and click the stream again — it's instant.
Does it seed after I'm done watching?
No — V1 stops idle torrents after TORRENT_IDLE_TIMEOUT_MIN (default 30 min) and frees the disk. Seeding is on the V2 roadmap.
Why not debrid? Out of scope. The spec targets homelab-only streaming with zero third-party dependencies.
Why an embedded BitTorrent client instead of qBittorrent?
No shared volume, no second container, native HTTP Range support, and the Jackett-proxied .torrent carries the passkey so private trackers work out of the box.
Stremio desktop vs TV?
Both work. notWebReady: true tells Stremio to use the native player rather than the web player.
The Install in Stremio button did nothing / the URL lost the :7001 port.
Some Stremio clients (older Windows builds in particular) mishandle the port in stremio:// deep-link URIs. Workaround: copy the https://…:7001/<base64>/manifest.json URL shown below the button, then in Stremio click the puzzle-piece icon → paste into Add-on Repository URL.
Loading failed when I click a stream.
Most often because the container restarted (e.g. Komodo redeploy) and the in-memory torrentStore was wiped while Stremio still had a cached list of stream URLs. Close and re-open the movie in Stremio to force a fresh stream-list fetch.
| Variable | Default | Meaning |
|---|---|---|
PORT | 7000 | Port to listen on |
CACHE_TTL_MINUTES | 1440 | TMDB cache TTL |
REQUEST_TIMEOUT_MS | 8000 | Jackett/TMDB timeout |
STREAM_READY_TIMEOUT_S | 60 | Max wait for first pieces |
TORRENT_IDLE_TIMEOUT_MIN | 30 | Idle minutes before stopping a torrent |
HTTPS_PORT | 7001 | Port for the HTTPS listener |
HTTPS_CERT_PATH | ./certs/fullchain.pem | Path to TLS certificate (PEM) |
HTTPS_KEY_PATH | ./certs/key.pem | Path to TLS private key (PEM) |
HTTPS_DISABLED | (unset) | Set to 1 to disable the HTTPS listener |
bt.Cleanup() and Shutdown() now delete downloaded pieces from disk, not just from memory. Previously the container's writable layer (/tmp/jackstream) grew unboundedly until docker rm. Long-running containers now reclaim disk as torrents go idle or at shutdown.dropAndDelete() helper replaces direct torrent.Drop() calls; Shutdown() additionally wipes the DataDir to catch orphan files from fetch-fail paths.No user-facing behavior change. Existing installs continue to work; upgrade at any time.
Full rewrite from Node.js to Go with strict behavioral parity. Same URLs, same config format, same UX, but:
scratch base)utp-native segfaults — anacrolix/torrent is pure Go, µTP disabled by defaulthttp.ServeContent replaces ~245 lines of manual Range handlingNo user-facing changes. Existing addon install URLs continue to work unchanged.
local-ip.medicmobile.org certPRs welcome. Please run go test ./... and go vet ./... before opening one.
MIT — see LICENSE.
Content type
Image
Digest
sha256:7e75ff525…
Size
7.3 MB
Last updated
2 months ago
docker pull lborruto/jackstream