I’ve always wanted to build my own “mini data center” — something affordable, powerful, and actually useful. So, when I finally sat down with my Raspberry Pi 4, a 16GB SD card, and a 300GB external hard drive full of movies, I thought: “Why not make my own Netflix?” And not just locally — I wanted something I could access from anywhere. So this guide takes you through the exact process I used, including:
- - Installing Docker + Portainer
- - Mounting my external hard drive
- - Fixing the infamous Jellyfin playback error
- - Deploying Jellyfin
- - Making it accessible globally via Cloudflare Tunnel
- - Solving all the permission issues that nobody warns you about
If you follow this guide, you’ll have a fully working, cloud-accessible Netflix-style server running on a tiny Raspberry Pi. Let’s begin.
Here’s my setup:
- - Raspberry Pi 4 (2GB RAM)
- - 16GB microSD card
- - External hard drive (NTFS formatted — this will matter later!)
- - Docker & Portainer installed
- - Cloudflare account (free)
- - Domain name (comonhq.com in my case)
** Everything in this tutorial costs basically zero dollars.**
To make life easy, I deployed Jellyfin using Docker.
# Install Docker:
curl -sSL https://get.docker.com | sh [Add your Pi user to the docker group]: sudo usermod -aG docker $USER
# Install Portainer:
docker volume create portainer_data
docker run -d \
-p 8000:8000 \
-p 9443:9443 \
--name portainer \
--restart=always \
-v /var/run/docker.sock:/var/run/docker.sock \
-v portainer_data:/data \
portainer/portainer-ce:latest
Now you can access Portainer at: https://your-pi-ip:9443Docker makes everything easier.
My external hard drive had all my movies, so I plugged it into the Pi and ran:
lsblk
It showed up as /dev/sda1. I mounted it like this:
sudo mkdir -p /media/movies
sudo mount /dev/sda1 /media/movies
I could even see all my movies:
John Wick (2014).mp4
Moonfall (2022).mkv
The Martian (2015).mp4
Everything seemed fine…... BUT playback in Jellyfin failed. And that’s when I realized the real problem.
When I installed Jellyfin, I could browse the movie list — but playing any movie gave this error:
Playback failed due to a fatal player error.
This was happening even before I exposed Jellyfin publicly. So it wasn’t Cloudflare. It wasn’t Jellyfin. It was the drive.
##❗THE CAUSE My external drive was NTFS (Windows format) and the Pi mounted it with root-only permissions. Meaning: Jellyfin could see the files, but not read them. Huge difference. To confirm:
ls -ld /media/movies
It showed something like:
drwx------ root root /media/movies
Yeah… Jellyfin had zero access.
Install NTFS support:
sudo apt install ntfs-3g
Unmount the drive:
sudo umount /media/movies
Remount with proper permissions:
sudo mount -t ntfs-3g -o uid=1000,gid=1000,umask=022 /dev/sda1 /media/movies
Now check permissions:
ls -ld /media/movies
Should look like:
drwxr-xr-x comon comon /media/movies
JELLYFIN PLAYBACK WORKS! This was the biggest issue of the entire project — once the drive was readable, everything else worked flawlessly.
Here’s the Docker Compose file I used:
version: "3.8"
services:
jellyfin:
image: jellyfin/jellyfin:latest
container_name: jellyfin
network_mode: host
volumes:
- /media/movies:/media/movies
- /opt/jellyfin/config:/config
- /opt/jellyfin/cache:/cache
restart: unless-stopped
Run it (if you are running it directly from the CLI):
docker compose up -d
In my case, I was running it through Portainer, so I just restarted it
Jellyfin becomes available at: http://your-pi-ip:8096
Add your media library:
- Go to Dashboard → Libraries → Add
- Select “Movies”
- Set the path to /media/movies
Your movies should instantly appear.
Your Pi will now Direct Play files, which is more stable.
Cloudflare Tunnel allows you to expose Jellyfin securely without port forwarding. Install cloudflared:
curl -fsSL https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-arm64.deb -o cloudflared.deb
sudo dpkg -i cloudflared.deb
rm cloudflared.deb
Login:
cloudflared tunnel login
Create tunnel:
cloudflared tunnel create jellyfin-tunnel
Create config file:
sudo nano /etc/cloudflared/config.yml
tunnel: <YOUR_TUNNEL_ID>
credentials-file: /etc/cloudflared/<YOUR_TUNNEL_ID>.json
ingress:
- hostname: jellyfin.<your-domain>
service: http://localhost:8096
- service: http_status:404
The bug you will likely face (I faced it too):
#Cloudflare saves credentials in:
/home/youruser/.cloudflared/
#But cloudflared expects it in:
/etc/cloudflared/
# Thw Fix:
sudo mv ~/.cloudflared/*.json /etc/cloudflared/
sudo chown root:root /etc/cloudflared/*.json
Start service:
sudo cloudflared service install
sudo systemctl start cloudflared
Now visit: https://jellyfin.yourdomain.com (in my case - https://jellyfin.comonhq.com) You’ll see Jellyfin globally, securely, and with HTTPS.
Now only you (and whoever you allow) can stream.
Turning my Raspberry Pi into a Netflix-style media server was one of the most fun and useful projects I’ve done this year.
I learned:
- - NTFS permissions matter more than you think
- - Docker makes Jellyfin deployment incredibly simple
- - Cloudflare Tunnel is magic
- - The Raspberry Pi is still one of the most powerful small computers for home labs
And now I have a personal media server, accessible from home, work, or anywhere in the world. If you build this too, you’ll wonder why you didn’t do it earlier.
