How to Self-Host Transmission with Docker
What Is Transmission?
Transmission is a lightweight, open-source BitTorrent client known for its minimal resource footprint and clean interface. It replaces bloated desktop torrent clients like uTorrent and BitTorrent with a self-hosted web UI you can access from any browser. Transmission focuses on doing one thing well — downloading torrents — without the feature bloat that heavier clients carry.
Prerequisites
- A Linux server (Ubuntu 22.04+ recommended)
- Docker and Docker Compose installed (guide)
- 256 MB of free RAM (minimum)
- Storage for downloads
- A domain name (optional, for remote access)
Docker Compose Configuration
Create a docker-compose.yml file:
services:
transmission:
image: lscr.io/linuxserver/transmission:4.1.1
container_name: transmission
restart: unless-stopped
ports:
- "9091:9091" # Web UI
- "51413:51413" # Peer connections (TCP)
- "51413:51413/udp" # Peer connections (UDP)
environment:
PUID: ${PUID:-1000} # Your user ID (run: id -u)
PGID: ${PGID:-1000} # Your group ID (run: id -g)
TZ: ${TZ:-America/New_York} # Your timezone
PEERPORT: "51413" # Must match the port mapping above
USER: ${TRANSMISSION_USER} # Web UI username (set in .env)
PASS: ${TRANSMISSION_PASS} # Web UI password (set in .env)
volumes:
- transmission-config:/config # Settings, resume data, stats
- ${DOWNLOAD_DIR:-/srv/downloads}:/downloads # Completed and in-progress downloads
- ${WATCH_DIR:-/srv/watch}:/watch # Drop .torrent files here to auto-add
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9091/transmission/web/"]
interval: 30s
timeout: 10s
retries: 3
volumes:
transmission-config:
Create a .env file alongside it:
# User/Group IDs — run 'id' to find yours
PUID=1000
PGID=1000
# Timezone — find yours at https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
TZ=America/New_York
# Web UI credentials — CHANGE THESE
TRANSMISSION_USER=admin
TRANSMISSION_PASS=change-me-to-a-strong-password
# Download directory on the host — CHANGE THIS
DOWNLOAD_DIR=/srv/downloads
# Watch directory — drop .torrent files here to auto-add them
WATCH_DIR=/srv/watch
Create the host directories and start the stack:
sudo mkdir -p /srv/downloads /srv/watch
sudo chown 1000:1000 /srv/downloads /srv/watch
docker compose up -d
Initial Setup
- Open the web UI at
http://your-server-ip:9091 - Log in with the username and password you set in
.env - The default web UI is functional but minimal — you can swap it out for a better one (see Advanced Configuration below)
- Test by adding a torrent: click the Open Torrent button (folder icon) or paste a magnet link
The /watch directory is pre-configured as a watch folder. Drop any .torrent file into /srv/watch on the host and Transmission picks it up automatically.
Configuration
Download Paths
Transmission uses three internal directories by default:
| Path | Purpose |
|---|---|
/downloads/complete | Finished downloads |
/downloads/incomplete | In-progress downloads |
/watch | Watch folder for auto-adding .torrent files |
To customize, edit /config/settings.json while the container is stopped:
docker compose stop transmission
Key fields in settings.json:
{
"download-dir": "/downloads/complete",
"incomplete-dir": "/downloads/incomplete",
"incomplete-dir-enabled": true,
"watch-dir": "/watch",
"watch-dir-enabled": true
}
Start the container again after editing:
docker compose start transmission
Important: Always stop Transmission before editing settings.json. The running process overwrites the file on shutdown, discarding your changes.
Speed Limits
Configure speed limits in settings.json or through the web UI:
{
"speed-limit-down": 10000,
"speed-limit-down-enabled": false,
"speed-limit-up": 500,
"speed-limit-up-enabled": true,
"alt-speed-enabled": false,
"alt-speed-down": 2000,
"alt-speed-up": 200,
"alt-speed-time-enabled": true,
"alt-speed-time-begin": 540,
"alt-speed-time-end": 1020,
"alt-speed-time-day": 62
}
speed-limit-*: Global limits in KB/salt-speed-*: “Turtle mode” limits, useful for scheduling slower speeds during work hoursalt-speed-time-begin/end: Minutes from midnight (540 = 9:00 AM, 1020 = 5:00 PM)alt-speed-time-day: Bitmask for days (62 = Monday through Friday)
Authentication
Authentication is set via the USER and PASS environment variables. To restrict access further, use these optional environment variables in your docker-compose.yml:
environment:
WHITELIST: "192.168.1.*,10.0.0.*" # IP whitelist (comma-separated)
HOST_WHITELIST: "transmission.example.com" # Hostname whitelist for reverse proxy
If you lock yourself out, stop the container and edit /config/settings.json:
{
"rpc-authentication-required": false
}
Start the container, log in, set a new password, then re-enable authentication.
Peer Connection Settings
In settings.json:
{
"peer-port": 51413,
"peer-port-random-on-start": false,
"peer-limit-global": 200,
"peer-limit-per-torrent": 50,
"encryption": 1,
"dht-enabled": true,
"pex-enabled": true,
"lpd-enabled": false
}
encryption: 0 = prefer unencrypted, 1 = prefer encrypted, 2 = require encrypteddht-enabled: Distributed hash table for finding peers without trackerspex-enabled: Peer exchange — learn about new peers from connected peers
Advanced Configuration (Optional)
Alternative Web UIs
Transmission’s built-in web UI is basic. Swap it for a modern interface by setting the TRANSMISSION_WEB_HOME environment variable.
Flood for Transmission (recommended):
environment:
TRANSMISSION_WEB_HOME: /flood-for-transmission/
The LinuxServer.io image bundles Flood automatically. Set the environment variable and restart:
docker compose up -d
Flood gives you a modern, responsive UI with better sorting, filtering, and a cleaner layout. Other options include Combustion (/combustion-release/) and Kettu (/kettu/), but Flood is the most actively maintained.
Connecting to Sonarr and Radarr
Transmission integrates directly with the *arr stack as a download client.
- Go to Settings > Download Clients > Add > Transmission
- Configure:
- Host:
transmission(if on the same Docker network) or your server IP - Port:
9091 - Username: your
USERvalue from.env - Password: your
PASSvalue from.env - Category:
tv(Sonarr) ormovies(Radarr) - Directory: Leave blank to use default, or set
/downloads/complete/tvfor Sonarr,/downloads/complete/moviesfor Radarr
- Host:
- Click Test to verify the connection, then Save
For category-based sorting, create subdirectories on the host:
mkdir -p /srv/downloads/complete/tv /srv/downloads/complete/movies
If Prowlarr manages your indexers, it syncs them to Sonarr and Radarr automatically — no manual indexer setup needed in each app.
VPN Integration
For privacy, route Transmission traffic through a VPN using Gluetun:
services:
gluetun:
image: qmcgaw/gluetun:v3.41.1
container_name: gluetun
restart: unless-stopped
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun:/dev/net/tun
ports:
- "9091:9091" # Transmission Web UI (exposed via Gluetun)
- "51413:51413"
- "51413:51413/udp"
environment:
VPN_SERVICE_PROVIDER: "mullvad" # Your VPN provider
VPN_TYPE: "wireguard"
# WIREGUARD_PRIVATE_KEY: "your-key"
# WIREGUARD_ADDRESSES: "10.x.x.x/32"
volumes:
- gluetun-data:/gluetun
transmission:
image: lscr.io/linuxserver/transmission:4.1.1
container_name: transmission
restart: unless-stopped
network_mode: "service:gluetun" # All traffic routes through VPN
depends_on:
- gluetun
environment:
PUID: "1000"
PGID: "1000"
TZ: "America/New_York"
PEERPORT: "51413"
USER: "admin"
PASS: "change-me-to-a-strong-password"
volumes:
- transmission-config:/config
- /srv/downloads:/downloads
- /srv/watch:/watch
volumes:
transmission-config:
gluetun-data:
With network_mode: "service:gluetun", all Transmission traffic goes through the VPN tunnel. If the VPN drops, Transmission loses all network access — this is your kill switch. Ports are exposed on the Gluetun container, not on Transmission.
Blocklists
Transmission supports IP blocklists to block known bad peers. In settings.json:
{
"blocklist-enabled": true,
"blocklist-url": "https://github.com/Naunter/BT_BlockLists/raw/master/bt_blocklists.gz"
}
Transmission downloads and applies the blocklist automatically. Update it periodically through the web UI or by restarting the container.
Reverse Proxy
Behind Nginx Proxy Manager or another reverse proxy, forward your domain to http://your-server-ip:9091.
Add your domain to the HOST_WHITELIST environment variable:
environment:
HOST_WHITELIST: "transmission.example.com"
For Caddy, a minimal config:
transmission.example.com {
reverse_proxy localhost:9091
}
Transmission requires the X-Forwarded-Host header to be passed correctly. Most reverse proxies handle this by default.
See Reverse Proxy Setup for full configuration guides.
Backup
The /config volume contains Transmission settings, torrent resume data, and statistics. Back it up:
docker compose stop transmission
docker run --rm \
-v transmission-config:/data \
-v $(pwd):/backup \
alpine tar czf /backup/transmission-config-backup.tar.gz /data
docker compose start transmission
To restore:
docker compose stop transmission
docker run --rm \
-v transmission-config:/data \
-v $(pwd):/backup \
alpine sh -c "rm -rf /data/* && tar xzf /backup/transmission-config-backup.tar.gz -C /"
docker compose start transmission
Your downloaded files in /srv/downloads should be backed up separately. See Backup Strategy.
Troubleshooting
Web UI returns “403: Forbidden”
Symptom: Browsing to http://server:9091 returns a 403 error.
Fix: Transmission blocks connections from IPs not in its whitelist when accessed via a hostname. Either:
- Access by IP address directly instead of hostname
- Add your hostname to
HOST_WHITELISTin the environment variables - Stop the container and set
"rpc-host-whitelist-enabled": falsein/config/settings.json(less secure)
Downloads stuck at 0% with no peers
Symptom: Torrents are added but show 0 peers and never start.
Fix:
- Verify port 51413 is forwarded to your server (check with a port checker tool)
- Check that
PEERPORTin your environment matches your port mapping - If using a VPN, confirm your provider supports port forwarding and the port is active
- Enable DHT and PEX in settings if disabled — these help find peers without trackers
- Check disk space:
df -h /srv/downloads
Settings changes not persisting
Symptom: You edit settings.json but changes revert after restart.
Fix: Transmission writes its in-memory settings to settings.json on shutdown. If you edit the file while the container is running, your changes are overwritten. Always:
- Stop the container:
docker compose stop transmission - Edit the file
- Start the container:
docker compose start transmission
Permission denied errors on downloads
Symptom: Torrents fail with “Permission denied” or downloaded files are owned by root.
Fix:
- Verify
PUIDandPGIDmatch the owner of your download directory:ls -la /srv/downloads - Fix ownership:
sudo chown -R 1000:1000 /srv/downloads - Ensure the download directory exists and is writable before starting the container
Watch folder not picking up .torrent files
Symptom: Dropping .torrent files into /srv/watch does nothing.
Fix:
- Confirm the volume mount is correct:
docker inspect transmission | grep watch - Check that the watch directory is enabled in
settings.json:"watch-dir-enabled": true - Verify file permissions: the
PUID/PGIDuser must be able to read files in the watch directory - Check logs for errors:
docker logs transmission | grep watch
Frequently Asked Questions
Should I use Transmission or qBittorrent for my arr stack?
qBittorrent has better *arr stack integration out of the box — it supports categories natively (Sonarr and Radarr can auto-tag downloads), sequential downloading, and more granular control over seeding behavior. Transmission works well with the *arr stack but lacks native category support and sequential downloading. If your primary use is automated media downloading, qBittorrent is the better pick. If you want the lightest possible client for simple downloading, Transmission wins. See our qBittorrent vs Transmission comparison.
How do I enable port forwarding with a VPN?
When using Gluetun with a VPN provider that supports port forwarding (like Mullvad, ProtonVPN, or AirVPN), Gluetun can automatically configure the forwarded port. Set VPN_PORT_FORWARDING=on in the Gluetun environment, then configure Transmission to use the forwarded port. Without port forwarding, you can still download but speeds are significantly lower because peers cannot initiate connections to you.
Why is Transmission using so much CPU even with few active torrents?
This is usually caused by excessive DHT activity or a large number of tracked torrents (even paused ones). Reduce peer-limit-global in settings.json from the default 240 to 100-150. If DHT is enabled, it runs continuously to discover peers — disabling it ("dht-enabled": false) reduces CPU but limits peer discovery for public torrents. Also check that you do not have hundreds of completed/paused torrents — each one maintains tracker connections.
Can I access Transmission’s web UI remotely without a reverse proxy?
Yes, but it is not recommended. Transmission’s web UI is unencrypted HTTP. For remote access, either put it behind a reverse proxy with HTTPS, or access it through a VPN tunnel like Tailscale or WireGuard. If you must expose it directly, at minimum set strong credentials via USER/PASS and restrict access with WHITELIST to trusted IPs.
How do I switch from the default web UI to Flood?
Set the TRANSMISSION_WEB_HOME environment variable to /flood-for-transmission/ in your Docker Compose file and restart the container. The LinuxServer.io image bundles Flood automatically — no additional downloads needed. Flood provides a modern, responsive interface with better sorting, filtering, and drag-and-drop support.
Does Transmission support RSS feed auto-downloading?
The Docker web UI does not have built-in RSS support. For automated RSS-based downloading, use Sonarr or Radarr with Transmission as the download client — they handle RSS monitoring, filtering, and automatic grabbing far better than any built-in RSS feature. For non-media RSS feeds, tools like Flexget can be configured as a sidecar container to monitor RSS feeds and push torrents to Transmission.
Resource Requirements
- RAM: 50-100 MB idle, 150-300 MB with active downloads
- CPU: Very low. Transmission is one of the lightest torrent clients available.
- Disk: ~20 MB for the application. Storage depends entirely on your download volume.
Transmission is measurably lighter than qBittorrent — expect roughly half the memory usage at idle. This makes it a strong choice for low-resource servers like a Raspberry Pi.
Verdict
Transmission is the best torrent client for self-hosters who want something lightweight and reliable. It does exactly what a torrent client should — downloads torrents efficiently with minimal resource overhead. The built-in web UI is basic but functional, and swapping in Flood makes it genuinely good-looking.
The trade-off versus qBittorrent is feature depth. qBittorrent has a richer web UI out of the box, more granular configuration options, and slightly better *arr stack integration (category management, sequential downloading). If you are running a full *arr stack and want maximum control, qBittorrent is the better pick. If you want something simpler, lighter, and just as reliable for basic downloading, Transmission is the way to go.
For a complete download setup, pair Transmission with Sonarr for TV, Radarr for movies, and Prowlarr for indexer management.
Related
- Deluge vs Transmission: Torrent Clients Compared
- qBittorrent vs Transmission: Which to Self-Host?
- How to Self-Host qBittorrent
- How to Self-Host Sonarr
- How to Self-Host Radarr
- How to Self-Host Prowlarr
- Sonarr vs Radarr
- Transmission vs Deluge
- Best Self-Hosted Download Management
- Docker Compose Basics
- Reverse Proxy Setup
- Backup Strategy
- Docker Networking
Get self-hosting tips in your inbox
Get the Docker Compose configs, hardware picks, and setup shortcuts we don't put in articles. Weekly. No spam.
Comments