BitTorrent Server

Posted on 28 May 2026

Running Transmission as a server daemon rather than a desktop application changes how BitTorrent works in practice. Downloads happen on the server regardless of whether the desktop is on. Seeding continues indefinitely. Completed files are immediately available on the NAS to every device on the network. The web interface and transmission-remote allow managing downloads from any device without installing a client.

The source material covers Transmission on Ubuntu 14.04 with Upstart init scripts and a separate FlexGet daemon for automated downloads. This page updates the configuration for Ubuntu 24.04 and systemd, with FlexGet as an optional addition.

Container setup

Clone the base template:

pct clone 100 145 --hostname bittorrent --full
pct start 145

Inside the container:

hostnamectl set-hostname bittorrent.yourdomain.net
sed -i 's/base-template/bittorrent/g' /etc/hosts

Installation

Transmission is in the Ubuntu repositories:

sudo apt install transmission-daemon

This creates:

  • A debian-transmission user and group
  • /var/lib/transmission-daemon/ for state data and configuration
  • /etc/transmission-daemon/settings.json as the configuration file
  • A systemd service transmission-daemon which starts automatically

Stop the daemon before configuring it. Transmission overwrites settings.json with its in-memory state when it shuts down, so any changes made while it is running are lost:

sudo systemctl stop transmission-daemon

Download directories

Create the download directories on NFS-mounted NAS storage:

sudo mkdir -p /var/lib/transmission-daemon/downloads/complete
sudo mkdir -p /var/lib/transmission-daemon/downloads/incomplete
sudo chown -R debian-transmission:debian-transmission \
    /var/lib/transmission-daemon/downloads

If storing downloads on the NAS rather than locally, mount the NAS share first (covered in the NAS section) and create the directories on the mount point:

nas.yourdomain.net:/volume1/downloads  /var/lib/transmission-daemon/downloads  nfs  defaults,_netdev,nofail  0  0

Configuration

Edit /etc/transmission-daemon/settings.json. The daemon must be stopped first:

{
    "alt-speed-down": 500,
    "alt-speed-enabled": false,
    "alt-speed-time-begin": 540,
    "alt-speed-time-day": 127,
    "alt-speed-time-enabled": false,
    "alt-speed-time-end": 1020,
    "alt-speed-up": 500,
    "bind-address-ipv4": "0.0.0.0",
    "bind-address-ipv6": "::",
    "blocklist-enabled": true,
    "blocklist-url": "https://github.com/nicehash/NiceHashQuickMiner/raw/master/nicehash_badpeers.txt",
    "cache-size-mb": 256,
    "dht-enabled": true,
    "download-dir": "/var/lib/transmission-daemon/downloads/complete",
    "download-queue-enabled": true,
    "download-queue-size": 5,
    "encryption": 1,
    "idle-seeding-limit": 30,
    "idle-seeding-limit-enabled": false,
    "incomplete-dir": "/var/lib/transmission-daemon/downloads/incomplete",
    "incomplete-dir-enabled": true,
    "lpd-enabled": false,
    "message-level": 2,
    "peer-congestion-algorithm": "",
    "peer-id-ttl-hours": 6,
    "peer-limit-global": 200,
    "peer-limit-per-torrent": 50,
    "peer-port": 51413,
    "peer-port-random-high": 65535,
    "peer-port-random-low": 49152,
    "peer-port-random-on-start": false,
    "peer-socket-tos": "lowcost",
    "pex-enabled": true,
    "port-forwarding-enabled": false,
    "prealloc-min-overhead-gb": 1,
    "prefetch-enabled": true,
    "queue-stalled-enabled": true,
    "queue-stalled-minutes": 30,
    "ratio-limit": 2,
    "ratio-limit-enabled": true,
    "rename-partial-files": true,
    "rpc-authentication-required": true,
    "rpc-bind-address": "0.0.0.0",
    "rpc-enabled": true,
    "rpc-host-whitelist": "bittorrent.yourdomain.net,10.1.0.*",
    "rpc-host-whitelist-enabled": true,
    "rpc-password": "your-password-here",
    "rpc-port": 9091,
    "rpc-url": "/transmission/",
    "rpc-username": "transmission",
    "rpc-whitelist": "127.0.0.1,::1,10.*.*.*",
    "rpc-whitelist-enabled": true,
    "scrape-paused-torrents-enabled": true,
    "script-torrent-added-enabled": false,
    "script-torrent-done-enabled": false,
    "seed-queue-enabled": false,
    "speed-limit-down": 0,
    "speed-limit-down-enabled": false,
    "speed-limit-up": 0,
    "speed-limit-up-enabled": false,
    "start-added-torrents": true,
    "trash-original-torrent-files": false,
    "umask": 2,
    "utp-enabled": true,
    "watch-dir": "/var/lib/transmission-daemon/watch",
    "watch-dir-enabled": true
}

Key settings to review:

rpc-password: set a strong password. Transmission hashes it on next startup. Generate one in KeePassXC and store it there.

rpc-whitelist: restricts which IPs can access the web interface. The 10.*.*.* pattern allows access from all three sites via the WireGuard VPN.

rpc-host-whitelist: add the container hostname and any IP addresses used to access the web interface. Missing entries cause 421 Misdirected Request errors.

ratio-limit: set to 2.0 by default, meaning Transmission stops seeding when it has uploaded twice what it downloaded. Adjust to taste or disable entirely.

umask: set to 2 so downloaded files are group-writable, allowing other services (Jellyfin, Kavita) to read them without permission issues.

watch-dir: Transmission watches this directory for new .torrent files and starts them automatically. Create the directory:

sudo mkdir -p /var/lib/transmission-daemon/watch
sudo chown debian-transmission:debian-transmission \
    /var/lib/transmission-daemon/watch

Start and verify

sudo systemctl start transmission-daemon
sudo systemctl enable transmission-daemon
sudo systemctl status transmission-daemon

Verify the RPC port is listening:

ss -tlnp | grep 9091

Test the RPC connection locally:

transmission-remote -n 'transmission:your-password-here' --session-info

nginx reverse proxy

Add a virtual server or location block to the nginx web container to expose the Transmission web interface:

# Add to an existing server block or create a dedicated one
location /transmission/ {
    proxy_pass http://10.1.0.x:9091/transmission/;
    include snippets/proxy-headers.conf;

    # Restrict to internal network only
    include snippets/internal-only.conf;
}

Or as a standalone virtual server:

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    http2 on;
    server_name bittorrent.yourdomain.net;

    ssl_certificate /etc/ssl/certs/bittorrent.yourdomain.net.crt;
    ssl_certificate_key /etc/ssl/private/bittorrent.yourdomain.net.key;

    # Internal access only
    include snippets/internal-only.conf;
    include snippets/security-headers.conf;

    location /transmission/ {
        proxy_pass http://10.1.0.x:9091/transmission/;
        include snippets/proxy-headers.conf;
    }

    access_log /var/log/nginx/bittorrent.access.log main;
    error_log /var/log/nginx/bittorrent.error.log;
}

Firewall rules

Open the BitTorrent peer port on the UDM-SE for inbound peer connections. Without this, Transmission operates in passive mode and some torrents connect slowly or not at all.

On the UDM-SE, add a port forward:

SettingValue
Port51413
ProtocolTCP + UDP
Forward IPContainer IP address
Forward Port51413

transmission-remote usage

Useful transmission-remote commands from the desktop or server:

# Alias for convenience (add to ~/.bashrc)
alias t='transmission-remote -n "transmission:your-password" -l 10.1.0.x'

# List all torrents
transmission-remote 10.1.0.x -n 'transmission:password' -l

# Add a torrent by URL or file
transmission-remote 10.1.0.x -n 'transmission:password' -a https://example.com/file.torrent

# Add a magnet link
transmission-remote 10.1.0.x -n 'transmission:password' -a 'magnet:?xt=urn:...'

# Check session stats
transmission-remote 10.1.0.x -n 'transmission:password' -st

# Remove a torrent (keep data)
transmission-remote 10.1.0.x -n 'transmission:password' -t 1 --remove

# Remove a torrent and delete data
transmission-remote 10.1.0.x -n 'transmission:password' -t 1 --remove-and-delete

FlexGet: automated downloads (optional)

FlexGet is a Python-based automation tool that watches RSS feeds and adds matching torrents to Transmission automatically. It is useful for automatically downloading new episodes of TV shows, new releases from followed content creators, or any torrent feed with predictable naming.

Install FlexGet in a virtual environment owned by the debian-transmission user:

sudo -u debian-transmission python3 -m venv \
    /var/lib/transmission-daemon/flexget-venv
sudo -u debian-transmission \
    /var/lib/transmission-daemon/flexget-venv/bin/pip install flexget

Create the FlexGet configuration directory:

sudo mkdir -p /var/lib/transmission-daemon/flexget
sudo chown debian-transmission:debian-transmission \
    /var/lib/transmission-daemon/flexget

Create /var/lib/transmission-daemon/flexget/config.yml:

# FlexGet configuration
# /var/lib/transmission-daemon/flexget/config.yml

tasks:
  # Example: download a podcast feed
  example-podcast:
    rss: https://example.com/podcast/rss
    accept_all: yes
    transmission:
      host: localhost
      port: 9091
      username: transmission
      password: your-password-here
      path: /var/lib/transmission-daemon/downloads/complete/podcasts/

Create a systemd service for the FlexGet daemon:

sudo tee /etc/systemd/system/flexget.service << 'EOF'
[Unit]
Description=FlexGet daemon
After=transmission-daemon.service
Requires=transmission-daemon.service

[Service]
Type=simple
User=debian-transmission
Group=debian-transmission
WorkingDirectory=/var/lib/transmission-daemon/flexget
ExecStart=/var/lib/transmission-daemon/flexget-venv/bin/flexget \
    --loglevel warning daemon start
ExecStop=/var/lib/transmission-daemon/flexget-venv/bin/flexget \
    daemon stop
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable --now flexget

The source material uses an Upstart init script for FlexGet. The systemd service above replaces it. The After=transmission-daemon.service and Requires=transmission-daemon.service directives ensure FlexGet only starts after Transmission is running, which is the equivalent of the original start on started transmission-daemon Upstart directive.

Connecting the desktop Transmission client

The Transmission desktop client configured in the desktop Toolbox section connects to the server daemon rather than managing downloads locally. In Transmission on the desktop, go to Edit > Preferences > Remote and configure:

SettingValue
Enable remote accessYes
Hostbittorrent.yourdomain.net or 10.1.0.x
Port9091
AuthenticationYes
Usernametransmission
PasswordThe password from settings.json

All torrent management from the desktop GUI now happens on the server daemon. Downloads run on the server whether or not the desktop is on.

Stop the Transmission daemon before editing settings.json. Transmission overwrites the configuration file with its in-memory state when it exits. Changes made to the file while the daemon is running are silently discarded when it next shuts down. This is the most common source of confusion when configuring Transmission for the first time.


Roll Your Own Network / Server. Next: Calibre.