Skip to content

Serving Plex Clients from a Raspberry Pi

Plex logo, a plus, and Raspberry Pi logo on a blurry background which is the plex home dashboard.
Running a home media server has never been easier!

Plex is the gold standard for a home-hosted media server, allowing you to stream your home movies or (legally) ripped media from any television, computer, or phone either at home or when out and about.

Plex is widely run across many homelabs, as it is easy to setup, and unlike some other projects actually provides good value to the end user. In the remainder of this post, I'll break down how I have my Plex server set up for 24/7 access on a Raspberry Pi.

Storage

Storing a copy of all your films and TV shows takes up a lot of space. Before deciding to go down the Plex route consider the total storage you'll need. Budget about 1GB/hr of HD TV content and up to 100GB per Blu-ray you want to rip. Also consider home videos and any other content you might want/need.

For my Plex server, I currently have a dedicated 8TB 3.5" HDD. This drive is not mirrored and as such will lose all content when it dies. For me, this is not a big issue, as the cost/benefit ratio of having a secondary drive for parity or a backup is more of a headache than simply re-ripping the disks I have.

My Plex drive is a ZFS-formatted drive, which means I can easily make it into a mirrored vdev later down the line, and benefits from datasets and copy on write, amongst many other things. Besides this drive, I also have some others in operation for my NAS, but I've already done a bit of a deep dive into that on this blog, detailing the hardware in use and my 3-2-1 strategy for retention of important data.

I separate my content into a movies directory, a tv-shows directory, and pull in home videos from my YouTube archive, which I might discuss in another post.

Docker

When choosing how to run Plex, you can either go native, or run it in a Docker container. Interestingly, they also have a semi-official Kubernetes Helm chart, meaning that you can potentially make it highly available if you have a K8s cluster at your disposal.

On the official page, you can choose the network type for the server, either as a bridge device (giving the container its own networking, then exposing select ports), make use of a Macvlan (which assigns the computer another IP address specifically for the Plex server), or simply use the host network.

For my current setup, I found it simplest to just use the host network, as this meant fewer headaches getting the container running, and easier debugging later down the line.

Installation

To get started, I logged into my NAS server, running-lion, and cloned the repository into my home directory:

britton-charlie@running-lion:~ $ git clone --depth 1 https://github.com/plexinc/pms-docker plexmediaserver
Cloning into 'plexmediaserver'...
remote: Enumerating objects: 50, done.
remote: Counting objects: 100% (50/50), done.
remote: Compressing objects: 100% (41/41), done.
remote: Total 50 (delta 1), reused 27 (delta 1), pack-reused 0
Receiving objects: 100% (50/50), 60.45 KiB | 578.00 KiB/s, done.
Resolving deltas: 100% (1/1), done.

Importing Configuration

Following this, I created a config directory and copied my configuration from the previous server into this directory. This would mean all watch data and other settings would already be there when I started to use it. Configuration was copied from my computer as a zipped file, as there are many small files on disk which need expanding.

The configuration directory supplied to the docker-compose.yml file needs to be at config, which means that the files are at config/Library/Application Support/Plex Media Server/.

Editing docker-compose.yml

In the repository, there are already sample configurations for each of the three network set ups. I renamed mine and set the variables for my time-zone, IP, etc.

As I am using a Raspberry Pi, and for some reason Plex don't host an image for the ARM architecture, if you try and run the service without building your local image, you'll encounter the infamous exec <program>: exec format error.

Building the Image

To fix this, we need to build the container for the aarch64 architecture we're using:

britton-charlie@running-lion:~/plexmediaserver $ uname -m
aarch64
This is because we are running a 64-bit kernel, otherwise it would return armv7l. To build this, we copy the instructions from the README in the repository, and then we wait...
docker build --platform linux/arm64 -t plexinc/pms-docker:latest .

Well that was easy wasn't it? Oh wait no for some reason the build script is broken:

gzip: stdin: not in gzip format
tar: Child returned status 1
tar: Error is not recoverable: exiting now
The command '/bin/sh -c if [ "${TARGETPLATFORM}" = 'linux/arm/v7' ]; then         S6_OVERLAY_ARCH='armhf';       elif [ "${TARGETARCH}" = 'amd64' ]; then         S6_OVERLAY_ARCH='amd64';       elif [ "${TARGETARCH}" = 'arm64' ]; then         S6_OVERLAY_ARCH='aarch64';       fi     &&     curl -J -L -o /tmp/s6-overlay-${S6_OVERLAY_ARCH}.tar.gz https://github.com/just-containers/s6-overlay/releases/download/${S6_OVERLAY_VERSION}/s6-overlay-${S6_OVERLAY_ARCH}.tar.gz &&     tar xzf /tmp/s6-overlay-${S6_OVERLAY_ARCH}.tar.gz -C / --exclude='./bin' &&     tar xzf /tmp/s6-overlay-${S6_OVERLAY_ARCH}.tar.gz -C /usr ./bin &&     rm -rf /tmp/* &&     rm -rf /var/tmp/*' returned a non-zero code: 2

If this is also the case for you, then manually download with wget, then substitute a couple of lines in the build file to use the copy that's already downloaded, instead of letting the build script itself try.

wget https://github.com/just-containers/s6-overlay/releases/download/v2.2.0.3/s6-overlay-aarch64.tar.gz

Aside: making build context smaller

If you do this in the same order I did, and therefore have your config directory all setup, then Docker will copy this all across to the daemon before it tries to build, which in my case meant it had to read 2GB every time I tried to fix the build context.

echo "config" >> .dockerignore
This then reduced the overall size to 2.3MB, meaning it was effectively instant.

Finally, I saw the lines I like to see whenever fixing a build script:

Successfully built 9ce69f55bf8d
Successfully tagged plexinc/pms-docker:latest

After that, I ran docker-compose up and waited for it to come to life. Alas, this wouldn't work and yet more debugging of the build script was required. Looking at the root/installBinary.sh file and the Dockerfile, it was clear that the custom build was failing somewhere. The quickest fix for this is to just go to the Plex website and get the Ubuntu ARMv8 distribution here, setting this link as the ARG URL parameter in the Dockerfile.

Luckily, only one more docker build was needed, and fortunately this time their broken build script worked okay. Maybe I misread the instructions, but either way they were unclear and unhelpful when it broke.

Further Issues

Once I'd managed to get the server running, I had even more issues. As I network boot my Raspberry Pi, the latency on the database was really high. To somewhat alleviate this problem, I optimised the database in the settings. I then had to change the location of the movies and TV show libraries, as the import kept the paths from the old server.

Transcoding

The Raspberry Pi doesn't handle transcoding very well at 1080p and up. Therefore, to reduce the possibility that we have to transcode and thus probably not be able to stream on a TV, we need to either create optimised versions, or use something like PlexCleaner to ensure that everything can direct play.

Remote Access

Plex makes it easy to allow access outside the network, if you can login to the router and forward a port. From here, Plex manages access to the server through the specified port, but won't work unless manually setup.

To allow this to happen smoothly, you need to forward port 32400 from the internet to your local server IP.

Conclusions

This is a bit of a shorter one as it took somewhat longer to setup the server than first anticipated. Plex can be hosted on a Raspberry Pi within a Docker container if you put your mind to it, but it is a fair bit more cumbersome than just running it natively. Server installation is made harder by the issues with migrating, network booting the Pi, and the lack of processing power the Pi has, but allows 24/7 access as opposed to having a computer constantly on, and also means that less power is used watching your favourite TV shows.

Comments