If you've followed a guide to get Docker running inside a Proxmox LXC container, you've probably ended up staring at a terminal full of docker ps output and wondering if there's an easier way to see what's actually running. There is. It's called Portainer, and it turns Docker's command-line-only world into a web dashboard you can click around in.

This guide walks you through installing Portainer inside its own LXC container on Proxmox VE 9.2. You don't need to know Docker well before starting. By the end you'll have a working web UI where you can start, stop, and inspect containers without memorizing flags.

What You Will Learn

  • What Portainer actually does and why it's worth running
  • How to create an LXC container configured correctly for Docker
  • How to install Docker and Portainer step by step
  • What each command in the process actually does
  • Common errors people hit on this exact setup, and how to fix them
  • A few things worth doing differently once it's up and running

What Is This Feature?

Portainer is a web-based management tool for Docker. Docker itself is a way of packaging an application together with everything it needs to run — code, libraries, settings — into a self-contained unit called a container. Once you have Docker installed, you can pull ready-made containers for things like Nginx Proxy Manager, Pi-hole, or Uptime Kuma and have them running in seconds.

The catch is that Docker's native interface is the command line. That's fine once you know it, but it's not exactly welcoming. Portainer sits on top of Docker and gives you a browser-based dashboard: a list of running containers, buttons to start and stop them, a place to view logs, and a form for deploying new ones without typing a full docker run command from memory.

You're not replacing Docker with Portainer. You're adding a UI in front of it. Docker still does all the actual work; Portainer just talks to it on your behalf through the Docker socket.

Why Would You Use It?

Honestly, you don't strictly need Portainer. Everything it does can be done with docker commands. But once you're running more than two or three containers, the command line stops being convenient and starts being tedious — checking logs, restarting a stuck container, or seeing how much memory something is using all involve typing out container names or IDs you have to look up first.

Portainer fixes that by putting all of it in one screen. You can see every container's status at a glance, click into logs without piping through docker logs -f, and deploy a new stack by pasting in a docker-compose file instead of translating it into a long run command.

It's particularly useful in a homelab where you're experimenting a lot — trying a new self-hosted app, tearing it down, trying another one. Portainer makes that loop faster because you're not re-typing commands each time.

Prerequisites

Before you start, make sure you have:

  • A working Proxmox VE 9.2 host (earlier 8.x versions work too, though a couple of dialog boxes look slightly different)
  • Root or admin access to the Proxmox web interface
  • At least 4 GB of free disk space and 1 GB of free RAM on the node for the new container
  • A Debian 12 (Bookworm) LXC template — download it from local storage under CT Templates if you don't already have it
  • About 15 minutes

You don't need to have set up Docker before. This guide covers that from scratch inside the new container.

Step-by-Step Tutorial

Step 1: Create the LXC container

In the Proxmox web UI, click Create CT in the top-right corner. Give it a hostname like portainer, set a root password, and on the Template tab pick the Debian 12 template you downloaded.

On the Disks tab, 8 GB is plenty — Portainer itself uses very little space, though container images you pull later will add up. For CPU, one core is fine to start. For Memory, set 1024 MB; you can lower this later if it turns out you don't need it.

On the Network tab, leave DHCP on unless you already run static IPs in your network, in which case set one now — it saves you from Portainer's URL changing later.

Leave the container as unprivileged (the default). Running Docker in an unprivileged container is a little more work to configure, but it keeps the container more isolated from the host, which matters if something inside ever gets compromised.

Step 2: Enable nesting and keyctl

Docker needs two LXC features that aren't turned on by default: nesting and keyctl. Nesting lets you run containers inside a container — Docker's containers are themselves a form of containerization, so without this, Docker simply won't start. Keyctl allows the kernel keyring operations Docker relies on for things like secret handling.

Before starting the container, go to Options → Features in the container's settings and enable both. Or do it from the Proxmox shell — replace 105 with your container's actual ID:

pct set 105 --features nesting=1,keyctl=1

If the container is already running, stop it first with pct stop 105, run the command above, then start it again.

Step 3: Start the container and log in

Start the container from the Proxmox UI, then open its console (or run pct enter 105 from the Proxmox shell for a faster text-only session). You should land at a root prompt inside Debian.

Update the package list and install curl, which you'll need for the next step:

apt update && apt install -y curl

Step 4: Install Docker

Docker publishes an official install script that handles adding their repository and installing everything correctly. Run it with:

curl -fsSL https://get.docker.com | sh

This takes a minute or two on a typical connection. Once it finishes, confirm Docker is actually working:

docker run hello-world

If you see a message starting with "Hello from Docker!", nesting and keyctl are configured correctly and the Docker daemon is running. If this command hangs or errors out, jump ahead to the Common Errors section before continuing — there's no point installing Portainer on top of a Docker install that isn't working yet.

Step 5: Deploy Portainer

Portainer needs a place to store its own data — user accounts, settings, and so on — separate from the containers it manages. Create a Docker volume for that first:

docker volume create portainer_data

Now run Portainer itself:

docker run -d \
  -p 8000:8000 \
  -p 9443:9443 \
  --name portainer \
  --restart=always \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v portainer_data:/data \
  portainer/portainer-ce:latest

Give it about 15-20 seconds to pull the image and start the first time.

Step 6: Log in to Portainer

Find your container's IP address — either from the Proxmox UI's Summary tab for that container, or by running ip a inside it. Then open a browser and go to:

https://<container-ip>:9443

Your browser will warn you about an untrusted certificate — that's expected, Portainer generates a self-signed one by default. Click through the warning to continue.

You'll land on a setup screen asking you to create an administrator account. Do this within about 5 minutes of the container starting — Portainer locks this setup page after a short window as a security measure, and if you miss it you'll need to restart the container to try again. Once your admin account is created, you'll be dropped into the dashboard showing your local Docker environment, already connected.

Commands Explained

CommandWhat it does
pct set 105 --features nesting=1,keyctl=1Turns on the two LXC kernel features Docker needs, applied to container ID 105
curl -fsSL https://get.docker.com | shDownloads and runs Docker's official install script, which adds their apt repository and installs Docker Engine plus the CLI
docker run hello-worldPulls a tiny test image and runs it once, confirming the Docker daemon can actually create containers
docker volume create portainer_dataCreates a named, persistent storage location that survives even if the Portainer container is removed and recreated
-dRuns the container in the background ("detached") instead of tying up your terminal
-p 9443:9443Maps port 9443 on the container to port 9443 inside it — this is how you reach the web UI from outside
--restart=alwaysTells Docker to automatically start this container again after a reboot or crash
-v /var/run/docker.sock:/var/run/docker.sockGives Portainer access to the Docker socket, which is how it's able to see and control other containers on the same host

Common Errors

"docker: Error response from daemon: privileged mode is disabled" or the daemon simply refuses to start — this almost always means nesting isn't enabled. Double-check with pct config 105 on the Proxmox host and confirm you see features: nesting=1,keyctl=1 in the output.

hello-world hangs on "Unable to find image" and never completes — usually a DNS or network issue inside the container rather than a Docker problem. Try ping 8.8.8.8 and then ping google.com from inside the container to isolate whether it's DNS or connectivity.

Browser shows "Connection refused" at port 9443 — check the container is actually running with docker ps. If it's not listed, it likely exited right after starting; check why with docker logs portainer.

"Your session has expired" or a locked setup page — you took longer than the timeout window to create the admin account. Run docker restart portainer and try again, faster this time.

Troubleshooting

When something's not working, work through it in this order rather than guessing:

  1. Confirm the LXC container itself is running: check the Proxmox UI or run pct status 105.
  2. Confirm nesting and keyctl are set: pct config 105 should list both under features.
  3. Confirm the Docker daemon is actually up inside the container: systemctl status docker.
  4. Confirm Portainer's container is running: docker ps should show it with a status of "Up".
  5. Read the actual logs instead of guessing: docker logs portainer usually tells you exactly what's wrong, whether that's a port conflict or a permissions issue.

One thing that trips people up on ZFS-backed Proxmox hosts specifically: Docker's default storage driver, overlay2, doesn't always play nicely with ZFS. If docker info shows a storage driver other than overlay2, or Portainer's container fails to start with filesystem-related errors, that's the likely culprit. It's a deeper fix than this guide covers, but it's worth knowing the symptom so you're not chasing the wrong problem.

Best Practices

A few things worth doing once the basics are working:

  • Take a Proxmox snapshot of the container right after this initial setup. If you break something experimenting later, you can roll straight back to a known-good state.
  • Don't expose port 9443 directly to the internet. If you want to reach Portainer remotely, put it behind a VPN or a reverse proxy with its own authentication in front.
  • Back up the portainer_data volume, not just the container. The volume is what holds your admin account and settings — losing it means starting the setup wizard over.
  • Set a memory limit on the container once you know your actual usage. 1 GB is a safe starting point, but Portainer plus a handful of small containers rarely needs that much.

I'd also skip running Docker in a privileged LXC container unless you have a specific reason to. It's a shortcut that avoids the nesting/keyctl setup, but it removes a layer of isolation between the container and the Proxmox host itself — not a trade worth making for a homelab dashboard tool.

Frequently Asked Questions

Do I need to know Docker to use Portainer?

No. Portainer's whole point is letting you deploy and manage containers through forms and buttons instead of the command line. You'll pick up Docker concepts naturally as you go.

Should I run Docker in a VM instead of an LXC container?

For serious or production workloads, yes — a VM gives Docker a full isolated kernel and avoids the nesting/keyctl workarounds entirely. For a homelab, LXC uses noticeably less RAM and starts faster, and that's usually the better trade-off.

Can I manage containers on other Proxmox VMs from this same Portainer instance?

Yes, but not automatically. You'd install the lightweight Portainer Agent on each remote Docker host and add it as an "environment" inside Portainer, rather than running a separate full Portainer install everywhere.

Why does my browser say the connection isn't private?

Portainer serves its UI over HTTPS with a self-signed certificate it generates on first start. It's not a sign of a problem — just click through the warning, or replace it with your own certificate later if it bothers you.

What's the difference between Portainer CE and Portainer BE?

CE (Community Edition) is free and covers everything in this guide. BE (Business Edition) adds features like role-based access control at scale and paid support, aimed at teams managing many environments — not something a homelab setup needs.

Conclusion

You now have Docker running inside an isolated LXC container, with Portainer giving you a proper dashboard on top of it. From here, deploying a new self-hosted app is usually just pasting a docker-compose file into Portainer's Stacks section rather than working out a docker run command by hand.

Keep that snapshot from the Best Practices section handy while you experiment — it's the fastest way to undo a bad decision when you're trying out new containers.