Welcome! Strap in because this is gonna be a long ride.
To preface, I had an existing media server that I broke some permissions and reinstalling was the only option. I had an existing RAID 0 setup with lots of data I did not want to lose, plus a standalone SSD. So, without further adieu, here we go!
Installing Ubuntu Server
I chose Ubuntu Server because Ubuntu has a great deal of community support and I have no need for a desktop GUI.
Download the ISO from here. You may have to choose 'Option 3' to actually get a download. At the time of writing, I'm using 20.04.1, so take that into account.
My tool of choice for burning ISOs is balenaEtcher.
Plug in the USB, boot to it, and follow setup. Make sure you enable the SSH server AND NO LVM ON THE SSD. Check to make sure the full capacity of the SSD is mounted to /
and then you're good to go. Finish the setup, remove the USB, and reboot. Now we'll switch to SSH.
Configuring SSH
Port 22 sucks, but we need to login with it. Connect to the server on port 22 with the credentials you added during install.
Open the port in the firewall
sudo ufw allow 8364/tcp
Open the SSH config file and change the port used
sudo nano /etc/ssh/sshd_config
Find the line containing Port 22
, uncomment, and change to Port 8364
. Save (ctrl x
).
Restart the SSH server and then reconnect on your client.
sudo systemctl restart ssh
Drive Mounting
Find the UUID of the drive:
sudo blkid
Add your drive to /etc/fstab
(BE CAREFUL, THIS CAN BRICK STUFF):
sudo nano /etc/fstab
E.g:
UUID=ccc56606-385e-4a16-89c4-7f1513ab1641 /home ext4 defaults 0 0
Reboot the system and your drive your be properly mounted.
Docker
First, update your system:
sudo apt update
sudo apt upgrade
Instead of repeating things, go follow the official Docker tutorial here. Just follow the 'Install using the repository' and 'Install Docker Engine' sections.
Then, install Docker Compose by following the tutorial here.
The next part is taken mostly from Smart Home Beginner.
We will add the current user to the docker group to simplify some things in the future.
sudo gpasswd -a $USER docker
Activate the changes using the following:
newgrp docker
Portainer
Portainer is our docker management solution. Yes, I have serious issues with it but currently don't have an alternative. Maybe this will change in the future, but here we are.
Run the following commands to get Portainer up and running:
docker volume create portainer_data
docker run -d -p 8000:8000 -p 9000:9000 --name=portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce
docker run -d -p 9001:9001 --name portainer_agent --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v /var/lib/docker/volumes:/var/lib/docker/volumes portainer/agent
Open a browser and go to your computer's IP with the port 9000. For me, that's http://192.168.1.50:9000
. Chose a username and password, then create user.
Choose "Docker" and press "Connect".
Now that you are in the web panel, click on 'local' in the middle, and then the 'Stacks' tab on the left. Click 'Add stack' and give it a name such as "main_stack". Paste in the following config and adjust it to fit your needs.
---
version: "2.3"
services:
organizr:
image: linuxserver/organizr
container_name: organizr
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
volumes:
- ${USERDIR}/organizr:/config
ports:
- 9983:80
restart: unless-stopped
watchtower:
container_name: watchtower
restart: always
image: containrrr/watchtower
volumes:
- /var/run/docker.sock:/var/run/docker.sock
command: --schedule "0 0 4 * * *" --cleanup
radarr:
image: linuxserver/radarr
container_name: radarr
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
volumes:
- ${USERDIR}/radarr:/config
- ${USERDIR}/media/movies:/movies
- ${USERDIR}/downloads:/downloads
ports:
- 7878:7878
restart: unless-stopped
sonarr:
image: linuxserver/sonarr
container_name: sonarr
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
volumes:
- ${USERDIR}/sonarr:/config
- ${USERDIR}/media/tv:/tv
- ${USERDIR}/downloads:/downloads
ports:
- 8989:8989
restart: unless-stopped
duckdns:
image: linuxserver/duckdns
container_name: duckdns
environment:
- TZ=${TZ}
- SUBDOMAINS=kyleserver
- TOKEN=326ab158-e842-4d0e-aa20-233e0f7e51e3
restart: unless-stopped
minecraft-creative:
container_name: minecraft-creative
image: itzg/minecraft-server
environment:
EULA: "true"
TYPE: PAPER
VERSION: 1.16.2
CONSOLE: "false"
LEVEL_TYPE: "flat"
ports:
- 25566:25565
volumes:
- ${USERDIR}/minecraft-creative:/data
restart: unless-stopped
minecraft-survival:
container_name: minecraft-survival
image: itzg/minecraft-server
environment:
EULA: "true"
TYPE: PAPER
VERSION: 1.16.2
CONSOLE: "false"
MEMORY: 2G
ports:
- 25565:25565
volumes:
- ${USERDIR}/minecraft-survival:/data
restart: unless-stopped
qbittorrent:
image: linuxserver/qbittorrent:14.2.5.99202004250119-7015-2c65b79ubuntu18.04.1-ls93
container_name: qbittorrent
network_mode: "service:gluetun"
volumes:
- ${USERDIR}/docker/qbittorrent:/config
- ${USERDIR}/downloads:/downloads
restart: unless-stopped
environment:
- PUID=${PUID}
- PGID=${PGID}
- TZ=${TZ}
- UMASK_SET=002
- WEBUI_PORT=4545
gluetun:
image: qmcgaw/private-internet-access
container_name: gluetun
cap_add:
- NET_ADMIN
network_mode: bridge
ports:
- 8888:8888
- 8388:8388
- 8388:8388/udp # Shadowsocks
- 8001:8001
- 4545:4545
- 6881:6881
- 6881:6881/udp
volumes:
- ${USERDIR}/gluetun:/gluetun
environment:
- VPNSP=surfshark
- TZ=${TZ}
- USER=USERNAME
- PASSWORD=PASSWORD
- REGION=Canada Toronto
restart: unless-stopped
Next, run id
and note your uid and pid. We will input these as PUID and PGID in the "Environment" section.
PUID=1000
PGID=1000
TZ="America/Toronto"
USERDIR="/home/user"
Add any environment variables that you need NOW as I don't believe these can be changed in the future.
Click 'Deploy the stack'.
Currently, qbittorrent has an issue with mismatched torrent names, that's why it's using a custom image version. If it gets resolved in the future, remove everything after the colon.
These are simply the containers I use for everything I do. The 'gluetun' container connects to Surfshark VPN and routes the qbittorrent container's traffic through, allowing a normal container to connect to a VPN. This can be done with any container by moving its ports to gluetun and setting its network_mode
to "service:gluetun". After that, go and check each container to make sure it's working.
Jellyfin
Welp, this is gonna be a fun one. If you don't want to do hardware transcoding with a GPU, simply add a standard container to the above compose file. Otherwise, come along for this hell of a ride. There is no guarantee that some of these steps aren't redundant as I have no clue how any of this works. But, ideally, everything will work by the end of this.
Firstly, we need to install the NVIDIA drivers. I'm using a GTX 1050ti but it should work for any NVIDIA card 10-series or newer.
Run these commands first to disable Nouveau:
sudo bash -c "echo blacklist nouveau > /etc/modprobe.d/blacklist-nvidia-nouveau.conf"
sudo bash -c "echo blacklist nouveau > /etc/modprobe.d/blacklist-nvidia-nouveau.conf"
What is Nouveau and why are we disabling it? How dare you ask! Subsequently, I have no clue but it's what we gotta do.
Reboot.
Install DMKS:
sudo apt install dkms
Follow the instructions here to install the drivers. Additional Notes:
- Update the version number in the other commands
- Each command needs the be run with
sudo
Click 'Yes' for everything, and after exiting the GUI, reboot, then run the test commands.
Install ffmpeg:
sudo apt install ffmpeg
Next, we need to setup the NVIDIA Container Toolkit. Follow the official instructions here.
Now the GPU should be good to go! Next, we need to actually setup Jellyfin. Going back to SSH, go to your home dir (cd
).
Create a new docker compose file called docker-compose.yml
and fill it with the following:
version: "2.3"
services:
jellyfin:
image: linuxserver/jellyfin
container_name: jellyfin
network_mode: "host"
runtime: nvidia
environment:
- PUID=1000
- PGID=1000
- TZ=America/Toronto
- NVIDIA_VISIBLE_DEVICES=all
volumes:
- /home/user/jellyfin:/config
- /home/user/media/tv:/data/tvshows
- /home/user/media/movies:/data/movies
ports:
- 8080:8096
- 7359:7359/udp
restart: unless-stopped
Run docker-compose up -d
and Jellyfin will be running. Counterintuitvly, go to port 8096 on your server's IP and login.
Change Jellyfin Settings
- Go to Settings > Advanced > Networking. Change "Local HTTP port number" and "Public HTTP port number" to 8080.
- Go to Server > Playback and under "Hardware acceleration" choose 'Nvidia NVENC'. Select which files you want to decode.
- Change 'ffmpeg path' to
/usr/bin
Restart Jellyfin from Portainer, and you're good to go!
Conclusion
It was a lot of work, but hopefully everything works. Remember, DuckDuckGo and StackOverflow are your friends. If something doesn't work, let me know below and I'll do my best to help.
Good luck and stay curious!