Jellyfin Docker Setup with Permissions, Cloudflare Tunnel, DLNA & SMTP (Step-by-Step)

Complete step-by-step guide to install Jellyfin on Docker with correct permissions, Cloudflare Tunnel access, DLNA, and SMTP email notifications.
Jellyfin Docker Setup with Permissions, Cloudflare Tunnel, DLNA & SMTP (Step-by-Step)

🧰 Bulletproof Jellyfin Docker Setup with Local+Cloud Access and Correct Permissions

Running Jellyfin in Docker is a smart and efficient way to manage a home media server. It’s lightweight, portable, and easy to maintain. But improper configuration can lead to playback errors, metadata issues, and failed scans.

In this step-by-step guide, you'll learn how to:

  • ✅ Create a dedicated jellyfin user on the host
  • 📒 Set proper read/write permissions
  • 🌐 Enable LAN & Cloudflare Tunnel access
  • 📧 Configure SMTP email alerts
  • 🔒 Avoid common permission and playback issues

📦 Why Use Docker for Jellyfin?

Docker isolates Jellyfin from your base OS, making it easy to update, backup, and restore. It's especially useful for NAS systems or headless Debian servers. However, Docker containers use internal users, and you must ensure matching permissions on host volumes to avoid errors.

👤 Step 1: Create a Dedicated Jellyfin User

We don’t want to run Jellyfin as root. Let’s create a system-level non-login user:

sudo useradd -r -s /usr/sbin/nologin -d /nonexistent -M jellyfin
id jellyfin

You’ll get something like:

uid=994(jellyfin) gid=989(jellyfin)

We'll use UID 994 and GID 989 in the Docker stack.

📓 Step 2: Prepare Docker Volumes and Media Folder

We'll use named Docker volumes for /config and /cache, and a bind-mounted host directory for media:

  • /var/lib/docker/volumes/jellyfin_jellyfin_config/_data
  • /var/lib/docker/volumes/jellyfin_jellyfin_cache/_data
  • /srv/store/Media (your actual media path)

🔐 Step 3: Set Correct Permissions

This is the most crucial step. Jellyfin inside the container runs as UID 994, so all volumes and media folders must allow that UID to access them.

✅ Fix permissions with the following commands:

sudo chown -R 994:989 /var/lib/docker/volumes/jellyfin_jellyfin_config/_data
sudo chown -R 994:989 /var/lib/docker/volumes/jellyfin_jellyfin_cache/_data
sudo chown -R 994:989 /srv/store/Media

sudo find /var/lib/docker/volumes/jellyfin_jellyfin_config/_data -type d -exec chmod 750 {} \;
sudo find /var/lib/docker/volumes/jellyfin_jellyfin_cache/_data -type d -exec chmod 750 {} \;
sudo find /srv/store/Media -type d -exec chmod 750 {} \;

sudo find /var/lib/docker/volumes/jellyfin_jellyfin_config/_data -type f -exec chmod 640 {} \;
sudo find /var/lib/docker/volumes/jellyfin_jellyfin_cache/_data -type f -exec chmod 640 {} \;
sudo find /srv/store/Media -type f -exec chmod 640 {} \;
sudo find /srv/store/Media -type f -exec chmod 750 {} \;

🧱 Step 4: Docker Compose Stack with SMTP and DLNA

version: '3.8'

services:
  jellyfin:
    image: jellyfin/jellyfin:latest
    container_name: jellyfin
    ports:
      - "8096:8096"
      - "7359:7359/udp"
      - "1900:1900/udp"
    user: "994:989"
    restart: unless-stopped
    volumes:
      - jellyfin_config:/config
      - jellyfin_cache:/cache
      - /srv/store/Media:/media
    environment:
      - TZ=Asia/Kolkata
      - JELLYFIN_SMTP_SERVER=smtp.example.com
      - JELLYFIN_SMTP_PORT=587
      - JELLYFIN_SMTP_USERNAME=your-email@example.com
      - JELLYFIN_SMTP_PASSWORD=your-smtp-password
      - JELLYFIN_SMTP_FROM_ADDRESS=your-email@example.com
      - JELLYFIN_SMTP_USE_SSL=false
      - JELLYFIN_SMTP_USE_TLS=true

volumes:
  jellyfin_config:
  jellyfin_cache:

🌐 Step 5: Access Jellyfin on LAN and Cloud

You can access Jellyfin via:

  • LAN: http://192.168.0.x:8096
  • Cloudflare Tunnel: https://jellyfin.yourdomain.com

🚪 Step 6: Auto-Fix Permissions on Boot (Systemd)

Let’s make sure your permissions are fixed automatically every time the NAS boots.

Step 1: Create Fix Script

sudo nano /usr/local/bin/jellyfin-fix-perms.sh

Paste:

#!/bin/bash
chown -R 994:989 /var/lib/docker/volumes/jellyfin_jellyfin_config/_data
chown -R 994:989 /var/lib/docker/volumes/jellyfin_jellyfin_cache/_data
chown -R 994:989 /srv/store/Media

find /var/lib/docker/volumes/jellyfin_jellyfin_config/_data -type d -exec chmod 750 {} \;
find /var/lib/docker/volumes/jellyfin_jellyfin_cache/_data -type d -exec chmod 750 {} \;
find /srv/store/Media -type d -exec chmod 750 {} \;

find /var/lib/docker/volumes/jellyfin_jellyfin_config/_data -type f -exec chmod 640 {} \;
find /var/lib/docker/volumes/jellyfin_jellyfin_cache/_data -type f -exec chmod 640 {} \;
find /srv/store/Media -type f -exec chmod 640 {} \;
find /srv/store/Media -type f -exec chmod 750 {} \;

Then make it executable:

sudo chmod +x /usr/local/bin/jellyfin-fix-perms.sh

Step 2: Create systemd service

sudo nano /etc/systemd/system/jellyfin-perms.service

Paste:

[Unit]
Description=Auto-fix Jellyfin volume permissions at boot
After=local-fs.target docker.service
Wants=docker.service

[Service]
Type=oneshot
ExecStart=/usr/local/bin/jellyfin-fix-perms.sh
RemainAfterExit=true

[Install]
WantedBy=multi-user.target

Step 3: Enable and Start

sudo systemctl daemon-reexec
sudo systemctl daemon-reload
sudo systemctl enable jellyfin-perms.service
sudo systemctl start jellyfin-perms.service

Check status:

systemctl status jellyfin-perms.service

💪 Final Thoughts

With Docker, Jellyfin becomes easy to manage. With permissions automated and SMTP configured, you now have a self-healing, production-grade media server.

✅ Reliable, ✅ Secure, ✅ LAN + Remote, ✅ Ready to Scale

If you want GPU acceleration, Cloudflare Zero Trust, or media backups next, follow along — more posts coming soon!

About the author

Saurab Thakur
Student, Photographer by Hobby, Blogger / Content Writer

Post a Comment