Podman in Proxmox LXC for Rootless Container Workloads

Run Podman inside a Proxmox LXC without a root daemon. Covers LXC config, user namespaces, rootless setup, and Podman Compose in under 30 minutes.

Proxmox Pulse Proxmox Pulse
9 min read
Glowing nested containers floating in a dark server room with teal and blue lighting.

Podman gives you OCI-compatible containers inside a Proxmox LXC without a root-owned daemon, and that matters for a homelab or production node where you want isolation without the Docker attack surface. By the end of this guide, you'll have a Debian 12 LXC running Podman 5.x, a non-root user with proper UID maps, cgroup v2 delegated correctly, and Podman Compose handling multi-container stacks — all in an unprivileged container.

Key Takeaways

  • No daemon required: Podman is daemonless — containers run as child processes of the calling user, not as a persistent root service.
  • Unprivileged LXC works: With the right lxc.idmap settings and cgroup delegation, Podman runs cleanly in an unprivileged Proxmox VE 8+ container.
  • Docker Compose compatible: podman-compose and the Docker Compose binary both work with existing compose.yaml files against the Podman socket.
  • Rootless gotcha: Rootless Podman requires /etc/subuid and /etc/subgid ranges plus loginctl enable-linger — skip either and containers silently stop after logout.
  • Storage driver matters: Use overlay with fuse-overlayfs for rootless; vfs works but writes every layer as a full copy and will destroy performance on any real workload.

Why Podman Instead of Docker for LXC Containers

Docker's architecture inside an LXC has always been a compromise. The Docker daemon runs as root and listens on a Unix socket — in an unprivileged LXC, that means either accepting a privileged container (with all the security trade-offs that implies) or layering Docker's rootless mode on top of an architecture that was never designed for it.

Podman was designed rootless from the start. Each podman run call forks a conmon monitor process owned by the calling user. There is no daemon to babysit. If the user logs out, containers keep running as long as linger is enabled via systemd. The OCI image format is byte-for-byte identical to Docker's, so your existing images and compose files work without modification.

For Proxmox specifically, Podman slots cleanly into an unprivileged LXC once you set the user namespace ID maps in the LXC config file. That is a one-time change on the host — after that, the container user works like any normal Linux account. If you are already running Docker stacks and want to understand the baseline approach before switching, running Docker inside LXC containers on Proxmox covers that path in detail.

Setting Up the Proxmox LXC for Podman

Choose a Base Template

Debian 12 (Bookworm) is the recommended base. Podman 4.x ships in the main Debian repos; Podman 5.x is available through the openSUSE Kubic OBS repository. Ubuntu 24.04 LTS also works. Avoid Alpine for this use case — the musl libc and BusyBox userspace create friction with fuse-overlayfs and the slirp4netns network stack.

Download the template from the Proxmox shell on the host:

pveam update
pveam download local debian-12-standard_12.7-1_amd64.tar.zst

Create the LXC through the web UI or pct. Use an unprivileged container (the default). Two vCPUs and 2 GB RAM covers most workloads; bump to 4 GB if you plan to run several containers simultaneously.

Configure the LXC for User Namespaces

Stop the LXC before editing its config. The file lives at /etc/pve/lxc/<VMID>.conf on the Proxmox host. Add or verify these lines:

# Allow nested user namespace creation required for rootless Podman
lxc.apparmor.profile: unconfined
lxc.cap.drop:
lxc.cgroup2.devices.allow: a
lxc.mount.auto: proc:rw sys:rw

# Proxmox feature flags — tick these in the web UI under Options → Features
features: nesting=1,keyctl=1

The nesting=1 and keyctl=1 flags are the same checkboxes in the Proxmox web UI under the container's Options → Features panel. Either method works.

Before going further, verify your Proxmox host is running cgroup v2 in unified mode — Proxmox VE 8 and 9 both ship with this as the default:

# Run on the Proxmox HOST, not inside the LXC
stat -fc %T /sys/fs/cgroup

Expected output: cgroup2fs. If you see tmpfs, you are on a hybrid cgroup setup and need to add systemd.unified_cgroup_hierarchy=1 to the kernel command line in /etc/default/grub, then run update-grub and reboot.

The security question of unprivileged versus privileged containers matters here. Podman does not need a privileged LXC — if you are uncertain about the trade-offs, privileged vs unprivileged LXC containers on Proxmox walks through exactly why unprivileged is the right default.

Installing Podman on the Debian 12 LXC

Start the LXC and open a shell. Install from Debian repos first to pull in all dependencies, then optionally upgrade to 5.x:

apt update && apt install -y podman fuse-overlayfs uidmap slirp4netns
podman --version
# podman version 4.3.1

For Podman 5.x (recommended — it includes Netavark networking, better compose support, and improved cgroup handling), add the Kubic repo:

apt install -y curl gnupg2

curl -fsSL \
  https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/Debian_12/Release.key \
  | gpg --dearmor -o /etc/apt/keyrings/libcontainers.gpg

echo "deb [signed-by=/etc/apt/keyrings/libcontainers.gpg] \
  https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/Debian_12/ /" \
  | tee /etc/apt/sources.list.d/libcontainers.list

apt update && apt install -y podman
podman --version
# podman version 5.4.0

Configuring a Rootless Podman User

Do not run production containers as root inside the LXC even though the LXC itself runs as a mapped UID. Create a dedicated account:

useradd -m -s /bin/bash podmanuser
passwd podmanuser

Add subordinate UID and GID ranges so the user can create nested namespaces. Recent versions of useradd add these automatically; verify first:

grep podmanuser /etc/subuid /etc/subgid

If the entries are missing, add them manually:

echo "podmanuser:100000:65536" >> /etc/subuid
echo "podmanuser:100000:65536" >> /etc/subgid

Enable linger so the user's systemd session (and any containers) survive after SSH logout:

loginctl enable-linger podmanuser

Switch to the account and verify rootless Podman is operational:

su - podmanuser
podman info | grep -E 'rootless|storageDriver|cgroupVersion'

You should see rootless: true, storageDriver: overlay, and cgroupVersion: "2". If storageDriver shows vfs, fuse-overlayfs is not loading. Fix it on the Proxmox host (not inside the LXC):

# On the Proxmox HOST
modprobe fuse
echo "fuse" >> /etc/modules-load.d/fuse.conf

Then restart the LXC — the module needs to be present before the container mounts its overlay filesystem.

Running Your First Rootless Container

Still as podmanuser, pull and run a container:

podman run -d --name nginx-test -p 8080:80 docker.io/library/nginx:alpine
podman ps

Expected output:

CONTAINER ID  IMAGE                           COMMAND               CREATED        STATUS        PORTS                 NAMES
a3b9f1c4e5d2  docker.io/library/nginx:alpine  nginx -g daemon o...  4 seconds ago  Up 4 seconds  0.0.0.0:8080->80/tcp  nginx-test

Test it from another machine on the same network (replace LXC_IP with the LXC's IP address from ip addr):

curl http://LXC_IP:8080

For containers that need to survive reboots, generate a systemd user unit rather than relying on restart policies:

mkdir -p ~/.config/systemd/user
podman generate systemd --new --name nginx-test > ~/.config/systemd/user/nginx-test.service
systemctl --user daemon-reload
systemctl --user enable --now nginx-test

With linger enabled, this unit starts automatically at boot without any root involvement.

Using Podman Compose for Multi-Container Stacks

Install podman-compose:

# As root in the LXC
apt install -y python3-pip
pip3 install podman-compose

A standard compose.yaml works without changes. Here is a minimal example to confirm the setup:

services:
  db:
    image: docker.io/library/mariadb:11
    environment:
      MYSQL_ROOT_PASSWORD: changeme
      MYSQL_DATABASE: appdb
      MYSQL_USER: appuser
      MYSQL_PASSWORD: changeme
    volumes:
      - db_data:/var/lib/mysql

  app:
    image: docker.io/library/nginx:alpine
    ports:
      - "8081:80"
    depends_on:
      - db

volumes:
  db_data:
# As podmanuser, in the directory containing compose.yaml
podman-compose up -d
podman-compose ps

Expect the stack to be healthy within about 60 seconds on first pull. Subsequent restarts take under 5 seconds since images are cached in the user's local storage at ~/.local/share/containers.

Gotcha with podman-compose: It does not implement the full Compose spec. The depends_on with condition: service_healthy and some deploy: keys are silently ignored as of v1.2. If your stack relies on those, point the official docker-compose binary at the Podman socket instead:

# Enable the Podman API socket for the user
systemctl --user enable --now podman.socket

# Use it with docker-compose
export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/podman/podman.sock
docker-compose up -d

Podman vs Docker in LXC: Direct Comparison

Feature Podman (rootless LXC) Docker (LXC with nesting)
Root daemon required No Yes (dockerd runs as root)
LXC privilege level Unprivileged Privileged or nested
Compose support podman-compose / Docker socket docker-compose native
Systemd integration Native user units Requires docker.service as root
Image compatibility Full OCI / Docker Hub Full Docker Hub
Rootless networking slirp4netns / Netavark Docker bridge (kernel namespace)
GPU passthrough Limited in rootless mode Easier with NVIDIA Container Toolkit
Auto-restart after host reboot Via systemd user units + linger Via dockerd restart policy

Docker wins on ecosystem tooling — Portainer, Dockge, and most CI integrations assume a Docker socket. If you are managing several stacks through a web UI, managing Docker on Proxmox with Portainer and Dockge covers that workflow. Podman wins on isolation: there is simply less running as root.

For the broader architectural question of whether to distribute workloads across many LXCs versus consolidating on one VM, multiple Docker LXCs vs one Docker VM on Proxmox makes the trade-off concrete.

Common Pitfalls and How to Fix Them

Containers stop when you log out. You skipped loginctl enable-linger. Run it as root and confirm with:

loginctl show-user podmanuser | grep Linger
# Linger=yes

"Error: kernel does not support overlay mount" The fuse kernel module is not loaded on the Proxmox host. Load it and persist it:

# On the Proxmox HOST
modprobe fuse
echo "fuse" >> /etc/modules-load.d/fuse.conf

"Error: cannot set up namespace" /etc/subuid or /etc/subgid entries are missing or the range is smaller than 65536. Verify:

grep podmanuser /etc/subuid /etc/subgid
# podmanuser:100000:65536
# podmanuser:100000:65536

Port 80 or 443 binding fails. Rootless containers cannot bind to ports below 1024 by default. Lower the threshold on the Proxmox host:

echo "net.ipv4.ip_unprivileged_port_start=80" > /etc/sysctl.d/99-podman.conf
sysctl --system

Storage grows unbounded. Podman does not auto-prune. Add a weekly prune to the user crontab:

# As podmanuser
crontab -e
# Add this line:
0 3 * * 0 podman system prune -f --volumes

Conclusion

Podman in an unprivileged Proxmox LXC gives you Docker-compatible container workloads with no root daemon and no privileged container required — the setup takes about 20 minutes from template download to a running rootless stack. The one honest limitation to benchmark before committing: rootless slirp4netns networking adds per-packet overhead compared to Docker's kernel bridge; for high-throughput services, run a quick iperf3 comparison against a Docker LXC before moving production traffic. Your next step is to pick one existing compose stack, migrate it to Podman, verify all services start cleanly with podman-compose ps, and then lock it in with systemd user units so the stack survives reboots automatically.

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 →