How to Run Multiple Plex Servers on One NVIDIA GPU Using Incus and VMware ESXi
Build two independent Plex Media Servers that share one NVIDIA GPU by combining ESXi PCI passthrough, Ubuntu, and Incus system containers.
- Published
- Last updated
Introduction
What if you wanted to run two completely independent Plex Media Servers but only had one physical server and one NVIDIA GPU?
That was the problem I wanted to solve when designing my original home media infrastructure.
I wanted one Plex server dedicated to children’s movies and television shows, and another for adults. Both needed independent libraries, configurations, and network addresses. More importantly, both needed hardware-accelerated video transcoding without requiring separate GPUs.
Purchasing additional hardware seemed wasteful, particularly when most of the server’s resources would sit idle outside peak streaming hours.
My solution was to combine VMware ESXi, Ubuntu Linux, lightweight system containers, NVIDIA GPU sharing, and network-attached storage.
The architecture works by passing the physical GPU into a single Ubuntu virtual machine. Inside that VM, multiple Linux containers can access the same GPU through the host’s NVIDIA driver.
This guide walks through building that infrastructure from scratch using modern, supported software. We’ll also cover running Ubuntu directly on physical hardware, using local storage instead of a NAS, and optionally setting resource limits.
1. Understanding the architecture
Physical Server
CPU • RAM • NVIDIA GPU • Network • Storage
VMware ESXi — PCIe DirectPath I/O
Ubuntu Server VM
NVIDIA driver + Incus container manager
plex-kids
System container
Kids’ movies and TV
plex-adults
System container
Adults’ movies and TV
Shared NVIDIA GPU
Both containers access the same GPU through the VM’s driver
NAS via NFS
Network storage
Local Storage
Alternative option
On a bare-metal Ubuntu installation, remove the ESXi layer. The remaining architecture is the same.
There are two distinct operations involved:
GPU passthrough from ESXi to Ubuntu: VMware assigns the physical GPU exclusively to the Ubuntu VM.
GPU sharing from Ubuntu to containers: Incus exposes the GPU’s device interfaces and NVIDIA userspace libraries to multiple system containers. The containers share the Ubuntu VM’s Linux kernel and driver.
The GPU is not independently passed through to two virtual machines. That distinction is what makes this architecture possible without specialized GPU virtualization licensing.
Why Incus?
We’ll use Incus, a community-developed system-container manager that originated from the LXD project.
Incus allows each Plex installation to run in its own Linux environment without the overhead of another full VM.
Both containers can share the host’s CPU, memory, storage, and GPU while maintaining separate application installations and filesystems.
2. Requirements
| Component | Recommended configuration |
|---|---|
| Hypervisor | VMware ESXi 8.x or compatible version, optional |
| Ubuntu host/VM | Ubuntu Server 26.04 LTS |
| Container OS | Ubuntu 24.04 LTS |
| Container manager | Incus |
| GPU | NVIDIA GPU with supported NVENC/NVDEC capabilities |
| CPU | 4+ cores recommended |
| Memory | 16 GB recommended for the Ubuntu host/VM |
| Boot storage | SSD, with space for both Plex databases |
| Media storage | NFS NAS or locally attached disk |
| Networking | Gigabit Ethernet or faster |
| Plex | Two separate Plex Media Server installations |
The memory recommendation applies to the Ubuntu host or VM as a whole, not to each container.
We will not configure CPU or memory limits by default. Both containers will use available host resources as needed, subject to normal Linux scheduling and overall system capacity.
Hardware transcoding requires supported NVIDIA hardware and the appropriate Plex subscription entitlement. A Plex Pass or another eligible entitlement may be required.
Example network
We’ll use these illustrative addresses throughout the guide.
| Device | Address |
|---|---|
| Router | 192.168.1.1 |
| NAS | 192.168.1.10 |
| Ubuntu VM | 192.168.1.20 |
| Plex Kids | 192.168.1.101 |
| Plex Adults | 192.168.1.102 |
Replace these with addresses appropriate for your network.
3. Configure VMware ESXi GPU passthrough
Skip this section if Ubuntu is installed directly on physical hardware.
Before Ubuntu can share the GPU with its containers, the virtual machine must have direct access to the physical NVIDIA GPU.
Step 3.1 — Enable hardware virtualization
Restart the physical server and enter its BIOS/UEFI configuration.
Enable the appropriate settings for your processor and motherboard:
- Intel VT-d or AMD IOMMU
- CPU virtualization (Intel VT-x or AMD-V/SVM)
- Above 4G Decoding, if required by the platform and GPU
Save the configuration and reboot.
Step 3.2 — Enable GPU passthrough in ESXi
- Sign in to the VMware ESXi Host Client or vSphere Client.
- Select the physical ESXi host.
- Navigate to Manage/Configure → Hardware → PCI Devices.
- Locate the NVIDIA GPU.
- Enable passthrough using Toggle Passthrough.
- Reboot the ESXi host if prompted.
Some NVIDIA GPUs expose multiple PCI functions, such as graphics and HDMI/DisplayPort audio. Depending on the hardware, you may need to pass through associated functions as well.
Check the passthrough status after the host reboots.
Step 3.3 — Create the Ubuntu virtual machine
Create an Ubuntu Server VM with a suggested starting configuration:
| VM setting | Configuration |
|---|---|
| Guest OS | Ubuntu Linux 64-bit |
| vCPU | 4 or more |
| RAM | 16 GB |
| Boot disk | 80 GB or larger, preferably SSD-backed |
| Network adapter | VMXNET3 |
| Firmware | UEFI |
| GPU | NVIDIA PCI passthrough device |
The GPU’s compatibility with your ESXi release and platform must be verified. Not every consumer GPU and motherboard combination is officially supported.
Step 3.4 — Attach the GPU to the VM
With the VM powered off:
- Open the VM’s Edit Settings screen.
- Select Add New Device → PCI Device.
- Select the NVIDIA GPU.
- Add any required companion PCI functions.
- Enable Reserve all guest memory, or set a full memory reservation.
- Save the configuration.
For DirectPath I/O, VMware requires a reservation equal to the VM’s configured memory. This reservation is at the VMware VM level and is separate from container memory limits.
Depending on your GPU and ESXi configuration, you may also need to adjust the VM’s MMIO settings or firmware configuration. Use VMware’s compatibility guidance rather than applying arbitrary advanced VMX parameters.
Step 3.5 — Configure the virtual switch
Later, each Plex container will receive its own LAN IP address through macvlan networking.
This means the Ubuntu VM’s virtual network adapter must be able to send and receive traffic using additional MAC addresses.
On a standard VMware virtual switch, you may need to configure the relevant port group to allow:
| Security setting | Potential requirement |
|---|---|
| Promiscuous Mode | Accept |
| MAC Address Changes | Accept |
| Forged Transmits | Accept |
These settings depend on the switch type and network design. Apply them only to the dedicated port group used by this VM, not indiscriminately to the entire ESXi environment.
A VMware Distributed Switch may have additional security and MAC-learning options.
Step 3.6 — Install Ubuntu
Install Ubuntu Server 26.04 LTS normally.
During installation, configure SSH access and assign a stable network address to the VM, preferably through a DHCP reservation.
After installation, continue with the remaining steps inside Ubuntu.
4. Prepare Ubuntu and install the NVIDIA driver
From this point forward, commands run on the Ubuntu host or VM unless explicitly stated otherwise.
Update the system:
sudo apt update
sudo apt full-upgrade -y
Install the required utilities:
sudo apt install -y \
curl \
wget \
gnupg \
ca-certificates \
pciutils \
nfs-common \
ubuntu-drivers-common
Reboot if required:
sudo reboot
Step 4.1 — Verify GPU detection
Run:
lspci -nn | grep -i nvidia
The NVIDIA GPU should appear in the results.
If it doesn’t appear inside an ESXi VM, stop here and review the PCIe passthrough configuration.
Step 4.2 — Install the recommended NVIDIA driver
Check available drivers:
sudo ubuntu-drivers devices
Install the recommended driver:
sudo ubuntu-drivers install --recommended
Ubuntu provides this installation method for its current NVIDIA driver packages. It manages driver dependencies and integration with the installed kernel.
Reboot:
sudo reboot
Step 4.3 — Verify the driver
Run:
nvidia-smi
You should see your GPU model, driver version, and GPU memory information.
You can also inspect the kernel driver:
lspci -k -d 10de:
For the GPU’s display/3D controller function, the kernel driver should be NVIDIA.
Do not proceed until the GPU works correctly on the Ubuntu host. Incus cannot make a nonfunctional host GPU available to its containers.
5. Install Incus
Install Incus and the NVIDIA container integration tools:
sudo apt update
sudo apt install -y \
incus \
libnvidia-container-tools
Verify the NVIDIA runtime utility:
command -v nvidia-container-cli
This should return the path to the installed executable. If the package is unavailable, check the distribution’s enabled repositories and the official NVIDIA container-toolkit packaging for your release before proceeding.
Step 5.1 — Grant administrative access
sudo usermod -aG incus-admin "$USER"
Log out and back in, or start a new group session:
newgrp incus-admin
Step 5.2 — Initialize Incus
incus admin init
For a basic installation, configure:
- A local storage pool
- A managed network bridge, such as
incusbr0 - No clustering
- No public remote API listener
Choose a storage backend suitable for your disk layout. A directory-backed pool is simple; ZFS or Btrfs offers additional storage management features.
The managed bridge will provide temporary networking while we configure direct LAN access later.
Verify:
incus version
incus storage list
incus network list
incus profile show default
Incus’s official installation and initialization documentation provides additional storage and networking options.
6. Create the two Plex containers
We’ll use Ubuntu 24.04 LTS system containers for both Plex installations.
Create the first container:
incus launch images:ubuntu/24.04 plex-kids
Create the second:
incus launch images:ubuntu/24.04 plex-adults
Check their status:
incus list
Update both:
incus exec plex-kids -- apt update
incus exec plex-kids -- apt upgrade -y
incus exec plex-adults -- apt update
incus exec plex-adults -- apt upgrade -y
How resources are allocated
By default, Incus does not impose explicit CPU or memory limits on these containers.
Both Plex instances can use available CPU time and memory from the Ubuntu host or VM. Linux schedules the workloads dynamically.
For example, if only Plex Kids is actively transcoding, it can use the available host resources without being restricted by an artificial four-core limit.
When both servers are busy, they compete for the available resources under normal Linux scheduling.
This is the behavior we want for a small, shared-hardware deployment.
Resource limits are optional and covered later.
7. Make the NVIDIA GPU available to both containers
This is the central part of the configuration.
The Ubuntu host already controls the GPU. Incus will expose that GPU to both containers, allowing the two Plex installations to use hardware transcoding concurrently.
Step 7.1 — Stop both containers
incus stop plex-kids
incus stop plex-adults
Step 7.2 — Add the GPU devices
For a host with one NVIDIA GPU:
incus config device add plex-kids gpu0 gpu \
gputype=physical
incus config device add plex-adults gpu0 gpu \
gputype=physical
For hosts with multiple GPUs, specify the GPU’s PCI address using the pci device option so that both containers select the intended GPU.
The physical GPU device type supports Linux containers. Unlike exclusive GPU assignment to a full VM, multiple containers can reference the same host GPU.
Step 7.3 — Enable NVIDIA library integration
Configure the containers to receive the necessary NVIDIA userspace libraries from the Ubuntu host:
incus config set plex-kids nvidia.runtime=true
incus config set plex-adults nvidia.runtime=true
Configure the driver capabilities:
incus config set plex-kids \
nvidia.driver.capabilities=compute,utility,video
incus config set plex-adults \
nvidia.driver.capabilities=compute,utility,video
The video capability is particularly important for video acceleration. The runtime options are documented in Incus’s instance configuration reference.
Step 7.4 — Start both containers
incus start plex-kids
incus start plex-adults
Step 7.5 — Verify GPU visibility
Check the kids container:
incus exec plex-kids -- nvidia-smi
Check the adults container:
incus exec plex-adults -- nvidia-smi
Both should report the same NVIDIA GPU.
Also verify the device nodes:
incus exec plex-kids -- ls -l /dev/nvidia*
incus exec plex-adults -- ls -l /dev/nvidia*
If the NVIDIA utility or device nodes are missing, check the container startup logs and the host’s NVIDIA runtime integration before proceeding.
What happens when both servers use the GPU?
Both containers submit video-processing workloads to the same physical GPU.
They are not each assigned half of the GPU. Instead, the NVIDIA driver manages concurrent workloads, subject to available GPU resources, codec support, and hardware encoder-session limits.
This means additional Incus containers can also be configured to use the GPU in the same way, provided the hardware has enough capacity.
8. Configure media storage
We need somewhere to store the movies and television shows.
There are two approaches:
- Option A: Network-attached storage using NFS.
- Option B: Locally attached HDDs or SSDs.
Both approaches use the same final directory structure, so the Plex container configuration remains identical.
/srv/plex-media/
├── kids/
│ ├── movies/
│ └── tv/
└── adults/
├── movies/
└── tv/
The Ubuntu host handles storage access. The containers receive only the directories they need.
Option A — Configure NFS storage
This option is useful if your media already resides on a NAS running TrueNAS, Synology, Unraid, or another NFS-compatible system.
For this example, assume:
NAS IP: 192.168.1.10
NFS Export: /export/plex-media
Mount Point: /srv/plex-media
Your NAS must already have an NFS export configured and permit the Ubuntu host to access it.
Step A1 — Install the NFS client
sudo apt install -y nfs-common
Create the mount directory:
sudo mkdir -p /srv/plex-media
Step A2 — Mount the NAS
sudo mount -t nfs \
-o vers=4.1,ro \
192.168.1.10:/export/plex-media \
/srv/plex-media
The NFS export path may differ depending on the NAS configuration, particularly when using an NFSv4 pseudo-filesystem.
Verify:
findmnt /srv/plex-media
ls -la /srv/plex-media
Confirm that the kids and adults directories are visible.
Step A3 — Configure automatic mounting
Back up the existing mount configuration:
sudo cp /etc/fstab /etc/fstab.bak
Edit:
sudo nano /etc/fstab
Add this entry on one line:
192.168.1.10:/export/plex-media /srv/plex-media nfs4 ro,vers=4.1,_netdev,nofail,x-systemd.automount 0 0
Apply the changes:
sudo systemctl daemon-reload
sudo umount /srv/plex-media
sudo mount -a
Access the directory to trigger the automount, then verify the remote filesystem:
ls /srv/plex-media
findmnt -T /srv/plex-media
The mount should identify the NFS source, not just the underlying local directory.
The read-only setting helps prevent Plex from accidentally changing or deleting source media.
Option B — Configure local storage
If you don’t have a NAS, you can use an additional local HDD or SSD.
For an ESXi deployment, you can add a virtual disk backed by a datastore, or pass through an appropriate storage controller or device to Ubuntu.
The following example assumes a new, empty partition at /dev/sdb1.
Step B1 — Identify the disk
lsblk -f
Check disk sizes and filesystem information carefully:
lsblk -o NAME,SIZE,FSTYPE,UUID,MOUNTPOINTS,MODEL
If the disk is already formatted and contains your media, do not reformat it.
Step B2 — Format a new partition, if necessary
Warning: This command erases all data on the selected partition. Use it only on a verified, empty partition.
sudo mkfs.ext4 -L plex-media /dev/sdb1
If you’re starting with a completely blank disk rather than an existing partition, first create a GPT partition table and partition using your preferred disk-management tool.
Step B3 — Mount the filesystem
sudo mkdir -p /srv/plex-media
Find the UUID:
sudo blkid /dev/sdb1
Edit:
sudo nano /etc/fstab
Add:
UUID=YOUR-ACTUAL-UUID /srv/plex-media ext4 defaults,nofail 0 2
Mount:
sudo systemctl daemon-reload
sudo mount -a
Verify:
findmnt /srv/plex-media
df -h /srv/plex-media
Step B4 — Create the media directories
sudo mkdir -p \
/srv/plex-media/kids/movies \
/srv/plex-media/kids/tv \
/srv/plex-media/adults/movies \
/srv/plex-media/adults/tv
For newly created local media directories, set permissions so the host account responsible for managing media can write files, while the Plex service accounts can read them.
Avoid granting unrestricted write access to every local user.
9. Mount the media directories inside the containers
Regardless of whether you chose NAS or local storage, the containers will access their libraries at /media.
First, verify the storage source is mounted:
findmnt -T /srv/plex-media
Kids container
incus config device add plex-kids media disk \
source=/srv/plex-media/kids \
path=/media \
readonly=true
Adults container
incus config device add plex-adults media disk \
source=/srv/plex-media/adults \
path=/media \
readonly=true
These disk devices expose only the designated directories.
The kids container does not receive the adults’ directory, and the adults container does not receive the kids’ directory.
Verify:
incus exec plex-kids -- ls -la /media
incus exec plex-adults -- ls -la /media
Configure filesystem permissions
Incus containers are unprivileged by default. Their user IDs are mapped to different host IDs, which can affect access to host-mounted directories.
For local ext4 storage, one practical solution is to enable shifted disk mounts:
incus config device set plex-kids media shift=true
incus config device set plex-adults media shift=true
Restart the containers if required:
incus restart plex-kids
incus restart plex-adults
Shifted mounts require support from the host kernel and underlying filesystem. They may not work on every NFS mount.
For NFS, use a UID/GID and permissions strategy compatible with your NAS export. You can use ACLs or appropriate identity mappings, but do not make the containers privileged simply to bypass file permissions.
After installing Plex, we’ll verify access using the actual Plex service account.
10. Configure independent network addresses
Each Plex server should have its own IP address so both can use Plex’s default TCP port, 32400.
We’ll use macvlan networking to connect the containers directly to the local network.
Step 10.1 — Identify the network interface
On Ubuntu:
ip -br addr
ip route show default
Find the interface connected to your LAN.
For a VMware VM, this might be ens160. On a physical server, it could be eno1 or enp3s0.
In the examples below, we’ll use ens160. Replace this with your actual interface.
Step 10.2 — Stop the containers
incus stop plex-kids
incus stop plex-adults
Step 10.3 — Configure macvlan
The default Incus profile typically includes an eth0 device connected to the managed Incus bridge.
Override that device for each container:
incus config device override plex-kids eth0 \
nictype=macvlan \
parent=ens160
incus config device override plex-adults eth0 \
nictype=macvlan \
parent=ens160
Verify:
incus config show plex-kids --expanded
incus config show plex-adults --expanded
Each container should have a macvlan network interface connected to ens160.
Macvlan allows containers to use separate MAC addresses and receive IP addresses from the LAN’s DHCP server.
Step 10.4 — Start the containers
incus start plex-kids
incus start plex-adults
Check:
incus list
If DHCP is configured on your network, both containers should receive an address.
For stable addresses, create DHCP reservations on your router using the containers’ assigned MAC addresses.
Example:
| Container | IP address | Plex web interface |
|---|---|---|
| plex-kids | 192.168.1.101 | http://192.168.1.101:32400/web |
| plex-adults | 192.168.1.102 | http://192.168.1.102:32400/web |
Important macvlan considerations
Macvlan has a networking limitation: the Ubuntu host cannot normally communicate directly with its macvlan containers over the parent interface.
Other LAN devices can communicate with them.
If you need host-to-container communication, consider a Linux bridge instead.
Also, when running Ubuntu inside VMware, the virtual switch must permit traffic associated with the additional MAC addresses.
If the containers cannot obtain DHCP addresses, check the ESXi port-group security settings and upstream switch restrictions before changing the Ubuntu configuration.
11. Install Plex Media Server
Now that the containers have storage, networking, and GPU access, we can install Plex.
We’ll use Plex’s official package repository and signing key.
Step 11.1 — Install Plex in the kids container
Enter the container:
incus exec plex-kids -- bash
Install prerequisites:
apt update
apt install -y curl gnupg ca-certificates
Create the keyring directory:
install -d -m 0755 /etc/apt/keyrings
Download and install Plex’s repository signing key:
curl -fsSL \
https://downloads.plex.tv/plex-keys/PlexSign.v2.key \
| gpg --dearmor -o /etc/apt/keyrings/plexmediaserver.v2.gpg
Configure the repository:
echo "deb [signed-by=/etc/apt/keyrings/plexmediaserver.v2.gpg] https://repo.plex.tv/deb/ public main" \
> /etc/apt/sources.list.d/plex.list
Install Plex:
apt update
apt install -y plexmediaserver
Enable the service:
systemctl enable --now plexmediaserver
Verify:
systemctl status plexmediaserver
The repository and signing key follow Plex’s current Linux installation instructions.
Step 11.2 — Verify media access
Still inside the container, run:
runuser -u plex -- ls -la /media
Also test a library:
runuser -u plex -- ls -la /media/movies
If you receive Permission denied, resolve the storage permissions or UID/GID mapping before continuing.
Exit:
exit
Step 11.3 — Install Plex in the adults container
Enter:
incus exec plex-adults -- bash
Repeat the installation commands from Step 11.1.
Then verify:
runuser -u plex -- ls -la /media/movies
systemctl is-active plexmediaserver
Exit:
exit
Step 11.4 — Verify both installations
From the Ubuntu host:
incus exec plex-kids -- \
systemctl is-active plexmediaserver
incus exec plex-adults -- \
systemctl is-active plexmediaserver
Both should report:
active
12. Complete the Plex configuration
From another computer on the same LAN, open:
Plex Kids
http://192.168.1.101:32400/web
Plex Adults
http://192.168.1.102:32400/web
Replace the addresses with the actual IP addresses assigned to your containers.
Sign in to Plex and complete the server setup.
For initial server claiming, Plex may require a local trusted connection. If the setup wizard doesn’t allow claiming from another LAN computer, establish an SSH tunnel directly to the container.
For example, inside the container, install and enable SSH:
apt install -y openssh-server
systemctl enable --now ssh
Create an administrative account with a strong password or, preferably, SSH key authentication. From your workstation, establish a tunnel to that container:
ssh -L 8888:127.0.0.1:32400 adminuser@192.168.1.101
Then open:
http://127.0.0.1:8888/web
Repeat separately for the adults container, using its IP address. Do not expose SSH to the public internet.
Configure the media libraries
For Plex Kids, create the following libraries:
| Library | Directory |
|---|---|
| Movies | /media/movies |
| TV Shows | /media/tv |
For Plex Adults, create:
| Library | Directory |
|---|---|
| Movies | /media/movies |
| TV Shows | /media/tv |
Although the paths are identical, each container points to a different host directory.
Give the servers distinct names, such as Plex Kids and Plex Adults.
Use appropriate Plex account and library-access controls to prevent children’s accounts from accessing adult content. Separate containers provide filesystem and application separation, but account permissions are still essential.
13. Enable NVIDIA hardware transcoding
Open the Plex web interface for each server.
Navigate to:
Settings → Server → Transcoder
Enable the hardware transcoding options available to your account and Plex version:
- Use hardware acceleration when available
- Use hardware-accelerated video encoding
If Plex offers a hardware transcoding device selector, select the NVIDIA GPU.
Repeat this on both servers.
Test simultaneous GPU usage
Start a video on the kids server and another on the adults server.
For testing, select playback settings that force a supported video transcode rather than Direct Play.
On the Ubuntu host, monitor the GPU:
watch -n 1 nvidia-smi
You can also inspect video-engine utilization, where supported:
nvidia-smi dmon -s u
Check both Plex dashboards. Hardware-accelerated video transcoding should be indicated by (hw).
If both streams are transcoding with hardware acceleration, the GPU-sharing configuration is functioning.
Remember that the number of concurrent streams depends on GPU capability, supported codecs, available resources, and NVIDIA driver limits. Sharing a GPU does not remove those limits.
14. Optional: Configure CPU and memory limits
By default, we have not applied any CPU or memory limits to either container.
This is intentional.
If the Ubuntu VM has 8 vCPUs and 16 GB of RAM, both Plex containers can draw from those available resources as needed.
A container does not reserve all the resources it can see. Actual usage depends on workload demand and Linux scheduling.
For most small installations, leaving resource limits unset is a reasonable starting point.
When limits might be useful
You may want to introduce limits if one server consistently consumes resources needed by the other, or if the Ubuntu host runs additional services.
For example, to limit Plex Kids to four vCPUs and 4 GiB of memory:
incus config set plex-kids limits.cpu=4
incus config set plex-kids limits.memory=4GiB
To apply the same limits to Plex Adults:
incus config set plex-adults limits.cpu=4
incus config set plex-adults limits.memory=4GiB
These are ceilings, not resource reservations.
To remove the limits and restore the default behavior:
incus config unset plex-kids limits.cpu
incus config unset plex-kids limits.memory
incus config unset plex-adults limits.cpu
incus config unset plex-adults limits.memory
Verify:
incus config show plex-kids --expanded
incus config show plex-adults --expanded
Recommendation: Start without limits. Monitor actual CPU and memory consumption before deciding whether restrictions are necessary.
15. Configure automatic startup
We want both Plex servers to start automatically whenever Ubuntu boots.
Enable Incus autostart:
incus config set plex-kids boot.autostart=true
incus config set plex-adults boot.autostart=true
Verify:
incus config get plex-kids boot.autostart
incus config get plex-adults boot.autostart
Both should return true.
Additional considerations for NAS users
If your media resides on a NAS, storage availability becomes an important startup dependency.
With the systemd NFS automount configured earlier, the host can mount the share on demand.
However, an unavailable NAS can still prevent Plex from accessing its libraries.
For NAS-backed deployments, I recommend testing these conditions before relying on automatic startup:
- Reboot Ubuntu while the NAS is online and verify that the media directories are accessible.
- Confirm that both Plex containers start successfully and can scan their libraries.
- Temporarily make the NAS unavailable during a controlled maintenance test and observe the recovery behavior.
For a more controlled production deployment, use a systemd-managed startup unit that verifies the NFS filesystem and expected directories before starting the containers, with Incus autostart disabled to avoid competing startup paths.
Do not use a simple directory-existence check as proof that NFS is mounted; the local mount-point directory may exist even when the NAS is offline.
For local storage, ensure that the media disk is mounted before the Incus containers start.
16. Monitoring and maintenance
Useful commands for managing the environment:
| Task | Command |
|---|---|
| List containers | incus list |
| Show container resources | incus info plex-kids |
| Monitor container metrics | incus top |
| Show GPU status | nvidia-smi |
| Check media mount | findmnt -T /srv/plex-media |
| Restart kids server | incus restart plex-kids |
| Restart adults server | incus restart plex-adults |
| Stop kids server | incus stop plex-kids |
| Start kids server | incus start plex-kids |
Update Ubuntu
sudo apt update
sudo apt upgrade -y
Update both containers
incus exec plex-kids -- apt update
incus exec plex-kids -- apt upgrade -y
incus exec plex-adults -- apt update
incus exec plex-adults -- apt upgrade -y
Check Plex service logs
incus exec plex-kids -- \
journalctl -u plexmediaserver -n 100 --no-pager
incus exec plex-adults -- \
journalctl -u plexmediaserver -n 100 --no-pager
Back up the containers
Before major updates, consider stopping Plex and exporting the containers:
incus stop plex-kids
incus stop plex-adults
incus export plex-kids plex-kids-backup.tar.gz
incus export plex-adults plex-adults-backup.tar.gz
Start them again:
incus start plex-kids
incus start plex-adults
The exports contain the containers’ root filesystems and configuration, but externally mounted NAS or host media directories are not included as ordinary container data.
Back up the media separately.
Keep copies of the backups on another physical device or storage system.
17. Troubleshooting
| Issue | Possible cause | Recommended action |
|---|---|---|
| GPU missing inside Ubuntu VM | ESXi passthrough misconfiguration | Check PCI device assignment, IOMMU, VM memory reservation |
nvidia-smi fails on Ubuntu |
Driver or kernel issue | Check installed driver, kernel modules, Secure Boot |
| GPU works on Ubuntu but not in containers | Incus device or runtime configuration | Check GPU device, NVIDIA runtime settings and host tools |
| Plex uses CPU transcoding | Hardware acceleration not active | Check Plex entitlement, transcoder settings and video capabilities |
| Containers don’t receive LAN addresses | Macvlan or VMware switch restrictions | Check DHCP, parent NIC and virtual switch security |
| Plex cannot read movies | Filesystem permission mismatch | Check the Plex service account and UID/GID mapping |
| NAS media disappears | NFS disconnected | Verify mount status and NAS connectivity |
| Playback buffers during multiple transcodes | GPU, CPU, disk or network saturation | Monitor utilization and reduce simultaneous transcoding demand |
Troubleshooting GPU access
First verify the GPU on the Ubuntu host:
nvidia-smi
Then inspect the container GPU configuration:
incus config device show plex-kids
incus config device show plex-adults
Check the runtime settings:
incus config get plex-kids nvidia.runtime
incus config get plex-adults nvidia.runtime
Finally, check GPU visibility inside each container:
incus exec plex-kids -- nvidia-smi
incus exec plex-adults -- nvidia-smi
If GPU visibility works but Plex still does not hardware-transcode, check whether the required NVIDIA video-encoding libraries are available to Plex and whether the selected video format is supported by the GPU.
Troubleshooting media permissions
Run:
incus exec plex-kids -- \
runuser -u plex -- ls -la /media/movies
If access fails, inspect the directory ownership and permissions on the Ubuntu host and inside the container.
Do not make a container privileged or grant unrestricted permissions simply to bypass an access problem.
Troubleshooting network connectivity
Inspect the network interfaces:
incus exec plex-kids -- ip addr
incus exec plex-adults -- ip addr
Check the default routes:
incus exec plex-kids -- ip route
incus exec plex-adults -- ip route
Test connectivity to the gateway:
incus exec plex-kids -- ping -c 3 192.168.1.1
If DHCP and connectivity fail in an ESXi deployment, verify that the virtual switch permits the additional MAC addresses.
18. Why this architecture makes sense
A traditional solution might involve running two separate virtual machines, each with its own Plex installation.
That approach works well for application isolation, but sharing a single physical GPU between the VMs can be difficult without specialized GPU virtualization features.
Linux system containers offer a different model.
| Feature | Separate VMs | Incus system containers |
|---|---|---|
| Independent Plex installations | Yes | Yes |
| Separate libraries and settings | Yes | Yes |
| Independent network identities | Yes | Yes |
| Shared host kernel | No | Yes |
| Share a physical GPU without GPU partitioning | Not with ordinary exclusive PCIe passthrough | Yes |
| Independent CPU and RAM limits | Yes | Optional |
| NAS storage support | Yes | Yes |
| Local storage support | Yes | Yes |
| Typical virtualization overhead | Higher | Lower |
The biggest advantage is resource consolidation.
When neither Plex server is transcoding, the GPU remains available for other workloads. When one server needs acceleration, it can use the GPU. When both require acceleration, they can share it within the GPU’s supported capabilities.
The same principle applies to CPU and memory. We don’t have to permanently allocate a fixed number of cores to each Plex installation.
And because the media is stored separately from the containers, we can rebuild or replace a Plex instance without moving the entire media collection.
Conclusion
The original goal was to create two independent Plex Media Servers without buying two physical servers or two NVIDIA GPUs.
By combining VMware ESXi, Ubuntu, Incus system containers, and shared NVIDIA GPU access, we can achieve that goal with a single physical machine.
The architecture provides independent Plex installations, separate media libraries, dedicated network addresses, and access to a shared hardware transcoding engine.
For users who already have a NAS, NFS keeps media storage centralized. For users without network storage, locally attached disks work just as well.
And because Incus containers share the host’s resources dynamically, there’s no need to impose artificial CPU or memory limits unless the workload demands it.
One physical host. Two independent Plex servers. One shared NVIDIA GPU.
The result is a practical, resource-efficient home media infrastructure that can be expanded to additional services as needed.
Official documentation
- Broadcom — VMware PCI device passthrough
- Ubuntu — NVIDIA driver installation
- Incus — Installation
- Incus — GPU devices
- Incus — Instance configuration
- Incus — Network interface types
- Incus — Disk devices
- Plex — Linux repository installation
- Plex — Hardware-accelerated streaming
Editorial validation: The GPU-sharing design, ESXi passthrough requirements, Incus configuration options, and Plex repository commands have been checked against official documentation. The complete deployment has not been end-to-end tested on a fresh Ubuntu 26.04 installation. In particular, verify the NVIDIA container integration, shifted filesystem mounts, and Plex hardware transcoding with your selected GPU before marking the guide production-validated.
Sources & credits
- Broadcom — VMware PCI device passthrough ↗
- Ubuntu — NVIDIA driver installation ↗
- Incus — GPU devices ↗
- Incus — Network interface types ↗
- Plex — Hardware-accelerated streaming ↗
- Written and curated by E Vang for The Binary Report.