Docker Storage Drivers: fuse-overlayfs vs overlay2 for Proxmox LXC

Choose between fuse-overlayfs and overlay2 drivers when running Docker in unprivileged or privileged LXC containers on Proxmox VE—get better performance, security, and GPU passthrough.

Proxmox Pulse Proxmox Pulse
9 min read
Two transparent storage layers hovering over server drives, one frosted and clear.

Docker gives you fast container startup times, lightweight resource usage, and a massive ecosystem of pre-built images—without the overhead of full virtual machines. On Proxmox VE, you can run Docker inside LXC containers rather than dedicating entire VMs to it, which saves CPU, memory, and disk space across your cluster. The trick is choosing between unprivileged and privileged storage drivers correctly for your workload type.

Key Takeaways

  • Unprivileged Works — Most homelab workloads run fine with fuse-overlayfs in an unprivileged LXC container without any special capabilities beyond what's already enabled by default.
  • Driver Choice Matters — The overlay2 driver needs privileged mount or cgroup v1, while fuse-overlayfs works everywhere but adds some CPU overhead; pick based on your storage backend and workload type.
  • GPU Needs Privileged Mode — If you plan to pass through a GPU for AI inference workloads like Ollama, your LXC container must be privileged so Docker can access the device node directly.

How to Choose Between Unprivileged and Privileged Storage Drivers?

The most common point of confusion when setting up Docker inside an LXC container is which storage driver to use—and whether that choice forces you into privileged mode or keeps you in unprivileged mode. This matters because it affects both security posture and performance characteristics, especially for long-running workloads like databases, media servers, and AI inference engines.

Proxmox VE uses cgroup v2 by default starting with version 9+, which changes how overlay storage drivers behave inside containers compared to older releases that used cgroup v1 natively. Understanding this difference prevents the "overlay not supported" errors many administrators encounter when they first try Docker in an LXC container on a fresh Proxmox install.

The two primary options are fuse-overlayfs and overlay2. The former is built into most modern Linux distributions through kernel FUSE support, while overlay2 relies on direct mount calls that traditionally required privileged containers to work correctly inside unprivileged LXCs. Here's the practical breakdown:

Driver Privileged Required? Performance Best For
fuse-overlayfs No (works in unprivileged) ~5-10% overhead from FUSE layer Homelab, mixed workloads, GPU passthrough with caveats
overlay2 Yes (unless using cgroup v1 or lxc.apparmor.profile=unconfined) Lower CPU usage, direct mount calls High-throughput I/O, databases, heavy container churn

If you're running a homelab and want to keep your LXC containers unprivileged for the security benefits—which include better isolation between workloads on the same host—fuse-overlayfs is almost always the right choice. The performance penalty exists but rarely matters in practice unless you have thousands of IOPS hitting container filesystems continuously, which most Docker-based homelab applications don't generate at that scale anyway.

How to Set Up a LXC Container for Docker?

Start by creating an LXC container from one of the standard Proxmox templates rather than importing or building your own base image from scratch. The official Debian and Ubuntu templates include all necessary kernel modules, cgroup support, and FUSE libraries that Docker needs out of the box:

pct create 101 local:vztmpl/debian-12-default_20240918_amd64.tar.zst \
  --hostname docker-lxc \
  --cores 2 \
  --memory 2048 \
  --netname=eth0,ip=dhcp,gw=192.168.1.1 \
  --unprivileged=1 \
  --ostype=debian \
  --rootfs local-lvm:storage-size=30G,size=5G

This creates a container named docker-lxc with an unprivileged setup, 2 GB of RAM allocated for the base OS plus Docker daemon and running containers (leaving room in your host memory), and a 30 GB LVM-thin root volume where you can expand later as needed. The key flags here are --unprivileged=1, which ensures the container runs without CAP_SYS_ADMIN, and choosing an appropriate storage backend—local-lvm or ZFS depending on whether you're running Build a Software-Defined Datacenter with Proxmox VE style workloads that benefit from shared cluster storage.

After creating the container, open it in the shell and install Docker using the official repository rather than relying on what your distribution ships:

apt-get update && apt-get -y install ca-certificates curl gnupg
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
chmod a+r /etc/apt/keyrings/docker.gpg

echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian $(. /etc/os-release && echo "$VERSION_CODENAME") stable" > \
  /etc/apt/sources.list.d/docker.list
apt-get update
apt-get -y install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Now configure Docker to use your chosen storage driver. Edit /etc/docker/daemon.json and add the appropriate overlay configuration:

For fuse-overlayfs (unprivileged, recommended for most homelab setups):

{
  "storage-driver": "fuse-overlayfs"
}

For traditional overlay2 if you need maximum I/O performance in a privileged container or have cgroup v1 support enabled:

{
  "storage-driver": "overlay2",
  "features": {
    "ignore_chown_errors": true,
    "native_mount_options": ["rbind"]
  }
}

After making your change, restart Docker and verify the driver is active:

systemctl restart docker
docker info | grep -i storage-driver
# Output should show either fuse-overlayfs or overlay2 depending on what you configured

When Does Privileged Mode Actually Matter?

Many administrators default to privileged containers because it's simpler—no configuration, no driver selection—and everything "just works." That approach is perfectly reasonable for homelabs and even small production deployments. But understanding when privilege actually matters helps you make informed decisions rather than blindly applying defaults:

GPU passthrough requires a privileged container. If your Docker workloads need access to the GPU—running Ollama models, Open WebUI instances with hardware-accelerated inference, or Jellyfin transcoding—you must set privileged=1 in your LXC configuration. Without it, Docker cannot mount the device nodes for /dev/dri/card0, /dev/dri/renderD128, and related GPU devices that pass through from the host to the container via PCI passthrough rules:

lxc.cgroup.devices.allow = c 245:* rwm
lxc.mount.entry = /dev/dri card0 dev/dri/card0 none bind,optional=0 0 0
lxc.mount.entry = /dev/dri/renderD128 renderD128 dev/dri/renderD128 none bind,optional=0 0 0

Volume mounts with special filesystems need privilege. If you're mounting ZFS datasets or Ceph RBD volumes directly into Docker containers using the -v flag rather than running them as block devices through Proxmox's storage pool, a privileged container can handle those mount operations without additional configuration. This matters when your Docker workloads write heavy data—like database engines in PostgreSQL or MongoDB—that benefit from direct access to ZFS datasets with native compression and checksumming enabled by default on most homelab setups today.

Network namespaces behave differently. In an unprivileged container, the network setup is handled through a virtual Ethernet bridge between the host's Linux bridge (typically vmbr0 as configured when you follow Configuring VLANs on Proxmox with Linux Bridges best practices) and your LXC container. Docker then creates its own internal network stack inside that namespace, which can occasionally cause port conflicts if host services are listening on the same ports as containers. A privileged container gives you more control over this behavior through --network=host mode in Docker Compose files or individual service definitions.

For most homelab users running typical workloads like Home Assistant OS alongside other Build a Private Cloud at Home with Proxmox VE services, the unprivileged approach is sufficient and provides better isolation between containers that run on the same host node without interfering with each other's cgroups or device access.

What Trade-offs Should You Expect?

The honest trade-off when choosing your Docker-in-LXC setup comes down to security versus flexibility: an unprivileged container gives you stronger process-level isolation, which matters if you're running workloads that handle external traffic from Cloudflare Tunnel on Proxmox for Zero-Trust Remote Access or other exposed services. But it constrains what Docker can do with storage mounts and device access unless you carefully configure the container's capabilities through lxc.cgroup.devices.allow rules in /etc/pve/lxc/<containerid>.conf.

A privileged LXC gives you full host-level visibility, which simplifies GPU passthrough configuration since your containers see all devices directly without needing explicit allow-listing. The security trade-off is real but often acceptable for homelab environments where the primary threat model is between workloads rather than from external attackers—though even there, Docker's own network isolation and volume permissions provide meaningful protection if you configure them properly alongside CrowdSec on Proxmox: Cluster-Wide Brute-Force Defense for host-level security.

One specific gotcha to watch out for when using fuse-overlayfs in unprivileged mode: Docker's default storage location (/var/lib/docker) will use the FUSE translation layer, which means any volume mounts that reference bind-mounted directories from your Proxmox LXC container may show different ownership and permissions than expected. This is particularly noticeable if you're running Cockpit on Proxmox: Manage KVM, LXC, and Docker in One UI alongside your containers and the web interface displays file sizes differently for FUSE-backed volumes compared to native overlay2 mounts. The fix is straightforward—ensure container user namespaces map correctly by setting lxc.include = /etc/lxc/default.conf in /etc/pve/lxc/<containerid>.conf.

Automating Your Setup with Ansible or Portainer?

Once your Docker-in-LXC setup works, consider whether to manage it manually through the shell (which gives you full control and debugging visibility) or automate configuration management. For larger homelabs running multiple containerized services—Jellyfin for media streaming, Ollama for local AI inference with GPU Passthrough on Proxmox: Complete Guide configurations applied—the Ansible approach described in Automate Proxmox VE with Ansible Full VM Playbooks scales well because you can apply the same Docker configuration to dozens of containers across your cluster.

Portainer offers a middle ground if you prefer GUI management but want more structure than raw docker-compose.yaml files, as covered in Managing Docker on Proxmox with Portainer and Dockge—particularly useful when running workloads that need persistent volumes backed by ZFS snapshots or Ceph RBD blocks.

Conclusion

Docker inside unprivileged LXC containers gives homelab users the best balance of performance, security, and resource efficiency on Proxmox VE 9.x today. The fuse-overlayfs driver works reliably across all supported versions without requiring privileged mode, while overlay2 remains available for workloads that need maximum I/O throughput or direct device access through ZFS-backed volumes. Your choice between drivers depends primarily on whether your storage backend benefits from native mount capabilities and how much GPU passthrough overhead you're willing to accept—both reasonable trade-offs depending on workload type rather than hard constraints.

The next step is picking a specific Docker image for one of your homelab services, creating an LXC container with the right driver configuration using pct, deploying it in privileged or unprivileged mode based on whether GPU passthrough matters to you, and then monitoring resource usage over several days as containers start up under load.

Share
Proxmox Pulse

Written by

Proxmox Pulse

Sysadmin-driven guides for getting the most out of Proxmox VE in production and homelab environments.

Related Articles

View all →