Skip to main content

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.

🧠 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

  • 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


🧱 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
Enable and start Docker: 
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.


📂 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}
Where is your media going to be stored? Mount your media drive to /opt/jellyfin/media. Or, if you already have a local address, you can put it there.
We are not going over how to mount a drive in this tutorial so, if you don't know how to do that part, go learn now, and come back. This example may not make sense to you.
Example:
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
: 
wq
enter


🌐 Step 5 — Configure Nginx Reverse Proxy

Install Nginx.

sudo apt install nginx -y
Now locate the config file so we can make a virtual reverse proxy.
Will probably be at /etc/nginx/sites-available/
Edit the file "default" 
Paste the following:
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.
  
}
🔧 Replace:
  • Your.customesite.com with your actual DuckDNS (or other custom) domain.
  • localhost:8096 with your current port, if you have changed it. 
Save and exit 
Esc
: 
wq
enter

Start/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
Can you see it running?

Visit your server:


https://yourdomain.duckdns.org  Or whatever your domain name is. Go see it!

You should see the Jellyfin setup wizard 🎉

***need to check out***  
*install nginx

prereq: If you "run" i mean...