Featured image of post Why Unprivileged LXC + NFS = Regret (Here’s How I Learned the Hard Way)

Why Unprivileged LXC + NFS = Regret (Here’s How I Learned the Hard Way)

I spent weeks fighting invisible permission walls,. Don’t make the same mistake.

I spun up some unprivileged LXCs on Proxmox (Jellyfin, Sonarr, Radarr, and Audiobookshelf). The plan was to keep it lightweight, clean, and have them all talk to my NAS over NFS.

That plan lasted about a week.

What followed was a parade of silent failures, missing files, and permission bugs that made me question reality. Unprivileged sounded safe. Turns out LXCs are just too stripped down to work reliably if you need NFS access.

Let me show you why unprivileged LXC is a trap for anything that needs NFS access, and how I crawled back to VMs running Docker. Humbled but functional.

💭 TL;DR
Unprivileged LXC + NFS seems awesome and secure until root mapping, id shifts, and bind mount hell break your stack. Use privileged LXC or, better yet for NFS, a VM. I learned this the hard way with Proxmox.

The Two Faces of LXC: Privileged vs Unprivileged

LXC containers come in two flavors: privileged and unprivileged. That one word changes everything about how your containers behave, what they can access, and how much pain you’ll experience.

🔓 Privileged Containers: Power at a Price

A privileged container runs as root on the host. Not “container root.” Actual host root.

What that means:

  • Container UID 0 = host UID 0
  • Full access to system calls
  • Direct read/write access to host files
  • Minimal UID translation (things just work with NFS, USB devices, bind mounts, etc.)

Sounds scary? It should be. If a service inside that container gets compromised, the attacker now has root on your host. Full stop.

When privileged LXC makes sense:

  • Internal-only services you fully trust
  • Containers behind a firewall, with zero external exposure
  • Services that need real root access

🔒 Unprivileged Containers: Safe but Issues with NFS

Unprivileged containers were designed to fix that security risk by adding a layer of UID mapping.

They add 100000 to all container UIDs:

  • Container UID 0 → host UID 100000
  • Container UID 1000 → host UID 101000
  • And so on…

So even if something breaks inside, the container can’t mess with your host. It’s sandboxed. Safe.

But here’s the catch: that UID mapping breaks everything outside the container.

  • NFS doesn’t recognize 100000 as root.
  • File permissions stop making sense.
  • Accessing anything shared with the host becomes a pain.

Unprivileged containers work great when:

  • You don’t need to write to NFS
  • You don’t care about permissions on shared files
  • You want to sandbox a sketchy app or test environment

So Which One Should You Use?

Use Case Best Container Type
Running Jellyfin/Arr stack with NFS Virtual Machine or Privileged
Public-facing container Virtual Machine or Unprivileged
Docker inside LXC Privileged (not recommended)
Internal utility that touches host fs Privileged
Unsafe app or 3rd-party binary Unprivileged

Bottom line:
Privileged = easier, more powerful, more dangerous
Unprivileged = safer, but crippled when it comes to real-world file access

And if you’re mixing in NFS?
Unprivileged goes from “safe” to “useless.”

MINISFORUM MS-A2

MINISFORUM MS-A2
A Ryzen-powered beast in a mini PC shell. Dual 2.5 GbE, 10 GbE option, triple NVMe. Small box, big Proxmox energy.

Contains affiliate links. I may earn a commission at no cost to you.

My Descent Into Troubleshooting Hell

Let me walk you through the steps I took. Each one with hope, each one crushed by reality. If this looks like your future, do yourself a favor and skip ahead to VMs now.

Attempt #1: Custom UID Mapping

I tried overriding lxc.idmap to fake container UID 0 as host UID 1000:

lxc.idmap: u 0 100000 1000
lxc.idmap: g 0 100000 1000
lxc.idmap: u 1000 101000 1
lxc.idmap: g 1000 101000 1
lxc.idmap: g 1001 101001 1
lxc.idmap: u 1001 101001 64534
lxc.idmap: g 1002 101002 64534

Result: Partially worked, but created more permission edge cases.

Attempt #2: NFS Export Tweaking

I tried various NFS settings and settled on this:

/media/Storage/ *(all_squash,anongid=1001,anonuid=1000,insecure,rw,fsid=100,subtree_check)

Result: Files appeared but the permissions were still an issue.

Attempt #3: Host Mount + Bind Mount

I mounted NFS on the host, then bind-mounted into the LXC:

mp0: /mnt/storage/Shows,mp=/media/Shows
mp1: /mnt/storage/Movies,mp=/media/Movies
mp2: /mnt/storage/Music,mp=/media/Music
mp3: /mnt/storage/eBooks,mp=/media/eBooks
mp4: /mnt/storage/AudioBooks,mp=/media/AudioBooks

Result: Files showed up but were owned by nobody:nogroup. Jellyfin couldn’t scan, play, or write. When the host mount failed during reboots, containers booted with empty folders. Silent disasters everywhere.

Attempt #4: The bindfs Hail Mary

In my final attempt, I tried bindfs to remap ownership:

[Unit]
Description=Bindfs mounts for NAS directories
Requires=mnt-nas_storage.mount

[Service]
Type=oneshot
ExecStart=/usr/bin/bindfs -u 101000 -g 101001 /mnt/nas_storage /mnt/mapped_nas_storage
RemainAfterExit=true

[Install]
WantedBy=multi-user.target

Result: This worked the best, but I’d still randomly lose files. Every workaround fixed one thing and broke three more.

I’m sure someone has forced unprivileged LXCs to work, but I just want to enjoy my media and not be constantly fight with permissions.


The Privileged Container Security Trap

So what’s the catch with using a privileged container to fix NFS? You’ve now handed root access from the container directly to the host.

Root inside = root outside

If someone compromises Jellyfin (or any dependency), they’re root on your Proxmox node. Game over.

Security Misconfigurations

Most people don’t harden their containers. Leave one small crack that someone could exploit, and the container can damage your host or pivot to other network devices.

Network Exposure Risks

Privileged containers can mess with host-level network settings. Bridge them carelessly, and an attacker could sniff or spoof traffic across your entire LAN.

Shared kernel = Shared fate

Containers don’t isolate the kernel. A bug in ffmpeg, libva, or any media processing library could expose your entire host system.

It’s not a sandbox. It’s a potential backdoor.

TP-Link Omada SG3210X-M2

TP-Link Omada SG3210X-M2
Full-featured, compact, rack-ready. Eight multi-gig ports, dual 10 GbE uplinks, VLAN/QoS/ACL/LACP, and seamless integration with TP‑Link’s Omada controller. It locks down your Jellyfin/NAS traffic while scaling effortlessly with your homelab.

Contains affiliate links. I may earn a commission at no cost to you.

The Solution: Embrace VMs with Docker

After weeks of fighting with LXC permissions, I gave up and moved everything to VMs running Docker. Here’s why this works:

True Isolation

VMs provide actual isolation. If Jellyfin gets compromised, the attacker is trapped in a virtual machine and not loose on your host.

Docker Handles Permissions

Docker’s built-in user mapping and volume mounts handle NFS permissions much more gracefully than LXC’s UID mapping.

Predictable Behavior

No more silent failures, missing files, or permission mysteries. Things work the way you expect them to.


Final Recommendations

For Jellyfin + NFS + Remote Access:

  • Use a VM with Docker (best option)
  • Use privileged LXC only if it’s internal-only and you understand the risks
  • Avoid unprivileged LXC entirely for this use case

For Other Use Cases:

  • Internal utilities: Privileged LXC is fine
  • Public-facing services: Unprivileged LXC or VM
  • Anything touching NFS: VM with Docker

The Bottom Line:

Unprivileged LXC sounds safe until it isn’t. Add NFS, media servers, and remote access, and you’re stacking pain on top of pain.

I’ve patched, mounted, and prayed my way through this mess. My final verdict? If you’re doing anything serious with NFS or Jellyfin, ditch the LXC complexity and use VMs with Docker.

Don’t fight your stack. If you need NFS, go VM. If you’re exposing Jellyfin publicly, go VM. Save your sanity and your weekends.

TP-Link 2.5GB PCIe Network Card (TX201)

TP-Link 2.5GB PCIe Network Card (TX201)
Plug-and-play 2.5 GbE PCIe card that unlocks multi-gig speeds for about $30. Works out of the box with Proxmox, Linux, and Windows. No drama—just faster transfers.

Contains affiliate links. I may earn a commission at no cost to you.

© 2024 - 2025 DiyMediaServer

Buy Me a Coffee

Built with Hugo
Using a modified Theme Stack designed by Jimmy