Setting up a Raspberry-Pi for secure bit torrenting

The method for configuring the raspi as a torrenting node over vpn is based off of a ‘trial and error’ approach. It necessitates the use of openvpn, requiring itself valid .ovpn configuration files, which may require a premium service (successfully tested with NordVPN).

A recommended alternative is to use a docker managed transmission container, such as the linuxserver/transmission container. I have included instructions for this at the end of these notes.

Installing pre-requisites

All of the prerequisites are installed with

sudo apt-get update
sudo apt-get install openvpn transmission-daemon transmission-common transmission-cli
# for the URI forwarding terminal browser, also need
sudo apt-get install elinks

Configuring OpenVPN

We configure openvpn first, by editing/creating /etc/openvpn/client.conf, from some template .ovpn file provided by the VPN server. The starup routine of OpenVPN will configure the VPN according to this file, which often means a little editing is required, namely including auth-user-pass as

# ...

auth-user-pass .secrets

<ca>
-----BEGIN CERTIFICATE-----
# ...

and thus, create a .secrets file in /etc/openvpn/, storing the login details for the VPN server. This should be formatted

[username]
[password]

NB: the line break is essential, and you’ll probably want to sudo chmod 400 .secrets as well. With this, OpenVPN will automatically login and start routing all (except LAN) traffic through the VPN on startup.

Next, we need to enable the AUTOSTART="all" flag in

/etc/default/openvpn

You’ll need root privileges again to edit this.

Finally we need to configure the new DNS servers. Chances are, your VPN provider either has statically assigned name servers in their .ovpn files, or provides you with relevant IP addresses; if not, a simple Google search will yield free public DNS servers.

On some distributions, editing /etc/resolv.conf is enough to reconfigure the DNS servers (note this has to be done as root, first executing chattr -i /etc/resolv.conf); but that does not seem to work for me anymore. The configuration file gets rewritten by some network daemon, thus doesn’t hold permanently (if at all). Instead, we edit

/etc/dhcpcd.conf

and add the line

static domain_name_servers=DNS_IP1 [DNS_IP2 ...]

with the relevant DNS IP addresses. Finally, restart the DHCP service and (re)start OpenVPN

sudo service dhcpcd restart
sudo service openvpn (re)start

You can verify the VPN is working using, e.g.

pi@eidolon:~ $ curl ipinfo.io
{
  "ip": "5.253.206.172",
  "city": "Włochy",
  "region": "Mazovia",
  "country": "PL",
  "loc": "52.1961,20.9323",
  "org": "AS9009 M247 Ltd",
  "postal": "02-231",
  "timezone": "Europe/Warsaw",
  "readme": "https://ipinfo.io/missingauth"
}

Something I’ve noticed with the automated start of OpenVPN is that having multiple .conf files in /etc/openvpn/ can cause some anomalous behaviour, especially on more recent versions of linux, including a highly annoying systemd password manager writing to Wall sporadically; make sure you only have one in the directory!

Configuring Transmission

You can either use transmission natively, or through a docker container. The benefits of using a docker container, beyond the usual benefits, include built-in web UI and more stateful control of torrenting environment.

Native

The configuration settings for the transmission daemon can be found in /etc/transmission-daemon/settings.json. Lines of importance are

{
	// ...
	"download-dir": "/var/lib/transmission-daemon/downloads",
	// ...
	"rpc-password": "{20eb240695a406a6c62c80db858c4558eaea2146xL3ZaOo.",
	// ...
	"rpc-username": "transmission",
	// ...
	"speed-limit-down": 2,
	"speed-limit-down-enabled": true,
	"speed-limit-up": 100,
	"speed-limit-up-enabled": false,
	// ...
	"umask": 18,
	// ...
}

Before editing, ensure the daemon is not running sudo service transmission-daemon stop, else the changes will be reverted on reload.

Change username and password to whatever your preference is (alternative disable authentication entirely); the password will be changed to a hash value once the daemon is reloaded. Default username:password is transmission:transmission.

You can change the download directory here aswell, and it’s worth changing speed-limit-down to something a little more convenient, e.g. 100. I would not recommend disabling it, as anyone watching your traffic would suddenly become aware of a bandwidth spike and probably suspect torrenting behaviour! Similarly, you’ll be a bit of a cunt to your housemates.

You can also change the seeding speed limits here – if you do, remember to change the speed-limit-up-enabled to true.

Finally umask is set to 2 for all new files, setting read/write permissions for other (777-775=2)

Restart the service sudo service transmission-daemon start. You can control the daemon using transmission-remote {args}, but, unless you disabled authentication, you’ll always have to provide a login flag. As such, I recommend aliasing

alias tsm='transmission-remote --auth [transmission-user]:[transmission-pw]'

to save your fingers.

You can easily find a reference manual on the available commands. I found the most useful are

tsm -a "[uri]"			# append uri to queue
tsm -l 				# list current torrents
tsm -t {id}	-s/S 		# torrent with {id} should be {-s}topped or {-S}tarted.
tsm -t all {command}		# apply command to all torrents in list
tsm -t all -r 			# remove all torrents

NB: removing all torrents only removes their index from the daemon; the downloaded files will have to manually deleted.

With this you’re now all set to start torrenting securely over a VPN.

With Docker

We will use the linuxserver/transmission docker image

docker pull linuxserver/transmission

We require three volumes for the mounts, namely downloads, config, and watch.

The startup command for the container is then

docker run --rm -d \
	--name=transmission \
	-e PUID=1000 -e PGID=1000 \
	-e TZ="Europe/London" \
	-e TRANSMISSION_WEB_HOME="/flood-for-transmission/" \
	-e USER=transmission -e PASS=transmission \
	-p 9091:9091 \
	-p 51413:51413 -p 51413:51413/udp \
	-v ~/config:/config \
	-v ~/downloads:/downloads \
	-v ~/watch:/watch \
	linuxserver/transmission

Note the USER and PASS are used for both the web UI and the transmission remote.

The TRANSMISSION_WEB_HOME may also be left blank, in which case no web UI is started.

The configuration file in config/settings.json may then be configured as in the native case

Note, if using elinks with docker, prefix the regular commands with

docker exec transmission-remote ...

The web UI is then exposed at port 9091.

Allowing SSH behind OpenVPN

If you want remote (i.e. not LAN) access to the raspi, you’ll have to reroute network traffic correctly, such that external traffic coming to the eth0 interface is correctly rerouted back through eth0. If this isn’t done, the pi tries to send back responses across tun0, since OpenVPN completely reconfigures the pi’s networking when active.

The fix for this is a little hacky, but it works well enough. Barebones, all that is required is a script

#!/bin/bash

(date; set; echo) >> /tmp/firewall.log

# check if openvpn is already active, if so stop and restart
ptrn="Active: active"
startvpn=0
if [[ $(sudo service openvpn status |grep Active:) =~ $ptrn ]]; then
	echo "vpn online" >> /tmp/firewall-preup.log
	startvpn=1
fi
sudo service openvpn stop

sudo ip rule add fwmark 66 table 666
sudo ip route add default via 192.168.0.1 dev eth0 table 666
sudo ip route flush cache
sudo iptables -t mangle -A OUTPUT -p tcp --sport 22 -j MARK --set-mark 66
sudo iptables -A INPUT -i tun0 -p tcp -m tcp --dport 22 -j DROP

if [[ "$startvpn" == "1" ]]; then
	sudo service openvpn start
fi

which you can save as e.g. ~/scripts/firewall-config and make executable as root with

sudo chown root:root ~/scripts/firewall-config && sudo chmod 4755 ~/scripts/firewall-config

Note, you don’t need those echoes; I use them just to make sure the script is being executed correctly.

What this script does is disable OpenVPN, create a new table for traffic with marker 66, and configure the firewall. The new table uses the gateway of your home router, normally 192.168.0.1 for eth0, instead of the OpenVPN gateway. We then flush the arp cache to have an unambigious gateway setup.

As incoming traffic on the native interface is unaffected by the OpenVPN, we mark the outgoing traffic with marker 66 on the SSH port, and drop all incoming SSH tcp traffic on tun0 to prevent interface confusion.

If the OpenVPN service was already started (which it probably was), the last check starts the service again now that the traffic is correctly configured.

If you port forward on your home router now to the raspi, you’ll have remote access.

Configure firewall on startup

I tried making this script run in /etc/network/if-pre-up.d/ and /etc/network/if-up.d/ but it was unable to correctly configure before OpenVPN spawns its service, so required one manual stop/start of the VPN before remote connection was allowed.

The solution I settled on was to create a systemd service, by creating the file /etc/systemd/system/firewall-config.service, with the following content

[Unit]
Description=Firewall configuration for SSH behind VPN
After=network.target

[Service]
Type=simple
User=pi
ExecStart=/bin/bash /home/pi/bin/firewall-config

[Install]
WantedBy=multi-user.target

and then executing

sudo systemctl enable firewall-config

to ensure the service is executed on startup.

If you followed to here, just reboot and your raspi is all set and ready.

Useful scripts

This is specifically for the NordVPN .ovpn configuration files for tcp VPN. To make changing country a little bit easier, without leaving the transmission daemon torrenting in the background, I created this little script as ~/scripts/cvpn:

#!/bin/bash
checkIP=0

while getopts "c" opt
do
	case "$opt" in
		c)
			checkIP=1
			;;
		?)
			echo "Usage: cvpn [-c] server-extension"
			exit 1
	esac
done

TSM='transmission-remote --auth [transmission-user]:[transmission-pw]'
shift $(expr $OPTIND - 1 )

echo "Stopping active transmissions..."
$TSM -t all -S
echo "Copying $1 configuration file..."
sudo /etc/openvpn/copy.sh $1
echo "Restarting openvpn service..."
sudo service openvpn restart 

if [ $checkIP -eq 1 ]; then
	echo "Fetching IP information..."
	sleep 6									# approx how long it takes for vpn to setup
	curl ipinfo.io
	echo ""
fi

echo "(Re)Starting active transmissions..."
$TSM -t all -s

Using -c will print the location of the VPN server so you can be sure it worked correctly, and the server-extension for NordVPN would be e.g. uk18.

This script also requires copy.sh in /etc/openvpn/, and the .ovpn files in the directory /etc/openvpn/nordtcp/. The script is as follows

#!/bin/bash
cp /etc/openvpn/nordtcp/$1.nordvpn.com.tcp.ovpn /etc/openvpn/client.conf
sed -i -e 's/auth-user-pass/auth-user-pass .secrets/g' /etc/openvpn/client.conf