How to make a home media server with torrent support over a secure VPN using a headless Raspberry PI 5

Let's walk you through every step of the way to getting this done. I've used this tutorial to eat my own dog food twice now, so it's getting pretty polished.

How big of a computer do you need?

Media servers are bound by processor speed and, of course, storage space. They are not memory hogs, they don't need 16GB to operate, but the faster CPUs will serve you well. That's one of two big reasons why I went with a Raspberry PI 5, for the substantially faster CPU. The second reason was so that I could have direct support to run everything off of a sollid state drive. I started with a cheap $20 nvme and today I'm following these instructions to update that to a 4Tb internal drive. I'm doing this to update storage space while simultaniously keeping everything neat and tidy in one box instead of hanging external hard drives off my USB ports. I'm extremely pleased with how my media server worked out and now I'm upgrading it.

One thing you do need for the operating system is 64 bit. The PI has 32 bit options available, do not use those.

What do you need to get started:

Raspberry Pi 5, 4GB ram, $65, for $90 you can get 8GB, and for $130 you can get the 16GB

https://www.amazon.com/dp/B0CK3L9WD3

If your Pi doesn't come with a power supply you will need one. The Pi 5 is power hungry, don't just plug any USB C power into it. $13

https://www.amazon.com/dp/B0CQLNP9DZ

You are also going to need a micro-HDMI adapter, careful there are several other small sizes of HDMI to get confused with. $9

https://www.amazon.com/dp/B08P5SDCVT

You could certainly make this work well on a Raspberry Pi 4 using a Micro SD card.

I put my Pi 5 into the Argon NEO 5 M.2 NVME PCIE Case, it's great looking, most of it is aluminum, and it provides the adapter circuit needed to attach a solid state drive. Running off a solid state drive is much faster and more long term stable than an SD card.

https://www.amazon.com/dp/B0CRH8V95R

You will need a solid state drive (unless you just want to use an SD card). Do not screw up and get a SATA drive. You need an M.2 SSD PCIe, the 2280 in the title refers to its length, this is the full size (longest) one and takes up the full space in the Argon case. It isn't very big, just a 256GB, but I wasn't honestly sure this project was going to work and this only Cost $20

https://www.amazon.com/dp/B0DKFG4JX9

How do you burn the Raspberry Pi 64 bit image onto the solid state drive? Just one more complexity of having gone the SSD route instead of the tried and true method of runnig a Pi off of an SD card. You are going to need an adapter like this one. Cost $17

https://www.amazon.com/dp/B07MNFH1PX

Installing the operating system

Put the SSD drive into the enclosure / adapter and plug it into your PC.

Use the Raspberry Pi Imager to burn the ISO to your SSD drive.

https://www.raspberrypi.com/software/

There are very important options you need to select in order to set this up as a remote machine in your network closet. Its a little more forgiving if it is on your desk with easy access to a keyboard and mouse.

Select the correct device, either a Pi 5 or a Pi 4 depending on what you have.

"Choose OS", you must choose a 64 bit OS, this will not work with a 32 bit. 64 Bit good, 32 bit bad. You could just pick the "recommended" on the main screen, it will come with a graphical desktop and web browsers and other tools, none of which we need for our project. I would go into "Raspberry Pi OS (other)" and select "Raspberry Pi OS Lite (64-bit)", this will just get you the terminal view which is what we need.

In the custom settings I'm setting the hostname to "pi5" and the user to "pi" and a password I won't forget and should probably write on the pi case. I'm not configuring wireless, I did set my locale settings and keyboard.

If you want SSH to work: look at the Services tab in customization settings, check "Enable SSH" and "use password authentication", be certain to remove any value from "set authorized keys", there is a bug where if that is still populated but disabled then ssh still won't work for password. Skipping these steps will have you pulling the drive out and doing it again if you need remote access.

Be certain to click the "Yes" button on the "use customization" to proceed.

Once you are done writing to the SSD stick, remove it from the adapter and install it in your Pi case.

Setting up your static IP address

You need to log into your pi at least once with a keyboard and monitor in order to set the static IP address. You aren't going to want the IP address of your Pi to change every time it gets rebooted. All the connected devices are going to want a consistent address to connect to. This step is also critical if you will be remoting into your Pi to manage it.

A lot of the confusion of setting a static IP comes from the extra information you need to know. You have to set three things, one is the IP address you desire, one is the gateway IP address of the router, and one is the address of the DNS servers. They could have made that easier, but if you know going in that you need those things then it isn't at all hard.

Do not go hacking at any text files regardless of what you find on the internet. Those instructions get stale, and they never seem to work. The instructions I found most reliable are to use the "nmtui" command. There is a passable article for doing this at

https://pimylifeup.com/raspberry-pi-static-ip-address/

It looks intimidating, but really you collect your gateway IP address ahead of time, decide on a static IP, and you plug them into the interface. The DNS server IP addresses are easy, just use the known ones like googles 8.8.8.8 and 8.8.4.4

run

ip route | grep default

this tells you the IP address of your gateway. Make a note of the first IP mentioned in this string. Mine (and many peoples) is 192.168.1.1

I decided to set my static IP to 192.168.1.222 which matches the first three number in my gateway "192.168.1" and is a high enough number not to be confused with other devices, and it's easy to remember, "222" is the highest number where all the numbers repeat.

Thats the hard part, getting those IP addreesses written down. Now just run the commane
sudo nmtui
To configure the network. Edit the ethernet wired connection set the IPv4 to manual, add "address" 192.168.1.222, Set gateway to 192.168.1.1, added the google primary dns server 8.8.8.8, google secondary dns server 8.8.4.4 and save.

if you want to move the Pi to a server closet now, shutdown the pi "sudo shutdown now", plug the pi ethernet into the main router, the only wires going into the pi now are power and ethernet and it is in the network closet. Otherwise you can continue with the tuturail with the Pi at your desk.

use putty to ssh to 192.168.1.222 naming that entry something memorable like "Pi-5"

sudo apt update

sudo apt upgrade

Install jellyfin

https://pimylifeup.com/raspberry-pi-jellyfin/

I use the free media server Jellyfin. You could use the paid Plex, but lets face it if you got this far trying to setup a media server on a Pi instead of buying a $400 NAS and another $400 in drives, you are trying to save some money and you aren't goig to pay for the Plex subscription.

We could add jellyfin to the docker container we will setup in a momemt, but its easy just to install it and leave it separate.

sudo apt install apt-transport-https lsb-release

curl https://repo.jellyfin.org/debian/jellyfin_team.gpg.key | gpg --dearmor | sudo tee /usr/share/keyrings/jellyfin-archive-keyring.gpg >/dev/null

echo "deb [signed-by=/usr/share/keyrings/jellyfin-archive-keyring.gpg arch=$( dpkg --print-architecture )] https://repo.jellyfin.org/debian $( lsb_release -c -s ) main" | sudo tee /etc/apt/sources.list.d/jellyfin.list

sudo apt update

sudo apt install jellyfin

you can now complete your setup on a browser. Go to a browser and navigate to

http://192.168.1.222:8096/

I deselected "allow remote connections" and "enable autmatic port mapping" and it still showed up on my TV.

go through the web setup, on the "setup your media libraries" page click to add media library. you are going to want to read up on running a jellyfin server, putting different categories of movies into separate folder (don't nest the folders, and don't try to create an "all" category that watches the root folder, things get wonky).

Create a folder on your PI named /media/drive1/content/family. Trust me, organize early, create the action, superhero, fantasy, family, shows, etc folders now. It allows you to make nice libraries on your jellyfin. Whatever you do, create the /media folder now. It's important to sync that with the torrents in the next step. We'll download a sample movie into the /family folder in a bit.

Enter a content type (probably Movies, maybe Shows), add a "folders" pointing to an existing drive folder

click next

Install your TV / device app

Once done installing Jellyfin, go to your smart TV or device and add the "Jellyfin" app. When you start the app it should automatically see your jellyfin server. If not then manually enter it

http://192.1681.222:8096

Login with your jellyfin credentials

Torrenting your files safely

You may not want to expose your internet IP address when you torrent, especially if you torrent copyright files, which is wrong and illegal and don't do that.

Adding the VPN and the "transmission" torrent client.

Create a VPN

I haven't found a VPN that did a good job of allowing external users to connect to my torrents so that I could seed the torrents for other users. Seeding is very important for you to maintain a good download to upload ratio with your torrent community. If everyone just downloaded then there would be no uploading, so you need to either find a paid service which lets you leech as much as you need, or you need a good VPN which won't give you grief about incoming connections. I spent an enormous amount of time trying to make dedicated VPNs work before I finally got this all working with a simple VPS (virtual private server). For 5 pounds/mo you can have your own VPS to do with as you will, including running a simple VPN service. You can use any cheap VPS you like, you can easily find one that takes paypal and credit cards. The one I like only accepts crypto, so that can be an added hurdle. Setting up a new VPN is as trivial as paying a company $5/month for an IP address and login. If you want to use snowcore, follow these instructions and have some crypto handy, otherwise setup a super cheap VPS wherever you like and then skip ahead to "Install the VPS service on the VPN"

Go to

https://snowcore.io/

click Dashboard

click "Register" to be given a uniqie ID number (there are no passwords, just big ID numbers) and login. REMEMBER that number! Write it down somewhere safe, it is your only way into your server. If you forget the number then you've lost the server.

click "vps" or go to https://snowcore.io/client/kvm

select KVM-1 for 5 pounds/mo

the snowcore checkout process is to take funds from your snowcore account, its a bit akward but you first have to go to

https://snowcore.io/client/payments

and deposit some funds. Again the interface isn't intuitive, there is an "amount" field on this page you need to fill out, and the amount is in british pounds. If you want to commit to just one months worth for now, add 5 pounds.

Now "pending payments" shows up at the bottom. "View" the payment, send crypto to the address and wait for funds to clear.

Now you have funds available to pay for your new server in your shopping cart. Go pay for the server and it will be available in your dashboard.

In the dashboard "View" the server.

Make note of the IPV4 address on the right side.

Click "view password" to view the login password. Copy/paste that somewhere, you are going to need it soon.

Log out of snowcore (click the user icon in the top right).

SSH (putty is a good choice for this) to the IP address of your new VPS.

login as root, use the password you copied. If you have the password in your clipboard you can right click in putty to paste it but putty doesn't display any change in a password field so it isn't obvious you pasted anything. When you get to the password prompt, right click and then hit enter, if that doesn't work then type the password.

Install the VPS service on the VPN

Now we are going to use the script from

https://github.com/angristan/openvpn-install

curl -O https://raw.githubusercontent.com/angristan/openvpn-install/master/openvpn-install.sh

I'm also hosting it at openvpn-install.sh

chmod +x openvpn-install.sh

./openvpn-install.sh

follow the prompts to install the new OpenVPN service. Its super easy. Pick a fun name, I called mine SnowWhite. select the default "1) Add a passwordless client"

Congratulations, you are running your own private VPN, you could add users and share with friends and family if you wanted. Honestly I don't because family and friends shouldn't be trusted to stay out of trouble, so I just let them use my jellyfin remotely.

So the important part here is the new text file in your current directory called "SnowWhite.ovpn". You want to transfer that to your PI machine. On your pi machine run

scp root@123.123.123.123:/root/SnowWhite.ovpn .

where 123.123.123.123 is replaced with your VPS IP address

connect to the VPN

ok the hard part is over and I've got something easy for you now. I've set this all up to run in a container service called Docker, and I've got simple config files for you. From your PI run

curl -sSL https://get.docker.com | sh

sudo usermod -aG docker $USER

nano docker-compose.yml

paste the following into docker-compose.yml, don't mess up any of tabbing or formatting.

Click to open my docker-compose.yml

replace SnowWhite with whatever you called it, be sure to get the path right.

then type

ctl-O enter

ctl-X

don't get cute with the transmision volumes, that way lies monsters. The left part /media is your local media folder which mounts to transmissions internal representation on the right called /media. Subdirectories get confusing, do they go on the left, do they go on the right. Just keep it simple and make them both the same. This is why you created a /media folder earlier.

this sets up a docker container in which an app called gluetun runs a VPN and creates a network_mode "service:gluetun"

notice the curl command and the transmission application both use network_mode: "service:gluetun"

Try running

docker compose up

If there are still some permissions issues you can fix it or you can just use sudo

sudo docker compose up

which will start everything in your current window and you'll need a new window to interact

I like to start everything in the current window to see that everything looks healthy there, otherwise you can add the -d flag to that command to not take up your window

Now to see a lot of this work come together, run this command:

docker compose run --rm curl ipinfo.io

you will connect to the docker curl we defined in our compose and you'll see you are connectiong from some exotic far away place like Amsterdam.

Similarly, the transmission application is up and running and you can hit it at

http://192.168.1.222:9091/transmission/web/

their interface sucks. A new one can easily be dropped in place but when I used the "Transmissionic-webui-v1.8.0.zip" then I wasn't able to upload .torrent files, so keeping it simple for now.

now that you have run transmission once, bring the docker container down

docker compose down

and you will find a folder named transmission-config

inside you will find settings.json

nano settings.json

change the entry for "download-dir" to "/media/drive1/content" and the transmission web client will default to that locaton when you give it torrents.

change the entry for incomplete-dir to /media/drive1/incomplete

write the output ctl-o enter ctl-x

now create the incomplete folder

mkdir /media/drive1/incomplete

now bring docker back up. Whatever permisison thing was plauging us earlier was just for pulling new containers down from the cloud, docker seems to start without sudo now, and we'll use the -d flag to start it in the background

docker compose up -d

Fun fact, that "restart: always" in the docker-compose is supposed to run the docker container when the PI is booted up so you don't have to start the container up each time. I haven't seen if that actually works yet.

Download a torrent file from somewhere, this free public domain one will do

http://www.publicdomaintorrents.com/bt/btdownload.php?type=torrent&file=Betty_Boop_My_Friend_the_Monkey.avi.torrent

In the transmission web app click on the folder with the Plus + button in it, click "choose files" locate your downloaded .torrent file or enter the url.

change the destination folder to /media/drive1/content/family

check that the message next to the destination folder changes to "x tb free" so you know it at least has read permission.

wait a few seconds and your download will appear.

Wait a few more seconds and it will successfully start writing to the download folder

If you are using a torrent site to find your torrents, it probably has a page for what you are "seeding" or uploading back to other users. Someone, somewhere seeded that Betty Boop file, and now hopefully you are seeding it as well. Notice the IP address on your torrent site, it says the same thing as when you ran the
docker compose run --rm curl ipinfo.io
command earlier. Somewhere that is not your local internet provider, but rather the address of your VPN service.

In the Jellyfin admin Dashboard, click "Scan all libraries" to get jellyfin to notice the new movie.

Grab some popcorn, gather the family, and watch your new movie