Building a Self-Hosted Streaming Service: FileBrowser + Jellyfin
Complete guide to setting up FileBrowser and Jellyfin together for a powerful self-hosted media streaming platform with advanced file management
Building a Self-Hosted Streaming Service: FileBrowser + Jellyfin
Want your own Netflix-like streaming service with full control over your media library? By combining Jellyfin (media server) with FileBrowser (file management), you get a powerful self-hosted solution that rivals commercial streaming platforms.
This guide shows you how to set up both tools together for seamless media management and streaming.
What Are These Tools?
Jellyfin: The Free Media System
Jellyfin is an open-source media server that lets you:
- Stream movies, TV shows, music, and photos to any device
- Organize your library with metadata, posters, and descriptions
- Transcode on-the-fly for different devices and bandwidths
- Share with family/friends with user accounts and permissions
- Access remotely via web, mobile apps (iOS/Android), or smart TVs
Think: Netflix, but you own everything.
FileBrowser: Web-Based File Management
FileBrowser provides a web interface to manage files:
- Upload/download files via drag-and-drop
- Create/delete/rename files and folders
- Share files with temporary links
- Edit files with built-in text editor
- User management with permissions and quotas
- Command execution for custom scripts
Think: Dropbox meets FTP, but self-hosted.
Why Use Them Together?
Separately, they're great. Together, they're transformative:
| Challenge | Solution |
|---|---|
| Adding media | Upload via FileBrowser, automatically appears in Jellyfin |
| Organizing files | Rename/move files without SSH or FTP |
| Bulk uploads | Drag entire folders into FileBrowser |
| Remote management | Manage library from phone/tablet |
| Sharing raw files | Share media files directly via FileBrowser links |
| No technical skills needed | Family members can add their own videos |
The workflow:
- Upload movies to FileBrowser
- Organize into proper folders
- Jellyfin automatically scans and adds them
- Stream from any device
Architecture Overview
Here's how the components work together:
┌─────────────────────────────────────────────┐
│ Docker Host (Your Server) │
│ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ FileBrowser │ │ Jellyfin │ │
│ │ :8080 │ │ :8096 │ │
│ └──────┬───────┘ └──────┬───────┘ │
│ │ │ │
│ └──────┐ ┐────────┘ │
│ ▼ ▼ │
│ ┌──────────────────┐ │
│ │ Shared Volume │ │
│ │ /media │ │
│ │ /movies │ │
│ │ /tv-shows │ │
│ │ /music │ │
│ └──────────────────┘ │
└─────────────────────────────────────────────┘
Key concept: Both containers access the same media directory, so files added via FileBrowser are immediately available to Jellyfin.
Prerequisites
Before starting, ensure you have:
- Linux server (Ubuntu, Debian, or similar)
- Docker & Docker Compose installed
- At least 2GB RAM (4GB+ recommended)
- Storage space for your media (external drive recommended)
- Basic command-line knowledge
Installation Guide
Step 1: Create Directory Structure
# Create project directory
mkdir -p ~/media-server
cd ~/media-server
# Create media directories
mkdir -p media/{movies,tv-shows,music,photos}
# Create config directories
mkdir -p config/{jellyfin,filebrowser}
Directory structure:
media-server/
├── media/
│ ├── movies/
│ ├── tv-shows/
│ ├── music/
│ └── photos/
├── config/
│ ├── jellyfin/
│ └── filebrowser/
└── docker-compose.yml
Step 2: Create Docker Compose File
Create docker-compose.yml:
version: '3.8'
services:
# Jellyfin Media Server
jellyfin:
image: jellyfin/jellyfin:latest
container_name: jellyfin
restart: unless-stopped
ports:
- "8096:8096" # HTTP web interface
- "8920:8920" # HTTPS (optional)
volumes:
- ./config/jellyfin:/config
- ./config/jellyfin/cache:/cache
- ./media:/media:ro # Read-only for security
environment:
- PUID=1000 # Your user ID
- PGID=1000 # Your group ID
- TZ=America/New_York # Your timezone
devices:
- /dev/dri:/dev/dri # Hardware acceleration (optional)
# FileBrowser File Management
filebrowser:
image: filebrowser/filebrowser:latest
container_name: filebrowser
restart: unless-stopped
ports:
- "8080:80"
volumes:
- ./media:/srv # Full access to media
- ./config/filebrowser/filebrowser.db:/database.db
- ./config/filebrowser/settings.json:/config/settings.json
environment:
- PUID=1000
- PGID=1000
Step 3: Get Your User ID
# Find your user and group IDs
id
# Output example:
# uid=1000(your_user) gid=1000(your_group)
Update PUID and PGID in docker-compose.yml with your IDs.
Step 4: Start the Services
# Start containers
docker-compose up -d
# Verify they're running
docker-compose ps
# Check logs if needed
docker-compose logs -f
Initial Configuration
Configure FileBrowser
-
Access FileBrowser: Open
http://your-server-ip:8080 -
Default credentials:
- Username:
admin - Password:
admin
- Username:
-
Change password immediately:
- Click on "Settings" (gear icon)
- Go to "User Management"
- Edit admin user
- Set strong password
-
Configure settings:
- Go to "Settings" → "Global Settings"
- Enable "Allow uploads"
- Enable "Allow new files/folders"
- Set default view to "List" or "Gallery"
-
Create media folders (if not visible):
- Navigate to root
- You should see:
movies/,tv-shows/,music/,photos/
Configure Jellyfin
-
Access Jellyfin: Open
http://your-server-ip:8096 -
Initial setup wizard:
- Select language
- Create admin account (strong password!)
- Click "Next"
-
Add media libraries:
For Movies:
- Click "Add Media Library"
- Content type: "Movies"
- Display name: "Movies"
- Folder: Click "+", add
/media/movies - Click "OK"
For TV Shows:
- Add another library
- Content type: "Shows"
- Display name: "TV Shows"
- Folder:
/media/tv-shows
For Music:
- Content type: "Music"
- Display name: "Music"
- Folder:
/media/music
For Photos:
- Content type: "Photos"
- Display name: "Photos"
- Folder:
/media/photos
-
Configure metadata:
- Language: English (or your preference)
- Country: United States (or your preference)
- Enable "Download images"
- Enable "Automatically refresh metadata"
-
Finish setup and wait for initial library scan
File Naming Conventions
For Jellyfin to properly identify media, follow these naming patterns:
Movies
movies/
├── The Matrix (1999)/
│ └── The Matrix (1999).mkv
├── Inception (2010)/
│ └── Inception (2010).mp4
└── Interstellar (2014)/
└── Interstellar (2014).mkv
Pattern: Movie Title (Year)/Movie Title (Year).ext
TV Shows
tv-shows/
├── Breaking Bad/
│ ├── Season 01/
│ │ ├── Breaking Bad S01E01.mkv
│ │ ├── Breaking Bad S01E02.mkv
│ │ └── Breaking Bad S01E03.mkv
│ └── Season 02/
│ ├── Breaking Bad S02E01.mkv
│ └── Breaking Bad S02E02.mkv
└── Game of Thrones/
└── Season 01/
└── Game of Thrones S01E01.mkv
Pattern: Show Name/Season XX/Show Name SXXEXX.ext
Music
music/
├── Artist Name/
│ ├── Album Name (Year)/
│ │ ├── 01 - Track Name.mp3
│ │ ├── 02 - Track Name.mp3
│ │ └── cover.jpg
│ └── Another Album (Year)/
│ └── ...
The Workflow: Adding Media
Method 1: Upload via FileBrowser (Easiest)
- Open FileBrowser:
http://your-server-ip:8080 - Navigate to appropriate folder (
movies/,tv-shows/, etc.) - Create folder for the movie/show (e.g., "The Matrix (1999)")
- Drag and drop your video file(s)
- Wait for upload to complete
- Rename if needed (right-click → Rename)
Method 2: Batch Upload via Command Line
# From your local machine
scp -r "Movie Collection/" user@server:~/media-server/media/movies/
# Or using rsync (better for large files)
rsync -avP "Movie Collection/" user@server:~/media-server/media/movies/
Method 3: Mount Network Share (Advanced)
Share your media folder via Samba/NFS, then add media directly from your desktop:
On server (install Samba):
sudo apt install samba
sudo nano /etc/samba/smb.conf
Add share:
[media]
path = /home/your_user/media-server/media
browseable = yes
writable = yes
guest ok = no
valid users = your_user
Restart Samba:
sudo systemctl restart smbd
On Windows: Connect to \\server-ip\media
On Mac: Connect to smb://server-ip/media
Automatic Library Updates
Configure Jellyfin to scan for new media automatically:
- Go to Jellyfin Dashboard
- Library → Select a library → "Edit"
- Enable "Monitor folder"
- Set scan interval (e.g., every 12 hours)
- Save
Alternatively, trigger manual scan:
- Dashboard → "Scan All Libraries"
Or via API:
curl -X POST "http://localhost:8096/Library/Refresh" \
-H "X-Emby-Token: YOUR_API_KEY"
User Management
Creating Users in FileBrowser
- Settings → "User Management"
- Click "New User"
- Set username/password
- Configure permissions:
- Scope:
/media/movies(limit access to specific folders) - Permissions: Upload, Create, Rename, Delete (as needed)
- Scope:
- Save
Use cases:
- Family member who only adds movies
- Friend who manages TV shows
- Read-only user for viewing files
Creating Users in Jellyfin
- Dashboard → "Users"
- Click "+"
- Enter name
- Set password (or allow no password for trusted network)
- Configure access:
- Enable/disable libraries per user
- Set streaming quality limits
- Allow/deny remote access
- Save
Advanced Configuration
Enable Hardware Transcoding (Jellyfin)
For faster transcoding and lower CPU usage:
- Dashboard → "Playback"
- Hardware acceleration: Select your GPU
- Intel: "Intel QuickSync (QSV)"
- NVIDIA: "NVIDIA NVENC"
- AMD: "AMD AMF"
- Enable codecs: H264, HEVC, etc.
- Save
Note: Requires proper device mapping in docker-compose.yml (already included above).
Custom Commands in FileBrowser
Add useful commands for media management:
- Settings → "Command Runner"
- Add command:
Example: Convert video to H264
ffmpeg -i "$FILE" -c:v libx264 -crf 23 "${FILE%.mkv}_h264.mkv"
Example: Extract subtitles
ffmpeg -i "$FILE" -map 0:s:0 "${FILE%.mkv}.srt"
- Save and use via right-click → "Execute command"
Reverse Proxy (HTTPS)
Use Nginx or Caddy for secure access:
Caddy example:
jellyfin.yourdomain.com {
reverse_proxy localhost:8096
}
files.yourdomain.com {
reverse_proxy localhost:8080
}
Install Caddy and reload config:
sudo caddy reload
Now access via:
https://jellyfin.yourdomain.comhttps://files.yourdomain.com
Remote Access
Option 1: Port forwarding
- Forward ports 8096 and 8080 on your router
- Access via
http://your-public-ip:8096
Option 2: Cloudflare Tunnel (recommended)
- Free, secure, no port forwarding
- Works behind CGNAT
- Built-in DDoS protection
Option 3: VPN (Tailscale/WireGuard)
- Most secure
- Access your network from anywhere
- No exposed ports
Mobile Access
Jellyfin Apps
iOS:
- Jellyfin Mobile (official, free)
- Swiftfin (third-party, beautiful UI)
Android:
- Jellyfin for Android (official, free)
- Findroid (third-party, Material Design)
Download from:
- App Store / Google Play
- F-Droid (Android, open-source)
FileBrowser on Mobile
- Use mobile browser:
http://your-server-ip:8080 - Responsive web interface works well on phones
- Upload photos/videos from phone directly
Backup Strategy
What to backup:
- Jellyfin config:
./config/jellyfin/(user settings, watched status) - FileBrowser database:
./config/filebrowser/filebrowser.db(users, permissions) - Media files:
./media/(most important!)
Backup script:
#!/bin/bash
# backup-media-server.sh
BACKUP_DIR="/mnt/backup/media-server"
DATE=$(date +%Y%m%d_%H%M%S)
# Stop services
cd ~/media-server
docker-compose stop
# Backup configs
tar -czf "$BACKUP_DIR/config_$DATE.tar.gz" config/
# Backup media (or use rsync to external drive)
rsync -avP media/ /mnt/external-drive/media-backup/
# Start services
docker-compose start
echo "Backup completed: $DATE"
Automate with cron:
# Run every Sunday at 2 AM
0 2 * * 0 /home/user/backup-media-server.sh
Troubleshooting
Jellyfin not seeing new files
Check:
- File permissions:
ls -la media/movies/ - Correct naming convention
- Trigger manual scan: Dashboard → "Scan All Libraries"
- Check logs:
docker-compose logs jellyfin
Fix permissions:
sudo chown -R 1000:1000 media/
sudo chmod -R 755 media/
FileBrowser upload fails
Check:
- Disk space:
df -h - File size limits (default: unlimited)
- Browser console for errors
- Logs:
docker-compose logs filebrowser
Increase upload size (if behind Nginx):
client_max_body_size 10G;
Transcoding fails / Buffering issues
Solutions:
- Enable hardware acceleration
- Lower streaming quality in Jellyfin settings
- Check network bandwidth
- Pre-transcode files:
ffmpeg -i input.mkv -c:v libx264 -preset slow -crf 22 output.mp4
Can't access remotely
Check:
- Firewall rules:
sudo ufw status - Port forwarding on router
- Server's local IP vs public IP
- Use Cloudflare Tunnel or VPN instead
Performance Optimization
Storage
- Use SSD for Jellyfin config/cache (faster metadata)
- Use HDD for media files (cheaper per GB)
- Enable RAID for data redundancy
Network
- Gigabit ethernet for server (no WiFi)
- MoCA adapters if ethernet not possible
- QoS rules to prioritize streaming traffic
Transcoding
- Hardware acceleration (GPU) saves CPU
- Pre-transcode large files to H264
- Limit concurrent streams per user
- Use Jellyfin's trickplay for thumbnails
Security Best Practices
- Strong passwords for all accounts
- HTTPS only for remote access (use reverse proxy)
- Disable admin on public internet (use VPN)
- Regular updates:
docker-compose pull && docker-compose up -d - Firewall rules: Only expose necessary ports
- Read-only media for Jellyfin (already configured above)
- Backup regularly (3-2-1 rule)
Cost Comparison
Self-Hosted (FileBrowser + Jellyfin)
Initial:
- Used PC/Raspberry Pi: $50-$200
- External HDD (4TB): $80-$100
Ongoing:
- Electricity: ~$5-15/month
- Internet: $0 (existing)
- Domain (optional): $10-15/year
Total first year: ~$200-350
Annual after: ~$60-180
Commercial Alternatives
- Netflix: $15.49/month = $186/year
- Hulu: $14.99/month = $180/year
- Disney+: $10.99/month = $132/year
- Amazon Prime: $14.99/month = $180/year
Total for all four: $678/year
Break-even: ~6 months with self-hosted!
Plus you own your content forever and have unlimited storage.
Use Cases
Family Media Server
- Parents upload family videos via FileBrowser
- Kids watch cartoons on tablets (Jellyfin app)
- Grandparents access via smart TV
- Everyone has their own watchlist
Shared House / Dorm
- Roommates contribute movies
- Each person has own Jellyfin account
- FileBrowser quotas prevent storage hogging
- Watch parties via Jellyfin SyncPlay
Content Creator
- Store raw footage in FileBrowser
- Organize by project/date
- Share preview links with clients
- Archive completed projects
Language Learning
- Upload movies/shows in target language
- Jellyfin's subtitle support
- Repeat viewing for practice
- Build personal learning library
Conclusion
Combining FileBrowser and Jellyfin creates a powerful, self-hosted streaming platform that rivals commercial services while giving you complete control.
Key benefits:
✅ Own your media - No licensing issues, no content removal
✅ No monthly fees - One-time hardware cost
✅ Unlimited storage - Add drives as needed
✅ Privacy - Your viewing habits stay private
✅ Customization - Full control over features and UI
✅ Family sharing - No per-user fees
✅ Remote access - Watch from anywhere
✅ File management - Easy media organization via web interface
You should try this if:
- You have a large media collection
- You're tired of subscription fatigue
- You want to share with family/friends
- You value privacy and control
- You enjoy self-hosting projects
Start small: Set up on an old laptop with a few movies. Once you see how well it works, invest in proper hardware and storage.
Happy streaming! 🎬
Resources
- Jellyfin: https://jellyfin.org/
- FileBrowser: https://filebrowser.org/
- Jellyfin Documentation: https://jellyfin.org/docs/
- FileBrowser Documentation: https://filebrowser.org/features
- Docker: https://docs.docker.com/
- r/Jellyfin: https://reddit.com/r/jellyfin
- r/selfhosted: https://reddit.com/r/selfhosted
Built your own streaming service? Share your setup in the comments! Questions about configuration? Drop them below.