Домашний Netflix за вечер: Transmission + Jellyfin + Telegram-бот на Docker с поддержкой NAS

At home, I have a Keenetic router equipped with a 2TB USB drive. For quite some time, it functioned merely as a network storage solution—files were stored, and Transmission was running smoothly. However, the default Transmission interface felt like a throwback to 2009, making it cumbersome to manage from my phone, and watching downloaded content on the television was a quest in itself. One evening, I decided to address these issues. The outcome was the deployment of three Docker containers, all initiated with a single command, transforming the experience into something much more user-friendly:

  • Open Telegram and send the bot a .torrent file.
  • The bot confirms: “✅ Added!”
  • After a while, it notifies: “✅ Downloaded! 📁 Movie Title · 💾 15 GB”
  • I open Jellyfin on the TV— the movie is already there, complete with a poster and a description in Russian.

Let me explain how this setup works.

What You Will Achieve

  • Transmission + Flood UI — a torrent client with a modern interface replacing the default one.
  • Jellyfin — a media server featuring posters, descriptions, and subtitles, accessible on the TV, phone, or browser.
  • Telegram Bot — add torrents and receive notifications directly in the messenger.
  • Watch Folder — simply drop a .torrent file into a folder on the NAS, and it downloads automatically.
  • All data is stored on a NAS network drive (SMB/CIFS), ensuring persistence through OS reinstalls.

Stack and Architecture


┌───────────────────────────────────────────────┐
│               Docker on Windows               │
│                                               │
│  ┌───────────────────────────────────────────┐│
│  │           Transmission + Flood UI         ││
│  │          :9091                            ││
│  └───────────────────────────────────────────┘│
│  ┌───────────────────────────────────────────┐│
│  │               Jellyfin                    ││
│  │               :8096                       ││
│  └───────────────────────────────────────────┘│
└───────────────────────────────────────────────┘

The key idea is that a CIFS-type Docker volume mounts the network share directly into the containers. Both containers (Transmission and Jellyfin) work with the same files on the NAS: the first writes, while the second reads.

Requirements

  • Docker Desktop (Windows/macOS) or Docker Engine (Linux)
  • A NAS or router with a USB drive and SMB share (Keenetic, Synology, QNAP, etc.)
  • A Telegram account for the bot

If you don’t have a NAS, a FAQ section at the end provides alternatives for using a local folder.

Step 1: Clone the Repository

git clone https://github.com/vervs3/mediabox.git
cd mediabox

Project structure:

mediabox/
├── docker-compose.yml
├── .env.example
├── bot/
│   ├── bot.py
│   ├── Dockerfile
│   └── requirements.txt
└── transmission/
    ├── setup-flood.sh
    └── custom-cont-init.d/
        └── 01-fix-settings.sh

Step 2: Configure the Settings

cp .env.example .env

Edit the .env file:

# Timezone
TZ=Europe/Moscow

# Network disk settings (NAS, Keenetic router, etc.)
SMB_HOST=//192.168.1.45/Transmission
SMB_USER=admin
SMB_PASSWORD=your_password

# Telegram bot (create one with @BotFather)
BOT_TOKEN=123456789:AAxxxxx...

# Your Telegram ID (find it with @userinfobot)
ALLOWED_USER_ID=123456789

Step 3: Install Flood UI

Here’s where I encountered my first hurdle. I expected the linuxserver/transmission image to include Flood out of the box, as it used to. However, recent versions have removed third-party UIs, and upon starting the container, it displays:

Changes Required!
This image no longer bundles 3rd party Transmission UI packages.
We would advise you to use subfolders under /config to store your UI packages

Thus, I manually downloaded Flood:

# Linux / macOS
bash transmission/setup-flood.sh

The script fetches the latest release of flood-for-transmission and unpacks it into transmission/config/flood-ui/. For Windows users, download the archive manually from GitHub releases and extract it into the same folder.

Step 4: Launch the Containers

docker compose up -d

On the first run, Docker will download the images (approximately 700 MB in total) and start all three services. To verify:

docker compose ps
NAME               STATUS
transmission       Up
jellyfin           Up
transmission-bot   Up

How It Works Internally — Three Noteworthy Points

1. Docker Volume with CIFS Instead of Bind Mount

The first approach I tried was to pass the network drive Z: as a standard volume:

git clone https://github.com/vervs3/mediabox.git
cd mediabox

0

This did not work. Docker Desktop on Windows operates on top of WSL2, and mounted network drives (Z:, servershare) are inaccessible from within the container. WSL2 simply does not recognize them. The solution is to use a Docker volume with the CIFS driver. Docker mounts the share directly, bypassing Windows:

git clone https://github.com/vervs3/mediabox.git
cd mediabox

0

Both containers—Transmission and Jellyfin—connect to this volume and operate on the same files. Transmission writes to /downloads/Downloads, while Jellyfin reads from /media/Downloads (both refer to the same volume but under different names within the containers).

2. Patching Transmission Settings on Each Start

The second surprise was that the linuxserver/transmission image resets part of the settings to default values every time it starts. Attempting to set watch-dir through environment variables does not work. Editing settings.json results in it being reset upon the next start. The custom-cont-init.d mechanism helps here: scripts in this folder execute after the image initialization but before transmission-daemon starts. We place our patch there:

git clone https://github.com/vervs3/mediabox.git
cd mediabox

0

The logs confirm that the script executed successfully:

git clone https://github.com/vervs3/mediabox.git
cd mediabox

0

3. Git Bash Breaks Paths in Environment Variables

The third pitfall is specific to Windows + Git Bash. When passing a path like /flood-for-transmission/ through -e in docker run, Git Bash converts it to C:/Program Files/Git/flood-for-transmission/. In the logs, this appears as:

git clone https://github.com/vervs3/mediabox.git
cd mediabox

0

This can be resolved by setting an environment variable before the command:

git clone https://github.com/vervs3/mediabox.git
cd mediabox

0

In docker-compose.yml, this issue does not arise since paths do not pass through the Git Bash interpreter.

Telegram Bot

The bot operates within a container using network_mode: "service:transmission", sharing the network stack with Transmission and connecting to it via localhost:9091. This eliminates the need to open additional ports and reduces network latency between containers.

Commands

Command Function
/list Displays a list of all torrents with progress bars and control buttons.
/active Shows only active downloads.
/stats Displays speed and overall statistics.
/help Provides help information.

Adding Torrents

There are three methods to add torrents:

  1. Send a .torrent file directly to the bot in chat.
  2. Send a magnet: link as text.
  3. Drop a .torrent file into the watch folder on the NAS—Transmission will pick it up automatically.

Unicode Progress Bar

A small yet delightful feature is that the progress is displayed directly in the message text:

git clone https://github.com/vervs3/mediabox.git
cd mediabox

0

Completion Notifications Without Duplicates

To prevent the bot from spamming completed torrents upon restart, we initialize a list of already downloaded IDs at startup:

git clone https://github.com/vervs3/mediabox.git
cd mediabox

0

When a torrent finishes downloading, the bot sends:

git clone https://github.com/vervs3/mediabox.git
cd mediabox

0

Jellyfin — First Launch

  1. Open http://localhost:8096
  2. Complete the setup wizard (language, create a user).
  3. Add a media library → type “Movies” → path /media/Downloads
  4. Jellyfin will automatically find the files and download posters and descriptions from TMDB.

Connecting from TV or Phone

Install the Jellyfin app (available on Android TV, Apple TV, Roku, Fire TV, iOS, Android) and enter:

git clone https://github.com/vervs3/mediabox.git
cd mediabox

0

Where 192.168.x.x is the local IP of your computer (use ipconfig on Windows, ip a on Linux).

FAQ

Q: Does it work without a NAS, just on a local folder?

Yes. Replace the volume in docker-compose.yml:

mediabox/
├── docker-compose.yml
├── .env.example
├── bot/
│   ├── bot.py
│   ├── Dockerfile
│   └── requirements.txt
└── transmission/
    ├── setup-flood.sh
    └── custom-cont-init.d/
        └── 01-fix-settings.sh

Q: How to add a VPN so that the provider cannot see the torrents?

Add the gluetun service and switch Transmission to its network:

mediabox/
├── docker-compose.yml
├── .env.example
├── bot/
│   ├── bot.py
│   ├── Dockerfile
│   └── requirements.txt
└── transmission/
    ├── setup-flood.sh
    └── custom-cont-init.d/
        └── 01-fix-settings.sh

Q: How to update to new versions of the images?

mediabox/
├── docker-compose.yml
├── .env.example
├── bot/
│   ├── bot.py
│   ├── Dockerfile
│   └── requirements.txt
└── transmission/
    ├── setup-flood.sh
    └── custom-cont-init.d/
        └── 01-fix-settings.sh

Q: Can I access it externally, not just within the local network?

Yes, the easiest way is through Tailscale or Cloudflare Tunnel—without port forwarding on the router.

The stack is compact—three containers, one docker-compose.yml, and one .env file with passwords. It can be set up from scratch in five minutes, with files residing on the NAS, ensuring they remain intact during OS reinstalls.

If you have a router with a USB drive at home and are still watching movies through a file explorer, give this setup a try. The difference is palpable.

Repository: https://github.com/vervs3/mediabox. I would appreciate a star ⭐ and welcome any questions in the comments—especially if you encounter other hurdles with your hardware.

TrendTechie
Домашний Netflix за вечер: Transmission + Jellyfin + Telegram-бот на Docker с поддержкой NAS