Jellyfin Multi-Server Architecture 2026: Load Balancing, Failover, and Geo-Distribution

Jellyfin Multi-Server Architecture 2026: Load Balancing, Failover, and Geo-Distribution

Jellyfin Multi-Server Architecture 2026: Load Balancing, Failover, and Geo-Distribution

A single Jellyfin server handles most home setups perfectly. An Intel N100 serves 3-4 simultaneous 4K transcodes. An i5 with a dedicated GPU handles 10+. But some scenarios push beyond what one server can deliver:

  • 20+ concurrent users overwhelming a single GPU
  • Geographic distribution where users in Europe and the US both need low-latency access
  • Zero-downtime maintenance where you cannot take the server offline for updates
  • Redundancy where a hardware failure must not mean days without service

This guide covers the architectures that solve these problems, and the honest limitations you will hit.


The Fundamental Limitation: SQLite

Before diving into architectures, understand the core constraint: Jellyfin uses SQLite as its database. SQLite does not support concurrent writes from multiple processes. This means:

  • You cannot run two Jellyfin instances writing to the same database simultaneously
  • You cannot have a true active-active cluster where both nodes serve requests
  • You can have active-passive (one serves, one waits)
  • You can have multiple independent servers synced via external tools

The EF Core migration in Jellyfin 10.11 laid the groundwork for PostgreSQL support (which would enable true multi-instance). But as of mid-2026, SQLite remains the only supported backend.


Architecture 1: Active-Passive Failover

The simplest multi-server setup. One server handles all traffic. If it fails, a standby takes over.

                    [Load Balancer / DNS Failover]
                         |              |
                    [Primary]      [Standby]
                         |              |
                    [Shared Storage (NFS/CIFS)]

How it works

  1. Primary server runs Jellyfin and serves all users
  2. Standby server has Jellyfin installed but stopped
  3. Shared storage (NFS/CIFS) holds media files accessible to both
  4. Config replication copies the Jellyfin database from primary to standby periodically
  5. Health check monitors the primary. If it fails, the standby starts Jellyfin
  6. DNS or load balancer switches traffic to the standby

Implementation with Keepalived

Keepalived provides a floating virtual IP that moves between servers:

# On primary (/etc/keepalived/keepalived.conf)
vrrp_script check_jellyfin {
    script "/usr/bin/curl -sf http://localhost:8096/health"
    interval 5
    weight -20
}

vrrp_instance JELLYFIN {
    state MASTER
    interface eth0
    virtual_router_id 51
    priority 100
    virtual_ipaddress {
        192.168.1.200
    }
    track_script {
        check_jellyfin
    }
}
# On standby
vrrp_instance JELLYFIN {
    state BACKUP
    interface eth0
    virtual_router_id 51
    priority 90
    virtual_ipaddress {
        192.168.1.200
    }
    notify_master "/usr/local/bin/start-jellyfin.sh"
    notify_backup "/usr/local/bin/stop-jellyfin.sh"
}

When the primary fails the health check, Keepalived promotes the standby. The notify_master script starts Jellyfin on the new primary.

Config Sync

Sync the Jellyfin database from primary to standby every hour:

# Cron on primary (every hour)
0 * * * * rsync -az /opt/jellyfin/config/ standby:/opt/jellyfin/config/

The standby is always at most 1 hour behind. Watch history from the last hour before a failure may be lost.

Limitations

  • Not zero-downtime - failover takes 10-30 seconds
  • Data loss window - up to 1 hour of watch history lost on failover
  • Single point of failure - shared storage must be reliable
  • Manual failback - returning to the primary requires stopping the standby

Architecture 2: Geo-Distributed Independent Servers

For users spread across continents, run independent Jellyfin servers in different regions with WatchState keeping them synchronized.

[User in Europe] --> [Jellyfin EU (Paris VPS)]
                         |
                    [WatchState] <-- syncs watch history
                         |
[User in US]     --> [Jellyfin US (NYC VPS)]
                         |
                    [Shared Media via Rclone/Syncthing]

How it works

  1. Two independent Jellyfin servers in different regions
  2. Same media library synced via Rclone, Syncthing, or shared cloud storage
  3. WatchState synchronizes watch history between both servers
  4. Users connect to their nearest server for lowest latency
  5. DNS-based routing (Cloudflare geo-steering) directs users to the closest server

Media Sync Options

MethodLatencyCostBest for
Rclone to cloud (S3/B2)HoursStorage costLarge libraries, async
Syncthing (peer-to-peer)MinutesBandwidth onlySmall-medium libraries
Shared NFS (same datacenter)InstantNetwork costSame-region servers

Cloudflare Geo-Steering

Configure Cloudflare DNS to route users to the nearest server:

  1. Create a Cloudflare Load Balancer
  2. Add two origin pools: EU server and US server
  3. Enable geo-steering: European users go to EU pool, American users go to US pool
  4. Health checks ensure traffic routes away from a downed server

Limitations

  • Media sync delay - new content takes time to propagate to all servers
  • Independent databases - each server has its own users, settings, and plugins
  • WatchState sync delay - watch history syncs periodically, not instantly
  • Double storage cost - media exists on both servers
  • Operational complexity - managing two servers instead of one

Architecture 3: Transcoding Offload

Keep one Jellyfin server but offload transcoding to dedicated workers.

[Jellyfin Main Server] -- serves UI, metadata, Direct Play
         |
         v (transcoding requests)
[Transcode Worker 1 (GPU)] -- handles HW transcoding
[Transcode Worker 2 (GPU)] -- handles HW transcoding

Current Reality (2026)

Jellyfin does not natively support distributed transcoding. The transcoding process is tightly coupled to the main server. However, workarounds exist:

JellyWatchTry JellyWatch — Your Jellyfin companion, everywhere.

Option A: Tdarr for pre-transcoding

Instead of real-time transcoding, pre-convert your library so everything Direct Plays:

  • Tdarr workers (on separate machines with GPUs) process your library in the background
  • Once converted, Jellyfin serves everything via Direct Play
  • Zero real-time transcoding needed on the main server

Option B: Multiple Jellyfin instances with user routing

Run multiple Jellyfin instances, each with its own GPU:

  • Users who trigger transcoding are assigned to a specific instance
  • Users who Direct Play are assigned to the main instance
  • Manual user management (not automatic)

Architecture 4: Read Replicas (Future - PostgreSQL)

When Jellyfin adds PostgreSQL support (roadmap for 12.0+), true read replicas become possible:

[Primary Jellyfin] -- writes to PostgreSQL primary
         |
[PostgreSQL Primary] --> [PostgreSQL Replica]
         |                       |
[Read-Only Jellyfin 1]    [Read-Only Jellyfin 2]

This would allow multiple Jellyfin instances to serve read requests (library browsing, metadata) while a single primary handles writes (watch state, user management). This is not available today but is the long-term direction.


Practical Recommendations

ScenarioRecommended architecture
1-10 users, single locationSingle server (no multi-server needed)
10-20 users, single locationSingle server with powerful GPU
20+ users, single locationPre-transcode library (Tdarr) + powerful server
Users on multiple continentsGeo-distributed independent servers + WatchState
Zero-downtime requirementActive-passive failover with Keepalived
Maximum redundancyGeo-distributed + active-passive at each site

The honest truth

For 95% of self-hosters, a single well-configured server is sufficient. Multi-server architectures add significant operational complexity. Before scaling horizontally, exhaust vertical scaling:

  1. Add a better GPU (Intel Arc A380 handles 6-8 simultaneous 4K transcodes)
  2. Pre-transcode your library with Tdarr (eliminates real-time transcoding)
  3. Optimize clients for Direct Play (set bitrate to Original)
  4. Upgrade to an N305 or i5 for more CPU headroom

Only pursue multi-server when a single machine genuinely cannot handle your load.


FAQ

Can I run two Jellyfin instances on the same database? No. SQLite does not support concurrent writes. Running two instances on the same database will corrupt it.

When will Jellyfin support PostgreSQL? The EF Core migration in 10.11 was the prerequisite. PostgreSQL is on the roadmap for 12.0 or later. No confirmed release date.

Is there a Jellyfin clustering plugin? No. Clustering requires database-level support that SQLite cannot provide.

How many users can one Jellyfin server handle? With Direct Play: effectively unlimited (limited by network bandwidth). With transcoding: depends on GPU. An Intel Arc A380 handles 6-8 simultaneous 4K transcodes.

Does JellyWatch work with multi-server setups? Yes. JellyWatch connects to a specific Jellyfin instance. For multi-server setups, you can add multiple servers in JellyWatch Premium and switch between them.


Scaling your Jellyfin setup? Monitor every instance from one app. Download JellyWatch on Google Play - multi-server support, real-time sessions, and push notifications.

On Emby? Download EmbyWatch on Google Play

Comments

No comments yet. Be the first to share your thoughts.

Leave a comment

Never displayed publicly.
0 / 2000 · Supports limited Markdown: **bold**, *italic*, `code`, [link](url), lists, > quote.