rationale Link to heading
- accessing transmission-daemon via web/cli
- do port forwarding via vpn provider to secure transmission
- using a dedicated lightweight distro
- centralize all your torrents from public/private trackers
- not using docker and it’s *arr stack but why ???
- be a good 24/7 seeder
requirements Link to heading
- own router/firewall or ability to open/nat ports
- (optional) using proxmox’s lxc for better performances, less overhead for storage and network
- an alpine box but any gnu/linux or even bsd will do ( commands differ just a bit )
- (optional) wireguard as it’s easy to setup and really convenient
- (optional) airvpn account to have all options ( this is not sponsored )
- a storage attached to your box
warnings Link to heading
- some trackers prohibit vpn use read the rulez
- some trackers need you to disable dht and pex or utp
scenarii Link to heading
- seedbox on lan
- seedbox on vps
seedbox on lan Link to heading
topology
- firewall pfsense : 192.168.66.1 :51442 NAT > 192.168.66.51 + rules on wan
- lxc alpinebox : 192.168.66.51 :51442 transmission-daemon + rclone
on alpine
/etc/network/interfaces
auto eth0
iface eth0 inet static
address 192.168.66.51/24
gateway 192.168.66.1
check routes and neighbours
ip r
ip n
ping the great whole internet
ping 9.9.9.9
vpn client Link to heading
- skip all vpn and port forwarding steps if no vpn is needed
setup wireguard in alpine
apk add wireguard-tools wireguard-tools-wg-quick
airvpn is a good vpn for port forwarding
generate wireguard conf via client area:
paste the .conf in /etc/wireguard/airvpn.conf
up the interface
wg-quick up airvpn
check vpn ip and status
ip -br a
wg show
if everything work as intended create an openrc initd to start at boot
/etc/init.d/wg-airvpn
#!/sbin/openrc-run
description="WireGuard Quick Airvpn"
depend() {
need localmount
need net
}
start() {
wg-quick up airvpn
}
stop() {
wg-quick down airvpn
}
enable it
chmod +x /etc/init.d/wg-airvpn
rc-update add wg-airvpn default
vpn port forwarding Link to heading
setup the name of the vm in airvpn client area
you can adjust the local port or not you deal whith what’s behind the firewall
for example in airvpn client area port forwarding
for you device only
- 51442
- device alpinebox
- protocol tcp/udp
- ipv4 only
- local port 51442
example pfsense :
- NAT : wan tcp/udp * :* wan_address :51442 > nat_ip 192.168.66.51:51442
- WAN rule: ipv4 tcp/udp * :* > 192.168.66.51:51442
in pfsense you’ll need to setup outbound nat to hybrid
later in transmission you’ll setup the listen port to :51442
storage Link to heading
- following commands refer to proxmox if you have another system go to directories
on proxmox mount usb or whatever media storage
for example
mount /dev/usbpool/mediacenter /mnt/media/
enter alpine container
pct enter 651
we need a user dlman
without sudo prvileges and with specific uid
adduser -s /bin/sh -u 1000 dlman
get back to proxmox’s shell
Ctrl + O
setup directory’s permissions recuresively
chown -R 101000:101000 /mnt/mediacenter/
1000
is the uid of dlman
configure the mountpoint
prohibit dangerous options and disable backup on this mp
/etc/pve/lxc/651.conf
mp0: /mnt/mediacenter,mp=/mnt/media,mountoptions=nodev;noexec;nosuid,backup=0
restart the container to check everything is ok
pct reboot 651
pct enter 651
directories Link to heading
create the needed directories :
mkdir -p /mnt/media/downloads/{complete,incomplete,torrents}
adapt the permission so transimission can write inside
transmission setup Link to heading
some packages are needed
apk update && apk upgrade
apk add rclone transmission-daemon-openrc transmission-daemon transmission-cli
- stop the service otherwise it’ll flush conf
rc-service transmission-daemon stop
configure transmission to require encryption for peers
/etc/conf.d/transmission-daemon
TRANSMISSION_OPTIONS="--encryption-required"
then configure transmission to
- dl stuff in
downloads
andincomplete
- watch new torrent files added automatically in
torrents
- disable dht pex and utp for some private trackers
- provide a user/password for rpc remote access
- limit access via rpc to localhost only on :9091
- setup the listening port for peers :51442
- force encryption with peers
- …
here is an example conf
-
warning : some private trackers ask to disable dht pex and utp
-
the first time you setup a password it detect it’s not a hash and will hash it once transmission is started
/var/lib/transmission/config/settings.json
{
"alt-speed-down": 50,
"alt-speed-time-begin": 540,
"alt-speed-time-day": 127,
"alt-speed-time-enabled": false,
"alt-speed-time-end": 1020,
"alt-speed-up": 50,
"announce-ip": "",
"announce-ip-enabled": false,
"anti-brute-force-enabled": false,
"anti-brute-force-threshold": 100,
"bind-address-ipv4": "0.0.0.0",
"bind-address-ipv6": "::",
"blocklist-enabled": false,
"blocklist-url": "http://www.example.com/blocklist",
"cache-size-mb": 128,
"default-trackers": "",
"dht-enabled": false,
"download-dir": "/mnt/media/downloads/complete",
"download-queue-enabled": true,
"download-queue-size": 20,
"encryption": 2,
"idle-seeding-limit": 30,
"idle-seeding-limit-enabled": false,
"incomplete-dir": "/mnt/media/downloads/incomplete",
"incomplete-dir-enabled": true,
"lpd-enabled": true,
"message-level": 2,
"peer-congestion-algorithm": "",
"peer-limit-global": 240,
"peer-limit-per-torrent": 50,
"peer-port": 51442,
"peer-port-random-high": 65535,
"peer-port-random-low": 49152,
"peer-port-random-on-start": false,
"peer-socket-tos": "le",
"pex-enabled": false,
"pidfile": "/var/run/transmission/transmission.pid",
"port-forwarding-enabled": true,
"preallocation": 1,
"prefetch-enabled": true,
"queue-stalled-enabled": true,
"queue-stalled-minutes": 30,
"ratio-limit": 2,
"ratio-limit-enabled": false,
"rename-partial-files": true,
"rpc-authentication-required": true,
"rpc-bind-address": "0.0.0.0",
"rpc-enabled": true,
"rpc-host-whitelist": "",
"rpc-host-whitelist-enabled": false,
"rpc-password": "REDACTEDPASS",
"rpc-port": 9091,
"rpc-socket-mode": "0750",
"rpc-url": "/transmission/",
"rpc-username": "btman",
"rpc-whitelist": "127.0.0.1,::1",
"rpc-whitelist-enabled": true,
"scrape-paused-torrents-enabled": true,
"script-torrent-added-enabled": false,
"script-torrent-added-filename": "",
"script-torrent-done-enabled": false,
"script-torrent-done-filename": "",
"script-torrent-done-seeding-enabled": false,
"script-torrent-done-seeding-filename": "",
"seed-queue-enabled": false,
"seed-queue-size": 10,
"speed-limit-down": 100,
"speed-limit-down-enabled": false,
"speed-limit-up": 100,
"speed-limit-up-enabled": false,
"start-added-torrents": true,
"tcp-enabled": true,
"torrent-added-verify-mode": "fast",
"trash-original-torrent-files": false,
"umask": "002",
"upload-slots-per-torrent": 8,
"utp-enabled": true,
"watch-dir": "/mnt/media/downloads/torrents",
"watch-dir-enabled": true
}
now you can start your service
service transmission-daemon start
accessing transmission remotely Link to heading
- via rpc web interface
- via rpc in ssh tunnel
be carefull do not expose your rpc on the internet !
- on the lan you may not need protection
/var/lib/transmission/config/settings.json
"rpc-whitelist-enabled": false,
http://192.168.66.51:9091/transmission/web/
- via secure ssh tunnel
you’ll need to bind the 9091 port to a local port on your remote client
add this option to alpine’s ssh conf
/etc/sshd_config
AllowTcpForwarding local
reload sshd
rc-service sshd restart
then from a client
ssh -i .ssh/seedbox_key -L 9091:localhost:9091 user@yourseedbox -p22
then you can use web browser to access the webui
http://localhost:9091
- you can also use
transmission-remote
on the seedbox or via the tunnel
port stuff Link to heading
check the port via edit preferences > network > listen port is :51442
check your listening sockets
netstat -tulpn
double check your firewall
now enable your service at start
rc-update add transmission-daemon
transmission-remote Link to heading
you can use cli to do some funny stuff and exploit scripts
create a .netrc file containing your credentials
machine localhost
login btman
password REDACTED
account REDACTED
eventualy use a bash_alias as follows
alias transmission-remote='transmission-remote -N ~/.secrets/.netrc'
get informations and perform actions :
transmission-remote -N .netrc -st
transmission-remote -N .netrc -l
now the fun begins you can add a torrent and label it :
transmission-remote -a Downloads/debian-12.5.0-amd64-netinst.iso.torrent -L iso
transmission-remote -a Downloads/Rocky-9.3-x86_64-dvd.torrent -L iso
then you can list all your torrents with labels
transmission-remote -F l:iso -l
ID Done Have ETA Up Down Ratio Status Name
25 100% 10.51 GB Done 382.0 0.0 0.06 Seeding Rocky-9.3-x86_64-dvd
214 100% 659.6 MB Done 0.0 0.0 0.00 Idle debian-12.5.0-amd64-netinst.iso
228 100% 8.80 GB Done 0.0 0.0 0.00 Idle Rocky-9.3-aarch64-dvd
Sum: 19.98 GB 382.0 0.0
then you can perform action like moving :
- torrent should be in idle or stopped to be moved
transmission-remote -F l:iso -l --move /mnt/media/iso/
if you need some more fun you can use this simple script to move torrents with label to specific directories
this stop moves and restart only active torrents with defined label located in /mnt/mediacenter/downloads/complete
to specific directories matching labels.
#!/bin/bash
# Define the directory mappings for each label
declare -A LABEL_DIRS=(
["iso"]="/mnt/media/iso"
["software"]="/mnt/media/software"
["serie"]="/mnt/media/series"
["doc"]="/mnt/media/documentaries"
["music"]="/mnt/media/music"
["movie"]="/mnt/media/films"
["junk"]="/mnt/media/junk"
)
# Define the complete download directory
COMPLETE_DOWNLOAD_DIR="/mnt/media/downloads/complete"
# Function to handle transmission-remote command with credentials
transmission_remote() {
transmission-remote -N ~/.secrets/.netrc "$@"
}
# Function to get the location of a torrent
get_torrent_location() {
transmission_remote -t "$1" -i | awk '/Location: / {print $NF}'
}
# Function to get the status of a torrent
get_torrent_status() {
transmission_remote -t "$1" -i | awk '/State: / {print $NF}'
}
# Loop through each label and process its torrents
for label in "${!LABEL_DIRS[@]}"; do
label_dir="${LABEL_DIRS[$label]}"
echo "Moving torrents with label $label to $label_dir directory..."
# Retrieve torrent IDs with the specified label
torrent_ids=$(transmission_remote -F "l:$label" -l | awk '$1 ~ /^[0-9]+$/ {print $1}')
if [[ -n "$torrent_ids" ]]; then
echo "Torrent IDs for label $label: $torrent_ids"
# Loop through each torrent ID and perform the necessary actions
for id in $torrent_ids; do
# Get the location of the torrent
torrent_location=$(get_torrent_location "$id")
# Check if the torrent is in the complete download directory
if [[ "$torrent_location" == "$COMPLETE_DOWNLOAD_DIR" ]]; then
# Get the status of the torrent
torrent_status=$(get_torrent_status "$id")
echo "Moving torrent $id with label $label..."
transmission_remote -t "$id" -S --move "$label_dir"
# Introduce a short delay before starting the torrent if its status was not "Stopped"
if [[ "$torrent_status" != "Stopped" ]]; then
sleep 1
transmission_remote -t "$id" -s
fi
else
echo "Skipping torrent $id with label $label as it's not in $COMPLETE_DOWNLOAD_DIR"
fi
done
else
echo "No torrents found with label $label"
fi
done
cron is your friend
ddl and cloud services Link to heading
configure rclone to dl stuff in /mnt/media/downloads
su -l dlman
rclone config
you can go through the process for multiple providers
enjoy your local seedbox.
seedbox on vps Link to heading
- reproduce ip address steps
- as firewall you can use iptables/nftables/ufw/firewalld or whatsoever
- use a ssh tunnel to bind rpc port to local ! (see above)
simple ufw example
ufw enable
ufw allow 22,51442/tcp
ufw allow 51442/udp
use netcat to can ports
nc -zv 192.168.66.51 51442
check in transmission-remote or via webui if everything is ok
troubleshooting : Link to heading
when using the client transmission-remote
it may change your settings.json
permissions
transmission-remote --list
-rw------- 1 transmis transmis 2.7K Feb 14 00:24 /var/lib/transmission/config/settings.json
you’ll have this error
/var/log/transmission/transmission.log
transmission-daemon Error loading config file -- exiting. (/home/buildozer/aports/community/transmission/src/transmission-4.0.4/daemon/daemon.cc:914)
because it changes the permission of your conf
-rw------- 1 transmis transmis 2.7K Feb 14 00:24 /var/lib/transmission/config/settings.json
correct the permissions
chmod g+rwx /var/lib/transmission/config/settings.json
ressources Link to heading
- mount binding point
- airvpn
https://airvpn.org/faq/port_forwarding/
- rclone
- transmission conf
https://github.com/transmission/transmission/blob/main/docs/Editing-Configuration-Files.md
https://github.com/transmission/transmission/blob/main/docs/Port-Forwarding-Guide.md