MySeedbox: From a Colab Hack to a Real Self-Hosted Seedbox
July 5, 2026
Last year I turned Google Colab into a free seedbox. It was a fun hack, but it had all the problems you'd expect from running a download server inside a notebook: the runtime died whenever it felt like it, nothing survived a refresh, and the "UI" was a stack of disabled sliders.
So I rebuilt it properly. MySeedbox is a self-hosted seedbox: paste a magnet link into a clean web interface, watch it download in real time, grab the finished files. It runs on any machine that has Docker.
The architecture
Three containers, each doing one job:
- qBittorrent — the torrent engine. Instead of driving libtorrent by hand like the Colab version did, I let a battle-tested client handle peers, resume data, and queueing, and talk to it through its Web API.
- FastAPI — a thin backend that wraps the qBittorrent API with the endpoints the frontend actually needs: add a magnet, list downloads with progress, remove a torrent, serve finished files.
- Vue — the frontend. A single page with an input for magnet links and a live-updating list of downloads — the ipywidgets sliders from the notebook, reborn as actual UI components.
The whole stack starts with one command:
docker compose up -d
What the notebook version taught me
Almost every design decision in MySeedbox is a direct answer to a Colab pain point:
| Colab hack | MySeedbox |
|---|---|
| Runtime disconnects kill downloads | qBittorrent runs as a daemon and resumes on restart |
| No persistence between sessions | State lives in qBittorrent + a mounted volume |
| Polling loop redraws widget sliders | The frontend polls a proper progress endpoint |
| Files land in Google Drive | Files land on your own disk, served over HTTP |
| One notebook, one user | A URL anyone on your network can open |
Driving qBittorrent from FastAPI
qBittorrent's Web API does the heavy lifting; the backend just translates.
Adding a magnet is a single authenticated call, and the progress endpoint
maps torrents/info into exactly the JSON shape the Vue app wants — name,
progress percentage, download rate, and state. No libtorrent bindings, no
state machine of my own, no state_str lookup table.
Why not just expose qBittorrent's own UI?
Fair question — qBittorrent ships with a web UI. Two reasons:
- Scope control. The built-in UI exposes every knob a power user could want. I wanted the opposite: one input, one list, zero configuration for whoever I share the URL with.
- The fun of it. The point of self-hosting projects like this is learning the full path — API design, Docker networking, a reactive frontend — on a problem small enough to actually finish.
Where it's heading
The code is on GitHub. Next on the list: auth for exposing it beyond the home network, and streaming finished video straight from the seedbox instead of downloading first.
If you ever built the notebook version — this is what it wanted to be when it grew up.