mysite/public-clearnet/sources/posts/boredom.md

11 KiB
Raw Permalink Blame History

title date draft description tags showToc TocOpen
Movie Night Over the Internet: Jellyfin + Tailscale on a Raspberry Pi 4 2025-12-21T09:30:00+01:00 false A cozy, slightly chaotic, very fun setup story: turning a Raspberry Pi 4 into a private movie-night server with Jellyfin, Docker, and Tailscale—starting on microSD and graduating to SSD later.
raspberrypi
jellyfin
tailscale
docker
homelab
movienight
true true

Ok. Let me tell you the why first. So.... I was turning from one side to the other on my bed, going through YouTube. The thing that I used to silence my pain, to let the time pass, and to forget. But it didn't hit the same anymore. I was bored. Eternal boredom. Then the loneliness came back. It's funny how you can be in the middle of dozens of people, i.e., not alone, but still feel lonely. Anyway. I though to myself "let't message one of my two best friends", We eventually went into a google meet, talked and talked, and decided to watch a movie together at the same time. I told him I still have my Raspberry Pi lying around, let me put it to good use. Few hours passed, and I was ready. Here is what happened in those few hours.

I wanted the kind of movie night where everyone presses play at the same moment, laughs at the same joke, and groans at the same plot twist—even when were scattered across different apartments and time zones. I also wanted it to be a little nerdy, a little elegant, and the kind of project that makes you feel like you own your gadgets again. Enter: a Raspberry Pi 4 (8GB), Jellyfin, and Tailscale.

This post is the “how it went” and the “how to do it” version. Its written for the future-me who will forget everything the second it works, and for anyone who wants a private streaming setup without punching holes in their router for the entire internet to poke at.

The idea

Jellyfin is the media server that turns your own movie files into a nice Netflix-like library. Tailscale is the secret tunnel that lets your friends reach your server as if they were sitting on your WiFi—without you exposing ports to the public internet. Docker is the little shipping container that keeps everything tidy and portable, which matters because I started on a microSD card and planned to move to an SSD later.

The trick to making a Raspberry Pi feel “fast enough” is to avoid video transcoding whenever possible. When Jellyfin can “direct play” a file, the Pi mostly just serves bytes. When it has to transcode, it suddenly feels like you asked a hamster to tow a car. So the theme of this build is compatibility: store media in formats that phones, browsers, and TVs can play directly.

What you need

My setup uses Ubuntu (64-bit is the long-term-friendly choice), a Raspberry Pi 4, a microSD card to get started, and eventually a USB 3 SSD for real “server vibes.” Youll also want a folder of movies youre allowed to stream to your friends. Streaming DRM content from Netflix or rental platforms through Jellyfin isnt supported, and Im intentionally keeping this firmly in the “your own files” lane.

Step one: choose a home for your stuff

Before installing anything, I picked paths that would survive my future SSD upgrade. The idea is simple: keep all persistent app data under one directory, keep all media under another directory, and let Docker mount those paths into containers.

On the Pi, I created a little directory neighborhood under /srv:

sudo mkdir -p /srv/jellyfin/{config,cache} /srv/media /srv/compose/jellyfin
sudo chown -R $USER:$USER /srv

If youre not ready to move movies into /srv/media yet, thats okay. The important part is that you pick a place you can later mount your SSD onto without rewriting your whole setup.

Step two: install Docker and start thinking in containers

I installed Docker and verified that docker compose worked. After that, everything became a file called docker-compose.yml and the comforting feeling that I can rebuild my server from a single folder if life gets weird.

A typical install flow on Raspberry Pi OS looks like this:

sudo apt update
sudo apt install -y ca-certificates curl
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER
newgrp docker
docker --version
docker compose version

Now for the part that feels like summoning a friendly daemon.

Step three: Jellyfin, running happily in Docker

In /srv/compose/jellyfin/docker-compose.yml, I defined a Jellyfin service and mounted my config, cache, and media directories into it. The key mental shift is that Jellyfin can only see what you mount into the container. If you try to browse to /home/hub/Documents/movies from inside the Jellyfin UI and it looks like the folder doesnt exist, its not being dramatic—it genuinely cant see it. Containers are like that.

Heres a simple docker-compose.yml that works well on a Pi:

services:
  jellyfin:
    image: jellyfin/jellyfin:latest
    container_name: jellyfin
    user: "1000:1000"
    ports:
      - "8096:8096/tcp"
      - "7359:7359/udp"
    volumes:
      - /srv/jellyfin/config:/config
      - /srv/jellyfin/cache:/cache
      - /srv/media:/media
    restart: unless-stopped

If your user isnt UID 1000, check it with id -u and id -g, then update the user: line accordingly.

I started Jellyfin like this:

cd /srv/compose/jellyfin
docker compose up -d

After that, Jellyfin lived at http://<pi-lan-ip>:8096 on my home network, which is the most satisfying “its alive” moment of the whole build.

Step four: Tailscale, the magic door for friends

Now comes the part that makes everything feel effortless. Instead of forwarding ports, configuring certificates, and hoping I didnt accidentally publish my server to the open ocean, I installed Tailscale on the Pi host.

curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up
tailscale ip -4

That last command gives you a 100.x.y.z address. Its your Pis Tailscale IP, and its the address your friends will use to reach Jellyfin. From anywhere, the server becomes:

http://100.x.y.z:8096

Or if you enabled magicDNS:

http://rpi:8096

The moment you can open that URL from your phone on mobile data and see your own server is the moment you start plotting your next homelab project.

If you want friends to access only this server and not everything else in your tailnet, Tailscale has a device sharing flow thats perfect for “heres the Pi, please dont look in the rest of my digital house.”

Step five: create a Jellyfin user for your friend

Jellyfin accounts are local to your server. Your friend wont “sign up” on some global Jellyfin site; instead, you create a user for them inside your Jellyfin admin dashboard. The nice part is that you can give them access only to the libraries you want, and you can keep admin permissions to yourself.

If typing passwords on a TV app makes you feel old instantly, Jellyfins Quick Connect feature can make logins much smoother. Your friend gets a short code on their device, you approve it from your logged-in browser, and nobody has to poke letters into a remote control one by one.

Step six: the secret to a smooth Pi movie night is Direct Play

A Raspberry Pi 4 is perfectly happy serving media files. It becomes less happy when it has to convert them on the fly. The goal is to store your library in a way that most clients can play without conversion.

For “plays on basically everything,” I like MP4 with H.264 video and AAC audio. When I inspected one of my files, I found H.264 video already, but the audio was AC3. AC3 is fine on some devices, but its not universal in browsers, and “my friend has no audio” is a movie-night mood killer.

The fix was to keep the video as-is and convert only the audio to AAC, which is much lighter than re-encoding the whole video. This command copies the H.264 video stream, converts audio to AAC stereo, and produces an MP4 thats friendlier to phones and browsers:

ffmpeg -i "500.Days.of.Summer.2009.1080p.BluRay.RARBG.FilmKio.mkv"   -map 0:v:0 -map 0:a:0   -c:v copy   -c:a aac -b:a 384k -ac 2   -movflags +faststart   "500.Days.of.Summer.2009.1080p.mp4"

Subtitles deserve their own tiny cautionary tale. Some subtitle formats trigger transcoding because the client cant render them natively and asks the server to burn them into the video. Text-based SRT subtitles are usually the easiest path. If your MKV contains an SRT track, you can extract it and keep it next to your MP4:

ffmpeg -i "500.Days.of.Summer.2009.1080p.BluRay.RARBG.FilmKio.mkv"   -map 0:s:0   "500.Days.of.Summer.2009.1080p.srt"

Once your friend is watching, you can confirm how Jellyfin is handling playback by checking the active session in the admin dashboard. Seeing “Direct Play” feels like winning.

Step seven: SyncPlay, aka “we pressed play together”

Jellyfin has SyncPlay for “group watch” nights, and its wonderfully simple when everyone is using compatible clients. In practice, the web client is an excellent baseline because its consistent and easy for friends. When we do movie night, we start a SyncPlay group, join it from each device, and keep a voice call open for commentary and laughter. Its not complicated; its just… cozy.

Starting on microSD, graduating to SSD later

Yes, you can run all of this on microSD to begin with. It works. It also feels like using a napkin as a hard drive if you add heavy-write services later. My plan is to move the system to an SSD when convenient, because SSDs are faster and they handle constant writes far better than microSD cards.

The reason the /srv layout is so helpful is that migration becomes a simple copy-and-mount story. When the SSD arrives, you can copy /srv to the SSD, mount the SSD at /srv, reboot, and your containers will come back exactly as before. Docker will happily reuse the same volume paths; Jellyfin will happily reuse the same library; and youll feel like a wizard who planned ahead.

Where this goes next

Once Jellyfin and Tailscale are stable, its easy to imagine the Pi doing more. Pi-hole is light and useful. A smart home hub is fun. Nextcloud is possible, especially with SSD storage and some attention to databases and caching. The practical advice Im giving future-me is to add services one at a time and keep /srv as the center of gravity, because nothing ruins movie night like “I tweaked DNS and now nothing works.”

For now, though, this little Pi does the job: it hosts a library, it welcomes friends through a private tunnel, and it turns “lets watch something” into a real shared moment—even when were not in the same room.

Happy streaming.

The movie night went great, I even posted a BeReal on it. The choice of movie was not random either. I'll write a review for it later on. It was just amazing.


{{< sigdl >}}