Plex Media Server on a Mini PC: Complete Setup Guide
Run Plex on a low-power mini PC with Docker. Full Compose config, hardware transcoding setup, remote access, and an honest look at what Plex Pass actually costs.
This post contains affiliate links. If you buy through them, I earn a small commission at no extra cost to you.
Plex is the path of least resistance for self-hosted media. You point it at a folder of movies and TV files, it fetches artwork and metadata, and thirty minutes later you have something that looks like a streaming service on every TV in the house. The apps are genuinely good, they are on every platform worth caring about, and non-technical family members can use it without a tutorial.
I run both Plex and Jellyfin. If you are still deciding between them, Plex vs Jellyfin is the honest comparison, and the Jellyfin setup guide covers the other side. This guide is about getting Plex running well on cheap, low-power hardware. If you have not set up Docker yet, start with how to start a homelab and Docker Compose basics.
Quick Answer: How to Set Up Plex on a Mini PC
- Grab a claim token from plex.tv/claim (it expires in four minutes)
- Create directories for config, transcode scratch, and media
- Write a
docker-compose.ymlusingplexinc/pms-dockerwithnetwork_mode: host - Run
docker compose up -dand openhttp://your-server-ip:32400/web - Add libraries pointing at your media, using Plex naming conventions
- Enable hardware transcoding by passing through
/dev/dri(Plex Pass required) - Set up remote access via port forward, reverse proxy, or Tailscale
Why a Mini PC Is the Right Box for This
Plex has a reputation as a CPU hog. That reputation comes from software transcoding, and software transcoding is a problem you can design around rather than buy your way out of.
Any modern Intel chip with QuickSync will hardware-transcode multiple 1080p streams while sitting at low single-digit wattage. An N100 or N150 mini PC costs less than a mid-range GPU, draws roughly the power of a phone charger under normal load, and runs Plex alongside a dozen other containers. The best mini PCs for a budget homelab covers current picks, and Beelink vs Minisforum compares the two vendors most people end up choosing between.
The one specification that matters here is Intel QuickSync. Not core count, not clock speed. A four-core N100 with QuickSync will outperform a much larger CPU without it for this specific workload.
| Workload | Hardware transcode | Software transcode |
|---|---|---|
| 1080p to 1080p | Trivial, several at once | Manageable, one or two |
| 4K to 1080p | Fine on QuickSync | Will bury a low-power CPU |
| Direct play (no transcode) | No CPU cost either way | No CPU cost either way |
Direct play is the goal. Transcoding is the fallback. Everything below is about making the fallback cheap.
Prerequisites
- A Linux server with Docker and Docker Compose installed
- Media files on the server or on a mounted network share
- A free Plex account
- About an hour
If you are running this on Proxmox, decide first whether Plex goes in a VM or an LXC. Hardware transcoding is meaningfully easier to pass into a privileged LXC than a VM, but the Proxmox VM vs LXC guide covers the tradeoffs. The LXC Docker template guide is the fastest route to a container host.
Step 1: Get a claim token
Go to plex.tv/claim while signed in and copy the token. It looks like claim-xxxxxxxxxxxxxxxxxxxx.
This token expires in four minutes. Get it immediately before you start the container, not while you are still writing your Compose file. If it expires, refresh the page and get a new one.
The claim token is what binds a fresh server to your Plex account without you having to be on the same network as the server during setup. Skip it and you will end up fighting an “unclaimed server” screen.
Step 2: Create the directory structure
mkdir -p /opt/plex/{config,transcode}
mkdir -p /data/media/{movies,tvshows,music}
What each of these does:
/opt/plex/config: the Plex database, metadata, artwork, and watch history. This is the directory you back up. It grows large over time because Plex caches artwork aggressively./opt/plex/transcode: scratch space for in-progress transcodes. Completely disposable. Put it on an SSD if you can, and never back it up./data/media/*: your actual media
If your media lives on a NAS, mount the share on the host first and point the Compose file at the mount path. Do not try to mount network shares inside the container. The homelab storage options article covers the layout decision if you have not made it yet.
Step 3: Write the Docker Compose file
Create /opt/plex/docker-compose.yml:
services:
plex:
image: plexinc/pms-docker:latest
container_name: plex
network_mode: host
environment:
- TZ=America/New_York
- PLEX_CLAIM=claim-xxxxxxxxxxxxxxxxxxxx
- PLEX_UID=1000
- PLEX_GID=1000
- ADVERTISE_IP=http://192.168.1.50:32400/
volumes:
- /opt/plex/config:/config
- /opt/plex/transcode:/transcode
- /data/media:/data:ro
devices:
- /dev/dri:/dev/dri
restart: unless-stopped
The parts worth understanding:
network_mode: host: Plex uses GDM broadcast discovery so clients on your LAN can find the server automatically. Bridge networking breaks that and produces the classic “server shows up on the internet but not on my own TV” problem. Use host networking.
PLEX_CLAIM: your token from Step 1. After the first successful start, this value is ignored. You can leave it in the file or clear it out.
ADVERTISE_IP: replace 192.168.1.50 with your server’s actual LAN address. This tells Plex which address to hand out to clients. Without it, Plex sometimes advertises a Docker-internal address that nothing can reach.
PLEX_UID / PLEX_GID: run id on the host and use your own values. The container needs read access to your media as this user.
/data:ro: mounted read-only. Plex has no reason to write to your media library, and a read-only mount means a misconfigured setting can never delete your files.
devices: /dev/dri: passes the Intel iGPU through for QuickSync. If your host has no /dev/dri, remove these two lines or the container will refuse to start. Check with ls -l /dev/dri first.
Step 4: Start the container and claim the server
cd /opt/plex
docker compose up -d
docker compose logs -f plex
Watch the logs until they settle. Then open http://192.168.1.50:32400/web in a browser, substituting your server’s IP.
If the claim token worked, you land in the setup wizard already signed in as yourself. If you get an “unclaimed server” prompt instead, the token expired. Stop the container, get a fresh token, update the Compose file, and start it again:
docker compose down
# edit PLEX_CLAIM with a new token
docker compose up -d
Step 5: Add your media libraries
In the wizard, add a library for each media type and point it at the container path, not the host path. Because of the volume mapping above, /data/media/movies on the host is /data/movies inside the container.
Plex’s metadata matching depends heavily on file naming. Follow these patterns:
/data/movies/Arrival (2016)/Arrival (2016).mkv
/data/tvshows/Severance/Season 01/Severance - S01E01.mkv
The year in parentheses for movies and the SxxExx pattern for TV are what the matcher keys on. Get this right up front and you will spend almost no time fixing wrong matches later. Get it wrong and you will be manually identifying items for an hour.
One setting worth changing during setup: turn off “Include my library in the Plex catalog and enable Discover features” unless you specifically want your library titles shared with Plex’s cloud services. It has no effect on local playback.
Step 6: Enable hardware transcoding
This step requires Plex Pass. Hardware transcoding is the single most valuable thing behind the paywall, and on a low-power mini PC it is the difference between the server working and the server choking.
First confirm the container can see the GPU:
docker exec -it plex ls -l /dev/dri
You should see renderD128 and card0. If the directory is empty or missing, the passthrough is not working. On a Proxmox LXC, this usually means the device is not mapped into the container config.
Then in the Plex web UI:
- Settings > Transcoder
- Check Use hardware acceleration when available
- Check Use hardware-accelerated video encoding
- Set Transcoder temporary directory to
/transcode
To verify it is actually working, play something that forces a transcode (drop the client’s quality setting to 720p) and open the Now Playing dashboard. You want to see Transcode (hw). If it says Transcode with no (hw), the acceleration is not engaging, and the cause is nearly always the device passthrough rather than the Plex setting.
Step 7: Set up remote access
You have three reasonable options, in increasing order of how much I would recommend them.
Plex Remote Access. Settings > Remote Access, enable it, forward TCP 32400 to your server. Simple, and it silently fails behind CGNAT or double NAT, which describes a lot of cable and cellular home internet. If the indicator will not go green and your ISP gives you a shared IP, stop fighting it.
Reverse proxy. Put Plex behind Nginx Proxy Manager with a real certificate on a subdomain. Cleaner URLs and one place to manage TLS, but you are still exposing a service to the internet.
Tailscale. Tailscale puts your server and your devices on the same private network with nothing forwarded and nothing exposed. For a server that only you and your household use, this is the right answer. The tradeoff is that every client device needs Tailscale installed, which rules out most smart TVs and streaming sticks.
I use Tailscale for anything I do not need to share broadly, and it removes an entire category of security worry. The homelab security guide covers the general principle: the service you never exposed is the one that never got compromised.
What Plex Pass Actually Costs
Plex is free to run. The paid tier gates a specific set of features, and it is worth being clear about which ones actually matter for a homelab.
| Feature | Free | Plex Pass |
|---|---|---|
| Local streaming and library management | Yes | Yes |
| Metadata, artwork, apps on most platforms | Yes | Yes |
| Hardware transcoding | No | Yes |
| Mobile downloads and sync | No | Yes |
| Skip intro and credits detection | No | Yes |
| Live TV and DVR | No | Yes |
Pricing has moved more than once, so check the current monthly, annual, and lifetime numbers directly rather than trusting a figure in any guide, including this one.
The honest math: if your clients direct play everything, the free tier is genuinely fine and you should not pay. If you stream to phones on cellular, share with family on unpredictable connections, or keep 4K files that need downscaling, hardware transcoding is the feature you are buying and it is the one that justifies the cost. If neither applies and you resent subscriptions on principle, Jellyfin does hardware transcoding for free and the setup guide is right here.
Backups
Back up /opt/plex/config. Skip /opt/plex/transcode entirely.
0 3 * * * docker compose -f /opt/plex/docker-compose.yml stop plex && \
tar -czf /backup/plex-config-$(date +\%Y\%m\%d).tar.gz /opt/plex/config && \
docker compose -f /opt/plex/docker-compose.yml start plex
Stopping the container first matters more here than it does for most services. Plex’s database is SQLite and under active write, and a tarball taken mid-write can restore into a corrupt database. A brief nightly restart is a fair trade for a backup that actually works.
Watch the size. The config directory grows steadily because of cached artwork, and it is normal for it to reach several gigabytes on a large library. Compress, rotate, and keep a week. The homelab backup strategy covers the wider picture, and if Plex is on a Proxmox guest, snapshots and backups handle the VM layer.
Updating
cd /opt/plex
docker compose pull
docker compose up -d
Plex ships updates frequently. If you would rather not do this by hand, Watchtower automates it, though for a media server that family members depend on there is an argument for updating deliberately instead.
Troubleshooting
Server not visible on the local network. Almost always bridge networking. Confirm network_mode: host and that ADVERTISE_IP matches the server’s real LAN address.
Transcoding when it should direct play. Open Now Playing and read the reason Plex gives. Image-based subtitles (PGS, VOBSUB) force a video transcode because they have to be burned into the picture. Client-side bandwidth caps do the same. Subtitles are the usual answer.
Permission denied on media. The container runs as PLEX_UID/PLEX_GID. Confirm that user can read the media directory on the host: sudo -u \#1000 ls /data/media/movies.
Hardware transcoding not engaging. Check /dev/dri inside the container first. If the device is there and it still will not engage, confirm Plex Pass is active on the account the server is claimed to, not just on your personal account.
Database corruption after an unclean shutdown. Plex ships a repair path in Settings > Troubleshooting, but the reliable fix is restoring last night’s config backup. This is why the backup above stops the container.
The Hardware, Briefly
If you are buying for this specifically, the shopping list is short. A mini PC with an Intel N100 or N150 covers the server itself, and the QuickSync engine on those chips is what makes the whole setup viable at low wattage. Storage is the other half: an external USB SSD or hard drive is the cheap starting point, though a proper NAS is the better long-term answer once your library outgrows a single drive.
Power draw is genuinely low. If you are curious how a box like this compares to the rest of a rack, homelab power usage breaks down the numbers, and building a homelab under $300 shows what else fits on the same hardware alongside Plex.
Where This Leaves You
A mini PC running Plex in Docker with QuickSync enabled is a media server that costs almost nothing to run, survives reboots, updates in two commands, and restores from a tarball. That is a better position than most people’s setups, and it took an hour.
The natural next steps are monitoring, so you can see what the box is actually doing under load (Grafana and Prometheus), and a dashboard to tie your services together as you add more of them. If you find yourself resenting the Plex Pass paywall every time you look at the transcoder settings, that is a signal worth listening to, and Jellyfin is a same-afternoon migration.