Getting started
This page takes you from nothing to a running Transmission web interface. You need Docker on a linux/amd64 or linux/arm64 machine. For the VPN route you also need an OpenVPN config file (.ovpn) from your VPN provider, and usually a file with your VPN user name and password.
1. Make the directories
The container stores its state in three directories you mount from the host:
mkdir -p config downloads watch
configholds Transmission’ssettings.json, resume data and torrent files.downloadsis where finished downloads land. Unfinished ones sit indownloads/_incomplete.watchis a drop box: a.torrentfile copied into it gets added automatically.
On every start the container gives all three, and everything inside them, to the user and group in PUID and PGID (default 1000). Pick the IDs of the host user that should own the downloads. See Configuration for what that does to existing files.
2. Start it without a VPN
docker run -d \
--name safe-transmission \
-e USERNAME=your_username \
-e PASSWORD=your_password \
-e PUID=1000 \
-e PGID=1000 \
-v "$PWD/config:/config" \
-v "$PWD/downloads:/downloads" \
-v "$PWD/watch:/watch" \
-p 8080:80 \
psyb0t/safe-transmission:latest
Open http://localhost:8080/. nginx asks for the user name and password, then redirects to Transmission’s web interface at /transmission/web/.
Leave out USERNAME and PASSWORD and there is no password at all: anyone who can reach port 8080 controls your Transmission. Read Security before publishing the port beyond your own machine.
3. Or start it with OpenVPN
Put the provider’s files next to the other directories:
mkdir -p openvpn
cp /path/to/provider.ovpn openvpn/config.ovpn
printf '%s\n' 'vpn_user' 'vpn_password' > openvpn/auth.txt
chmod 600 openvpn/auth.txt
The auth file is OpenVPN’s --auth-user-pass format: the user name on the first line, the password on the second. Skip it if your .ovpn file does not ask for a login.
Then add NET_ADMIN, WITH_OPENVPN=true and the two files:
docker run -d \
--name safe-transmission \
--cap-add=NET_ADMIN \
-e WITH_OPENVPN=true \
-e USERNAME=your_username \
-e PASSWORD=your_password \
-e PUID=1000 \
-e PGID=1000 \
-v "$PWD/openvpn/config.ovpn:/vpn-config.ovpn" \
-v "$PWD/openvpn/auth.txt:/vpn-auth.txt" \
-v "$PWD/config:/config" \
-v "$PWD/downloads:/downloads" \
-v "$PWD/watch:/watch" \
-p 8080:80 \
psyb0t/safe-transmission:latest
The container starts OpenVPN, waits 10 seconds, then starts Transmission. Check that the tunnel came up before you trust it: OpenVPN shows how.
4. Or use Docker Compose
The repository ships a docker-compose.yml for the VPN route. It expects the same layout as above: ./openvpn/config.ovpn, ./openvpn/auth.txt, ./config, ./downloads and ./watch next to it.
services:
safe-transmission:
image: psyb0t/safe-transmission:latest
cap_add:
- NET_ADMIN
environment:
- PUID=1000
- PGID=1000
- TZ=Etc/UTC
- WITH_OPENVPN=true
- USERNAME=your_username
- PASSWORD=your_password
ports:
- "8080:80"
volumes:
- ./openvpn/config.ovpn:/vpn-config.ovpn
- ./openvpn/auth.txt:/vpn-auth.txt
- ./config:/config
- ./downloads:/downloads
- ./watch:/watch
restart: always
Change USERNAME and PASSWORD first, then:
docker compose up -d
docker compose logs -f
The shipped file also has a version: "3.8" line at the top. Current Docker Compose ignores it and prints a warning.
5. Check the logs
docker logs safe-transmission
A healthy start without a VPN prints these lines from run.sh, followed by Transmission’s own log:
Setting up HTTP basic authentication...
Adding password for user your_username
Starting Nginx...
OpenVPN will not be started.
Starting Transmission...
With WITH_OPENVPN=true you see Ensuring the TUN device is available... and Starting OpenVPN... instead of the OpenVPN will not be started. line, then OpenVPN’s log. If the container exits, Troubleshooting lists the messages and what they mean.
Upgrading
Pull the new image and recreate the container. Everything that matters is in the mounted directories:
docker pull psyb0t/safe-transmission:latest
docker rm -f safe-transmission
Then run the same docker run command again, or docker compose pull && docker compose up -d. Release notes are in the CHANGELOG. Each release is also tagged on Docker Hub as vX.Y.Z if you want to pin one.