🎬 Get Your Media Organized: Jellyfin on Debian 13 with Docker!

Tired of scattered media files and clunky playback? Jellyfin is your free and open-source solution for a personal media server, allowing you to stream your movies, TV shows, music, and photos to any device. This guide will walk you through setting up Jellyfin on a fresh Debian 13 (Trixie) installation using Docker, leveraging an external 2TB hard drive for all your media storage.

We’ll cover everything from preparing your external disk to the final Docker Compose setup and initial Jellyfin configuration.

Prerequisites

Before we begin, ensure you have:

  • A fresh installation of Debian 13 (Trixie).
  • SSH access to your Debian server.
  • A user with sudo privileges.
  • Your 2TB external hard drive connected to the server.
  • Basic familiarity with the Linux command line.

Step 1: Prepare the External Hard Drive

This is a critical step to ensure your media storage is robust and automatically available.

1.1 Identify Your Disk

First, identify your external hard drive. It’s crucial to be absolutely sure to avoid formatting the wrong disk!

lsblk

Look for a disk that matches your 2TB size, likely named sdb, sdc, etc. For this guide, we’ll assume it’s /dev/sdb. Double-check this on your system!

Example output:

NAME   MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS
sda      8:0    0 100G  0 disk
├─sda1   8:1    0   1G  0 part /boot
└─sda2   8:2    0  99G  0 part /
sdb      8:16   0   1.8T  0 disk # <--- This is our 2TB drive (1.8T is approx 2TB)

1.2 Partition and Format the Disk

We’ll create a single ext4 partition on the disk.

⚠️ WARNING: This step will erase ALL data on the selected disk! Proceed with caution!

Start fdisk:

sudo fdisk /dev/sdb # Replace /dev/sdb with your actual disk

Follow fdisk prompts:

  • Type o (create a new empty DOS partition table)
  • Type n (add a new partition)
  • Type p (primary partition)
  • Type 1 (partition number 1)
  • Press Enter for default first sector.
  • Press Enter for default last sector (uses entire disk).
  • Type w (write table to disk and exit).

Format the new partition:

sudo mkfs.ext4 -F /dev/sdb1 # Replace /dev/sdb1 with your new partition

The -F flag forces the format even if it detects an existing filesystem.

1.3 Create Mount Point and Add to /etc/fstab

We’ll create a dedicated directory for your media and ensure the disk mounts automatically on boot.

Get the UUID of the new partition:

sudo blkid /dev/sdb1 # Replace /dev/sdb1

Look for a line like: /dev/sdb1: UUID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" TYPE=“ext4” … Copy the UUID string.

Create the mount point:

sudo mkdir -p /mnt/jellyfin

Add entry to /etc/fstab: Open fstab with a text editor:

sudo nano /etc/fstab

Add the following line to the end of the file. Replace YOUR_UUID_HERE with the actual UUID you copied!

UUID=YOUR_UUID_HERE /mnt/jellyfin ext4 defaults,nofail 0 2
  • defaults: Standard mount options.
  • nofail: Ensures the system boots even if the disk isn’t present (useful for external drives that might sometimes be unplugged, though generally you want them always on for a server).
  • 0 2: Dump frequency (0=never), fsck order (2=check after root).
  • Save and exit (Ctrl+X, Y, Enter for nano).

Mount the disk:

sudo mount -a

This command mounts all entries in fstab that aren’t already mounted. Verify it’s mounted:

df -h /mnt/jellyfin

Set Permissions: Docker containers often run as non-root users. It’s crucial that the user running the Docker container (or the jellyfin user inside the container) has write access to this mount point. For simplicity, we’ll give your primary user and the docker group ownership.

sudo chown -R $USER:docker /mnt/jellyfin
sudo chmod -R 775 /mnt/jellyfin

Replace $USER with your actual username if you’re not logged in as the intended user.

Step 2: Install Docker and Docker Compose

We’ll install Docker Engine and Docker Compose (v2) to manage our Jellyfin container.

2.1 Remove Old Docker Versions (if any)

for pkg in docker.io docker-doc docker-compose podman-docker containerd runc; do sudo apt remove $pkg; done

2.2 Install Docker Engine

Update apt and install dependencies:

sudo apt update
sudo apt install ca-certificates curl gnupg lsb-release -y

Add Docker’s official GPG key:

sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg

Add the Docker repository to apt sources:

echo \
  "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

Install Docker Engine, containerd, and Docker Compose (CLI plugin):

sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y

Add your user to the docker group (so you don’t need sudo for Docker commands):

sudo usermod -aG docker $USER

You need to log out and log back in for this change to take effect! You can type exit and reconnect via SSH, or simply reboot.

Verify Docker installation:

docker run hello-world

You should see a message indicating Docker is working correctly.

Step 3: Deploy Jellyfin with Docker Compose

Now we’ll create a docker-compose.yml file to define and run our Jellyfin container.

3.1 Create Project Directory and Volumes

Create a directory for your Jellyfin Docker files:

mkdir ~/jellyfin-docker
cd ~/jellyfin-docker

Create directories for Jellyfin’s configuration and cache:

mkdir config cache

3.2 Determine PUID and PGID

Jellyfin needs to run with specific user permissions to access your media. We’ll use your current user’s UID (User ID) and GID (Group ID).

id -u $USER
id -g $USER

Note down these numbers. For example, they might be 1000 and 1000.

3.3 Create docker-compose.yml

Create a file named docker-compose.yml in your ~/jellyfin-docker directory:

nano docker-compose.yml

Paste the following content, replacing YOUR_PUID and YOUR_PGID with the numbers you found above.

version: "3.8"

services:
  jellyfin:
    image: jellyfin/jellyfin:latest
    container_name: jellyfin
    environment:
      - PUID=YOUR_PUID # Example: 1000
      - PGID=YOUR_PGID # Example: 1000
      - TZ=America/Los_Angeles # Set your timezone, e.g., Europe/London, Asia/Tokyo
      - JELLYFIN_PublishedServerUrl=http://your_server_ip:8096 # Optional: Your server IP
    volumes:
      - ./config:/config
      - ./cache:/cache
      - /mnt/jellyfin:/data # This maps your external disk into the container
    ports:
      - 8096:8096 # Web UI
      - 8920:8920 # HTTPS (if configured later)
      - 1900:1900/udp # For server discovery
      - 7359:7359/udp # For server discovery
    restart: unless-stopped

Important Notes on the docker-compose.yml:

  • PUID and PGID: These ensure Jellyfin inside the container has the correct permissions to read/write your media files on /mnt/jellyfin.
  • TZ: Set your correct timezone. You can find a list of valid timezones here.
  • volumes:
    • ./config:/config: Stores Jellyfin’s configuration files on your host in ~/jellyfin-docker/config.
    • ./cache:/cache: Stores Jellyfin’s cache files on your host in ~/jellyfin-docker/cache.
    • /mnt/jellyfin:/data: This is the crucial part! It maps your entire external hard drive (mounted at /mnt/jellyfin on your host) to the /data directory inside the Jellyfin container. When you add media in Jellyfin, you’ll point it to /data.
  • ports: These map the container’s internal ports to your host’s ports, allowing you to access Jellyfin from your network.
  • Save and exit (Ctrl+X, Y, Enter for nano).

3.4 Start Jellyfin Container

Now, let’s bring Jellyfin to life!

docker compose up -d
  • up: Starts the services defined in docker-compose.yml.
  • -d: Runs the containers in detached mode (in the background).

You can check the status of your containers:

docker ps

You should see jellyfin listed with status Up.

Step 4: Initial Jellyfin Configuration

With the container running, it’s time to set up Jellyfin through its web interface.

Access Jellyfin Web UI: Open your web browser and navigate to http://YOUR_SERVER_IP:8096. Replace YOUR_SERVER_IP with the actual IP address of your Debian server.

Follow the Setup Wizard:

  • Language Selection: Choose your preferred display language.
  • Create Your User: Set up an administrator username and a strong password. This will be your main account for managing Jellyfin.
  • Add Media Library: This is where you point Jellyfin to your content.
  • Click + Add Media Library.
  • Choose Content type (e.g., “Movies”, “TV Shows”, “Music”).
  • Folder: Click + and navigate to /data (this is the external disk inside the container!). Then, select the specific subfolders where your movies, TV shows, etc., are located (e.g., /data/Movies, /data/TVShows).
  • Preferred metadata language: Choose your preference.
  • Click Ok. Repeat for all your media types.
  • Preferred Metadata Language & Country: Set your preferences.
  • Configure Remote Access: Decide if you want to allow remote connections. For now, you can leave it unchecked if you’re only using it locally.
  • Terms of Service: Agree to the terms.
  • Finish!

Jellyfin will now start scanning your media library and downloading metadata, artwork, and more. This might take some time depending on the size of your collection.

Step 5: Post-Installation (Optional but Recommended)

5.1 Configure a Firewall (UFW)

It’s highly recommended to enable a firewall to restrict access to your server.

Install UFW (if not already installed):

sudo apt install ufw -y

Allow SSH (so you don’t lock yourself out):

sudo ufw allow ssh

Allow Jellyfin ports:

sudo ufw allow 8096/tcp # Jellyfin Web UI
sudo ufw allow 1900/udp # Server discovery
sudo ufw allow 7359/udp # Server discovery

If you enable HTTPS later, you’ll also need:

sudo ufw allow 8920/tcp

Enable UFW:

sudo ufw enable

Confirm with y.

Check UFW status:

sudo ufw status verbose

5.2 Updating Jellyfin

To update Jellyfin, simply pull the latest Docker image and recreate the container:

cd ~/jellyfin-docker
docker compose pull jellyfin
docker compose up -d

5.3 Troubleshooting Can’t access Jellyfin UI:

  • Check your server’s IP address.
  • Ensure the Jellyfin container is running (docker ps).
  • Verify your firewall (UFW) is not blocking ports.
  • Check container logs (docker compose logs -f jellyfin). Media not showing up:
  • Did you add the correct library paths (e.g., /data/Movies) in Jellyfin’s dashboard?
  • Are the file permissions correct on /mnt/jellyfin? The chown and chmod commands earlier are vital.
  • Is the external disk mounted correctly (df -h /mnt/jellyfin)?

Congratulations! You now have a fully functional Jellyfin media server running on Debian 13 with Docker, utilizing a dedicated external hard drive for all your content. Enjoy streaming your media!