Jellyfin From Scratch: How to Build a Complete Media Server on Linux Mint (Docker, Nginx, and Letβs Encrypt)
Start from a clean OS and end with your own secure, self-hosted streaming platform β complete with HTTPS access, remote streaming, and full media organization.
Questions unlock answers.
π§ Introduction
Jellyfin is a free, open-source media server that lets you organize and stream your movies, shows, and music to any device. Think of it as your personal Netflix β except you control everything.
In this guide, youβll start from a clean Linux Mint installation and finish with a fully working Jellyfin server running inside Docker, served securely through Nginx with Letβs Encrypt SSL certificates, protected by Fail2ban, and accessible anywhere through a DuckDNS domain.
This tutorial uses CPU-only transcoding (no GPU acceleration) and follows current Docker Compose v2 standards. This means, if want to use your GPU to do all the heave lifting, I ain't gunna show you that here but, you can still use this tutorial to get your server up and running then, configure your GPU later.
π§° Prerequisites
-
A clean install of Linux Mint (based on Ubuntu 20.04 or later)
-
Sudo privileges
- Install SSH (if you want to connect remotely)
- Vim - Text editor (or which ever you prefer)
-
An active internet connection
-
A DuckDNS account and domain (e.g.,
myserver.duckdns.org) -
Some media files stored locally or on a mounted drive. I do NOT go over how to mount a drive!
- Router: port forwarding
- Ports 22, 80 and 443
Doing some of the Prereqs:
- Install your OS. I ain't helping with that part.
- If you even want to have remote access, Check this one out to do some sudo (super user) and some SSH (remote login) stuff.
- Install VIM text editor:
sudo apt install vim
- You will need a domain name for this. You can use your own custom one but, if you don't one, get one. duckdns.org is a good free source for that. Ill be using mint1.duckdns.org for this example.
- Where is your media files right now? If you haven't already, to but them where you are going to be using them at. /media is a good spot or, if you are mounting a drive, /mnt is also a good spot. i'll have a mounted RAID drive/s and will be mounting it in /mnt/media
I ain't helppen you with this neither so... if need be, now is a good time to pause and come back once you know where your stuff will be stored. - Your Router:
If you want to have remote access by SSH from other computer, install it. You use the link above or go here if you don't know how.
Either way, you will need to open up ports 80 and 443. This will expose your computer (and network) to the world.
Once you are able to complete those few tasks, we can then continue with getting a Jellyfin server up and running.
π§± Step 1 β System Preparation
Start by updating your system and installing a few required packages.
sudo apt update && sudo apt upgrade -y
...give it a minute to do its thang.
sudo apt install -y ca-certificates curl gnupg lsb-release ufw fail2ban
.........This might take another quick minute. If you can any prompts, say "yes" or "y".
Enable the firewall and allow only essential services: (run each line separately)
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow OpenSSH
sudo ufw allow 80,443/tcp
sudo ufw enable
Check status:
sudo ufw status
You should see SSH, HTTP, and HTTPS allowed. Did it work?
π³ Step 2 β Install Docker and Docker Compose
Install Docker Engine and the Compose plugin using official repositories: These are to separate programs that work in tandem. "Docker" and "Docker Compose"
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
sudo systemctl enable docker
sudo systemctl start docker
Verify installation:
docker --version
docker compose version
They should both tell you what version of Docker & Docker Compose you have.
For the time being, leave this be. We will come back to it.
π Step 3 β Create Directory Structure
Where do you want your Jellyfin to live? For this, weβll keep Jellyfin and related configs in /opt/jellyfin.
sudo chown -R $USER:$USER /opt/jellyfin
sudo mkdir -p /opt/jellyfin/{config,cache,media,nginx,certbot}
sudo mkdir /mnt/media
sudo mount /dev/sdX1 /mnt/media
sudo ln -s /mnt/media /opt/jellyfin/media
Or, you could mount directly to the directory:
sudo mount /dev/sdX1 /opt/jellyfin/media
You need this permanent so, go do that in fstab.
βοΈ Step 4 β Create the Docker Compose File
Create the file:
This is a .yml file. Don't know the language? That's OK. I gotchew.
sudo vim /opt/jellyfin/docker-compose.yml
Paste this configuration:
above, we made a bunch of directories. config, cache, media, nginx, certbot
Make sure that the directories in here match the ones you made.
Press "i" to edit the text. Paste this in:
services:
jellyfin:
image: jellyfin/jellyfin:latest
container_name: jellyfin
environment:
- PUID=1001
- PGID=1001
- TZ=America/Los_Angeles
volumes:
- /home/user/jellyfin/config:/config
- /home/user/jellyfin/cache:/cache
- /home/user/jellyfin/media:/media
ports:
- 8098:8096
restart: unless-stopped
Save and exit Esc: wqenter
π Step 5 β Configure Nginx Reverse Proxy
Install Nginx.
sudo apt install nginx -y
server {
server_name Your.customesite.com;
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass http://localhost:8096; #add your own port number if its not this
}
#place holder for certpot later. It will maintain your SSL cert for you.
# you can delete this line and the one above it once you get the certbot running.
}
Your.customesite.comwith your actual DuckDNS (or other custom) domain.localhost:8096with your current port, if you have changed it.
Esc: wqenterStart/Test it
sudo systemctl start nginx
sudo systemctl enable nginx
π Step 6 β Get Your SSL Certificate with your domain and Certbot
First, make sure your DuckDNS domain is pointed to your public IP. If you haven't already, go to your domain dashboard and make sure.
Go here to see how to get a an automated SSL cert.
Inside that page, go through the "Certbot : Auto SSL certifications." section. Then come back to continue.
π Step 7 β Start Up Everything
Now bring up all containers:
Be in the directory where your .yml file is located. (step 4)
docker compose up -d
Check containers:
docker ps
Visit your server:
You should see the Jellyfin setup wizard π
Don't forget.
Questions unlock answers.
Stay curious, my frens.