Turning Google Colab into a Free Seedbox
November 8, 2025
Seedboxes are great: a remote machine downloads your torrents at datacenter speeds, and you grab the finished files over HTTPS whenever you like. The problem is that a decent one costs money every month. At some point I realised I already had access to a free machine in the cloud with a fast pipe and Python pre-installed — Google Colab.
This post walks through the notebook I ended up with: a small libtorrent-powered downloader that saves straight into Google Drive.
⚠️ Only download content you have the rights to. Also note that heavy torrent traffic is not what Colab is intended for — treat this as an experiment, not a production service.
Installing libtorrent in Colab
Colab runs Ubuntu under the hood, so we can mix pip and apt:
!python -m pip install --upgrade pip setuptools wheel
!python -m pip install lbry-libtorrent
!apt install python3-libtorrent
The lbry-libtorrent wheel gives us Python bindings for libtorrent, the same
engine many desktop clients are built on.
Starting a session
A libtorrent session is the peer that talks to the swarm. We listen on the standard BitTorrent port range and keep a list of active downloads:
import libtorrent as lt
ses = lt.session()
ses.listen_on(6881, 6891)
downloads = []
Saving to Google Drive
The Colab VM's disk vanishes when the runtime disconnects, so downloads go straight into a mounted Google Drive folder instead:
from google.colab import drive
drive.mount("/content/drive")
Adding torrents
Two ways in. Either upload a .torrent file from your machine:
from google.colab import files
source = files.upload()
params = {
"save_path": "/content/drive/My Drive/Torrent",
"ti": lt.torrent_info(list(source.keys())[0]),
}
downloads.append(ses.add_torrent(params))
…or paste magnet links in a loop until you type exit:
params = {"save_path": "/content/drive/My Drive/Torrent"}
while True:
magnet_link = input("Enter Magnet Link Or Type Exit: ")
if magnet_link.lower() == "exit":
break
downloads.append(
lt.add_magnet_uri(ses, magnet_link, params)
)
Live progress bars
The fun part: notebook widgets as a download UI. One disabled slider per torrent, updated once a second with the name, speed, and state:
import time
from IPython.display import display
import ipywidgets as widgets
state_str = [
"queued",
"checking",
"downloading metadata",
"downloading",
"finished",
"seeding",
"allocating",
"checking fastresume",
]
layout = widgets.Layout(width="auto")
style = {"description_width": "initial"}
download_bars = [
widgets.FloatSlider(
step=0.01, disabled=True, layout=layout, style=style
)
for _ in downloads
]
display(*download_bars)
while downloads:
next_shift = 0
for index, download in enumerate(downloads[:]):
bar = download_bars[index + next_shift]
if not download.is_seed():
s = download.status()
bar.description = " ".join(
[
download.name(),
str(s.download_rate / 1000),
"kB/s",
state_str[s.state],
]
)
bar.value = s.progress * 100
else:
next_shift -= 1
ses.remove_torrent(download)
downloads.remove(download)
bar.close()
download_bars.remove(bar)
print(download.name(), "complete")
time.sleep(1)
When a torrent finishes seeding-state checks, it's removed from the session and the file is already sitting in Drive, ready to stream or download from any device.
The rough edges
It works, but the cracks show quickly:
- Runtime disconnects. Colab kills idle sessions; a long download needs the tab open and some luck.
- No persistence. The session dies with the runtime — there's no resume, no history, no queue that survives a refresh.
- Widget quirks.
bar.close()doesn't actually remove the slider in Colab (known issue). - One user, one notebook. There's no real UI, no auth, nothing you could hand to someone else.
Those limitations are exactly what pushed me to build a proper self-hosted version — a real web UI in Vue, a FastAPI backend, and qBittorrent doing the heavy lifting, all in Docker. That became MySeedbox, which gets its own post.