I have a collection of movies and TV shows that I want to watch from multiple devices — laptop, phone, TV. Keeping them synchronized and accessible from anywhere was awkward until I set up Jellyfin.
Jellyfin indexes your media library, downloads metadata and cover art, organizes everything into a polished interface, and streams to any browser or app. The free Jellyfin clients are available for basically every platform.
The server-side transcoding capability matters here: without it, your client needs to be able to play the original format directly. With it, Jellyfin converts the video in real time to something your device can handle. That's more CPU-intensive, which affects server sizing — I'll explain the trade-offs.
This guide deploys Jellyfin on Ubuntu 22.04 using Docker, with Nginx as the reverse proxy and HTTPS.
I run Jellyfin on Tencent Cloud Lighthouse. For streaming, bandwidth matters more than CPU for direct play. Lighthouse's bandwidth packages (200GB+ per month on standard plans) handle streaming video comfortably for personal use. For hardware transcoding of 4K content, you'll need more CPU power. The CBS cloud disk expansion is also useful here — you can attach additional storage for your media library as it grows, without migrating the Jellyfin configuration and database.
- Key Takeaways
| Jellyfin | Plex | |
|---|---|---|
| Cost | Free forever | Free tier + Plex Pass ($5/mo) |
| Data privacy | 100% self-contained | Plex servers collect metadata |
| Remote streaming | Free | Requires Plex Pass |
| Mobile apps | Free | Free for local, Plex Pass for remote |
| Hardware transcoding | Free | Requires Plex Pass |
| Active development | Yes (community) | Yes (commercial) |
| Requirement | Notes |
|---|---|
| Cloud server | Tencent Cloud Lighthouse — select Docker CE application image for fastest setup |
| Docker + Compose | Pre-installed with Docker CE image; or install manually |
| Storage | At least 50 GB for media; add a data disk for large libraries |
| Domain name | For remote access via HTTPS |
💡 If you selected the Docker CE application image, Docker is already running. Skip the Docker install lines below — start from
sudo apt install -y nginx.
ssh ubuntu@YOUR_SERVER_IP
sudo apt update && sudo apt upgrade -y
curl -fsSL https://get.docker.com | sudo sh
sudo usermod -aG docker $USER
newgrp docker
sudo apt install -y nginx
sudo ufw allow ssh
sudo ufw allow 'Nginx Full'
sudo ufw enable
# Create media directories
sudo mkdir -p /media/{movies,tvshows,music,photos}
sudo chown -R ubuntu:ubuntu /media
mkdir -p ~/apps/jellyfin && cd ~/apps/jellyfin
Create docker-compose.yml:
version: '3.8'
services:
jellyfin:
image: jellyfin/jellyfin:latest
container_name: jellyfin
restart: unless-stopped
ports:
- "8096:8096" # HTTP
- "8920:8920" # HTTPS (optional — we use Nginx instead)
volumes:
- ./config:/config
- ./cache:/cache
- /media:/media:ro # Media directory (read-only for security)
environment:
- PUID=1000
- PGID=1000
- TZ=America/New_York
devices:
- /dev/dri:/dev/dri # For hardware transcoding (Intel/AMD GPU); comment out if not applicable
docker compose up -d
docker compose logs -f
# Wait for: Startup complete
sudo nano /etc/nginx/sites-available/jellyfin
server {
listen 80;
server_name media.yourdomain.com;
client_max_body_size 100m;
location / {
proxy_pass http://127.0.0.1:8096;
proxy_http_version 1.1;
# WebSocket support (required for Jellyfin sync play and remote control)
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
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_set_header X-Forwarded-Host $host;
proxy_buffering off;
proxy_request_buffering off;
proxy_read_timeout 600s;
proxy_send_timeout 600s;
}
}
sudo ln -s /etc/nginx/sites-available/jellyfin /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d media.yourdomain.com
Visit https://media.yourdomain.com.
The Jellyfin setup wizard:
Select language
Create admin user — username and password
Add media libraries:
/media/moviesRepeat for TV Shows (/media/tvshows), Music (/media/music), Photos.
Metadata language — select your preferred language
Remote access — allow remote access (required for streaming outside home)
Jellyfin will scan your media directories and fetch metadata (posters, descriptions, episode info) from online databases.
# Upload movies
scp "My Movie (2024).mkv" ubuntu@YOUR_SERVER_IP:/media/movies/
# Upload entire folder
scp -r ~/Movies/ ubuntu@YOUR_SERVER_IP:/media/movies/
rsync -avzP --progress ~/Movies/ ubuntu@YOUR_SERVER_IP:/media/movies/
Jellyfin (like all media servers) relies on file naming for metadata lookup:
Movies:
/media/movies/
├── The Dark Knight (2008)/
│ └── The Dark Knight (2008).mkv
└── Inception (2010)/
└── Inception (2010).mkv
TV Shows:
/media/tvshows/
└── Breaking Bad/
├── Season 01/
│ ├── Breaking Bad - S01E01 - Pilot.mkv
│ └── Breaking Bad - S01E02.mkv
└── Season 02/
| Platform | App | Notes |
|---|---|---|
| Browser | Any browser | Access via URL |
| Android | Jellyfin for Android | Google Play / F-Droid |
| iOS | Infuse (paid) or Jellyfin Mobile | App Store |
| Apple TV | Swiftfin | App Store |
| Android TV | Jellyfin for Android TV | Google Play |
| Roku | Jellyfin | Roku Channel Store |
| Kodi | Jellyfin for Kodi | Kodi repository |
| Fire TV | Jellyfin | Amazon App Store |
Connect any client: enter https://media.yourdomain.com as the server address.
Media files are the most important backup. The Jellyfin config/database is smaller but worth backing up too:
# Backup Jellyfin config (metadata, users, settings)
docker run --rm \
-v ~/apps/jellyfin/config:/data \
-v ~/backups/jellyfin:/backup \
alpine tar czf /backup/jellyfin_config_$(date +%Y%m%d).tar.gz -C /data .
For media files, use rsync to a separate backup location (local drive, S3, etc.).
Jellyfin has two modes for streaming video:
On a VPS without a GPU, transcoding is very slow. A 1080p h.265 transcode can easily max out 4 CPU cores.
Solutions:
Check if hardware transcoding is available:
ls /dev/dri/
# If renderD128 exists, hardware transcoding may be available
# Update Jellyfin
cd ~/apps/jellyfin
docker compose pull
docker compose up -d --remove-orphans
# Rescan library (also available from admin UI)
docker exec jellyfin bash -c "curl -s -X POST http://localhost:8096/Library/Refresh"
# View logs
docker compose logs -f jellyfin
# Check container resource usage
docker stats jellyfin
| Issue | Likely Cause | Fix |
|---|---|---|
| Connection refused | Service not running or wrong port | Check systemctl status SERVICE and verify firewall rules |
| Permission denied | Wrong file ownership or permissions | Check file ownership with ls -la and use chown/chmod to fix |
| 502 Bad Gateway | Backend service not running | Restart the backend service; check logs with journalctl -u SERVICE |
| SSL certificate error | Certificate expired or domain mismatch | Run sudo certbot renew and verify domain DNS points to server IP |
| Service not starting | Config error or missing dependency | Check logs with journalctl -u SERVICE -n 50 for specific error |
| Out of disk space | Logs or data accumulation | Run df -h to identify usage; clean logs or attach CBS storage |
| High memory usage | Too many processes or memory leak | Check with htop; consider upgrading instance plan if consistently high |
| Firewall blocking traffic | Port not open in UFW or Lighthouse console | Open port in Lighthouse console firewall AND sudo ufw allow PORT |
What video formats does Jellyfin support for streaming?
Modern media servers support most common formats. Direct Play (native format support by client) is preferred over transcoding. H.264 video in MKV or MP4 containers has the widest client support.
What's the difference between Direct Play and Transcoding?
Direct Play streams the original file to the client, requiring no server CPU. Transcoding converts the video in real-time to a compatible format, requiring significant server CPU.
How much bandwidth do I need for video streaming?
Blu-ray quality: 25–40 Mbps. 1080p: 8–25 Mbps. 720p: 3–8 Mbps. Lighthouse bandwidth packages support these rates. For multiple simultaneous streams, multiply accordingly.
How do I add media files to the server?
Upload via SCP/SFTP from your local machine, rsync from a NAS, or download directly on the server. The guide covers the recommended directory structure for automatic library scanning.
Set up your private media server:
👉 Tencent Cloud Lighthouse — Bandwidth-ready VPS for media streaming
👉 View current pricing and promotions
👉 Explore all active deals and offers