Setting Up Jellyfin as a Self-Hosted Media Server

In this post, I share how I set up Jellyfin, a free and open-source media server, on my home server using Docker, integrated with Caddy for HTTPS and a custom subdomain.

🎯 Goals

  • Host Jellyfin locally using Docker
  • Access the media server via https://tv.wallaceat.me
  • Enable HTTPS with automatic certificate management using Caddy

📁 Project Structure

/home/wallace/server/jellyfin
├── docker-compose.yml
├── media/
├── media2/
└── fonts/

🧩 Docker Compose File

This is the docker-compose.yml I used to spin up Jellyfin:

version: "3.8"

services:
  jellyfin:
    image: jellyfin/jellyfin
    container_name: jellyfin
    user: 1000:1000
    volumes:
      - /home/wallace/server/jellyfin/config:/config
      - /home/wallace/server/jellyfin/cache:/cache
      - type: bind
        source: /server/jellyfin/media
        target: /media
      - type: bind
        source: /server/jellyfin/media2
        target: /media2
      - type: bind
        source: /mnt/torrents
        target: /torrent
        read_only: true
      - type: bind
        source: /path/to/fonts
        target: /usr/local/share/fonts/custom
        read_only: true
    restart: unless-stopped
    environment:
      - JELLYFIN_PublishedServerUrl=https://tv.wallaceat.me
    extra_hosts:
      - 'host.docker.internal:host-gateway'
    networks:
      - local

networks:
  local:
    external: true

🔒 Caddy Reverse Proxy

I configured the reverse proxy in my existing Caddy container. Here’s the snippet added to the Caddyfile:

tv.wallaceat.me {
  reverse_proxy jellyfin:8096
}

Ensure Jellyfin is in the same Docker network that Caddy is part of, or adjust to host.docker.internal:8096 if needed.

🌐 Domain and DNS

  • A subdomain tv.wallaceat.me was created and pointed to the public IP of the server using Dynu DNS
  • Dynu IP Update Client keeps the IP up to date in case it changes

⚠️ Common Issues I Faced

  • Port conflicts: Jellyfin initially used host network, which interfered with other services; switching to bridged network fixed it
  • Reverse proxy errors: Caddy logged connection timeouts when the Jellyfin container was misconfigured or not reachable
  • Permissions: Mounted volumes needed correct read/write permissions for Jellyfin to access media files

🎉 Outcome

Jellyfin is now fully accessible at https://tv.wallaceat.me with SSL and remote access. It’s integrated into my self-hosted stack alongside Immich and WordPress using Caddy as a central reverse proxy.

💡 Lessons Learned

  • Using Caddy simplifies HTTPS and domain routing significantly
  • Proper Docker network configuration is critical for reverse proxying
  • Persistent volumes are essential to keep configuration and media libraries intact

Jellyfin has been a solid and customizable solution for streaming my personal media library across devices, all from a home server setup.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *