Homelab Growing

Building a Plex Server on a Raspberry Pi 5: NVMe, Linux, and the Open-Source Deep End

Field notes from turning a Raspberry Pi 5 into a Plex server: enabling NVMe boot, learning Linux by breaking it, and getting comfortable in the open-source deep end.

Planted
Last tended

I wrote about running your own servers as a designer and called a Plex box “the lowest-stakes entry point” into infrastructure. This is that entry point with the receipts — the actual Raspberry Pi 5 build, the walls I hit, and the Linux fundamentals I only learned because I broke them first. The blog post is the why. This is the what actually happened at the terminal.

Booting Off NVMe Was the First Wall

The plan was simple: Pi 5, an M.2 NVMe HAT, a real SSD instead of a microSD card that dies every eight months. Then the Pi refused to boot from it.

Nobody tells you up front that a fresh Pi 5 doesn’t know how to boot from NVMe until you teach it. Two things have to be true. First, the bootloader EEPROM needs to be recent enough and configured to try the NVMe device — sudo raspi-config → Advanced → Bootloader Version, then sudo rpi-eeprom-config --edit to set a BOOT_ORDER that actually includes NVMe before it gives up and falls back to the SD card. Second, PCIe has to be switched on in /boot/firmware/config.txt:

dtparam=nvme
dtparam=pciex1
dtparam=pciex1_gen=3

That last line is the fun one. The Pi 5’s PCIe is only officially certified at Gen 2, but most NVMe HATs run happily at Gen 3 — you just have to opt in, and accept that “unofficial” means “works until a particular drive doesn’t.” That single toggle roughly doubled my read speeds. It’s also exactly the kind of tradeoff that never shows up in a design review: a real, physical constraint with a knob you can turn, and a documented reason the vendor won’t turn it for you.

The other half was getting the OS onto the drive. SD Card Copier (built into Raspberry Pi OS) clones a running SD card to the NVMe cleanly; I’ve also used rpi-clone for the same trick from the command line. Boot order matters here — until the EEPROM change took, the Pi kept quietly booting the SD card while I stared at an NVMe drive that “wasn’t working.” It was working. It just wasn’t being asked to.

Learning Linux by Breaking It

I did not learn Linux by reading a book. I learned it because Plex couldn’t see my media and the reason was a permissions mistake I’d made an hour earlier.

That’s the pattern that finally made the concepts stick:

  • Ownership and permissions. Every file has an owner and a group, and Plex runs as its own plex user — not as me. My media folder was owned by my account with permissions that locked everyone else out, so the plex user saw an empty library. chown, chmod, and actually understanding what 755 means stopped being trivia the moment they were the difference between a working server and a blank screen.
  • systemd is the thing keeping the lights on. A “service” isn’t a program you run; it’s a program the OS promises to keep running and restart when it dies. systemctl status plexmediaserver, systemctl enable so it survives a reboot, and journalctl -u plexmediaserver when I needed to know why it died. That’s the whole difference between a script and a service — and it’s the same distinction I lean on now when I scope “can we just add a background job?” at work.
  • Mounting drives, permanently. Plugging in storage isn’t the same as it being there after a reboot. Editing /etc/fstab with the drive’s UUID (from blkid, never /dev/sda1, which cheerfully renames itself) is how a mount survives power loss. I learned that the hard way, too.
  • SSH is the real interface. After the first day I never touched a monitor again. Key-based SSH, then living in the terminal, is the actual experience of running a headless machine.

None of this was hard, exactly. It was unfamiliar, and unfamiliar plus “the thing I want is broken” is a much better teacher than a tutorial where everything already works.

Why Won’t Plex Just Stay Working?

Getting Plex installed is easy — add Plex’s APT repository, apt install plexmediaserver, done. Getting it to stay useful is where the homelab tax gets paid.

The library permissions issue above was the first snag. Remote access was the second: Plex wants to reach the outside world on port 32400, which means either its own relay or actually understanding your router’s port forwarding — the same networking concepts, port by port, that quietly underpin every production service. And then transcoding. On a Pi 5, you lean on direct play — the client plays the file as-is — because ARM hardware transcoding for Plex isn’t the smooth story it is on an Intel box with Quick Sync. That constraint changed how I think about the whole setup: the “right” answer was often to store media in formats my devices already play, not to throw more CPU at converting them on the fly. Solve it at the source, not at runtime.

The Open-Source Deep End

The part I wasn’t ready for wasn’t technical. It was cultural.

There is no support line. There is no polished onboarding wizard that anticipates your exact drive, your exact HAT, your exact router. What there is instead is a bootloader man page, a Raspberry Pi forum thread from 2024, a Plex support article, and someone’s blog post benchmarking the exact NVMe HAT you bought — and you are the one who has to assemble those four sources into a working system. The answer to almost every problem existed. It was just never in one place, and never phrased for my exact situation.

That’s the open-source deep end, and it’s genuinely uncomfortable coming from consumer products that hide all of this. But it’s also the point. Every hour of piecing-it-together is an hour of building the constraint literacy I keep arguing designers need — the visceral, I-broke-this-myself understanding of why infrastructure behaves the way it does. You can’t buy that feeling. You have to earn it at 11pm with seven browser tabs open.

What’s Next

Move Plex into a Docker container so the whole setup is reproducible instead of hand-tuned — the same “if I can’t describe it in a Compose file, I’m not done” discipline from the self-hosting post. After that: automated backups of the Plex config off the NVMe, and a proper monitoring check so I find out the server is down before someone else’s movie night does.

Tools Used

Raspberry Pi 5NVMe HATRaspberry Pi OSPlex Media ServersystemdSSH