Open the Create menu in Proxmox VE and you'll see two options sitting right next to each other: VM and CT. Most beginners click VM because it's the familiar one — it looks like VirtualBox, like VMware, like every other virtualization tool they've used before. CT, short for container, gets ignored until someone tells them it's faster and lighter, at which point they use it without really knowing what it's doing differently under the hood.

This isn't a step-by-step guide to spinning up your first container — we've already covered that ground elsewhere. This is the article for the question that usually comes before that: what actually is LXC, and why does a full virtualization platform like Proxmox bother including it at all?

What You Will Learn

  • What LXC actually is, in plain terms, not textbook definitions
  • How a container achieves isolation without emulating a whole computer
  • What namespaces and cgroups do, and why both matter
  • Privileged versus unprivileged containers, at a conceptual level
  • Where containers genuinely beat VMs, and where they fall apart
  • How to peek at a running container's isolation using real commands

What Is This Feature?

LXC stands for Linux Containers. It's a way of running an isolated Linux system — its own filesystem, its own processes, its own network stack — without giving it a virtual CPU, virtual RAM chip, or virtual BIOS the way a VM gets. A container shares the host's actual Linux kernel. There's no hypervisor pretending to be hardware underneath it; there's just the kernel, drawing very careful lines around what one group of processes can see and touch.

Two kernel features make that possible. Namespaces give a container its own private view of things that are normally global — its own process ID numbering (so a container's process 1 doesn't collide with the host's process 1), its own network interfaces, its own mount points. From inside the container, it genuinely looks like a separate machine. Cgroups (control groups) handle the other half: limiting how much CPU, memory, and I/O a container is allowed to consume, so one noisy container can't starve everything else on the host.

Proxmox VE wraps all of this with its own tooling — pct on the command line, and a full GUI workflow — plus a library of ready-made templates (Debian, Ubuntu, Alpine, and others) so you're not building a root filesystem by hand.

Why Would You Use It?

The pitch for containers usually comes down to overhead. A VM boots an entire kernel, its own copy of everything, and reserves memory the way you configured it, whether it's using that memory or not. A container boots almost instantly because there's no kernel to start — it's already running, it's the host's — and it only holds onto the memory its processes actually need.

That makes LXC a good fit for things like a Pi-hole instance, a small web app, a Nextcloud install, or a Home Assistant setup — services that don't need their own kernel and benefit from being lightweight. It's a poor fit for anything that needs a different operating system than Linux (no, you can't run Windows in an LXC container), needs its own kernel modules, or genuinely needs the harder isolation boundary a VM provides.

If you want the fuller decision framework — CPU pinning, GPU passthrough, migration behavior, security posture — that's a comparison worth reading on its own. Here, the short version is enough: containers for lightweight Linux services, VMs for everything else.

Density is the other reason people reach for LXC on a homelab box. A Raspberry Pi 4 or a small mini PC with 8 GB of RAM might comfortably run a dozen small containers — a DNS server, a reverse proxy, a couple of monitoring agents, a small database — where the same hardware would struggle to run more than two or three equivalent VMs. You're not paying the "reserve a chunk of RAM for a guest kernel" tax a dozen times over.

Prerequisites

  • A working Proxmox VE host (any reasonably current 8.x or 9.x install)
  • At least one container template downloaded — check local storage → CT TemplatesTemplates in the GUI if you don't have one yet
  • One existing LXC container to poke around in — it doesn't need to be doing anything important
  • Shell access to the Proxmox host, either via SSH or the built-in web console

You don't need deep Linux kernel knowledge for any of this. If you can read a terminal prompt, you can follow along.

Step-by-Step Tutorial

Rather than walking through container creation again, let's actually look at the isolation LXC is providing, using a container you already have running.

  1. List your containers and note an ID:
    pct list
  2. Check its current resource usage — this is cgroups doing its job:
    pct status 101 --verbose
  3. Enter the container directly from the host, no SSH required:
    pct enter 101
  4. Inside the container, check what process ID your shell has. It'll almost certainly be a low number, even though this container is running on a host with hundreds of host-level processes:
    echo $$
  5. Still inside the container, list running processes. You'll only see the container's own processes — nothing from the host, and nothing from any other container:
    ps aux
  6. Exit back to the host:
    exit
  7. From the host, look at that same container's processes from the outside, using its real host-level PID. Find it with:
    pct exec 101 -- cat /proc/1/status
    Compare the PID reported inside the container against what the host sees for that same process — this is namespaces at work. Two different numbers, one process.
  8. Check the container's config to see the cgroup-based limits Proxmox set for it:
    pct config 101

None of this changes anything on your system — it's just making the invisible part of LXC visible for a minute.

Commands Explained

CommandWhat it does
pct listShows every LXC container on the host, its ID, status, and name.
pct status <ctid> --verboseShows live resource usage for a specific container — CPU time, memory, and swap, pulled straight from its cgroup.
pct enter <ctid>Drops you into a root shell inside the container directly from the host, without needing SSH or a password.
pct exec <ctid> -- <command>Runs a single command inside the container from the host, without a full interactive session.
pct config <ctid>Prints the container's configuration file — CPU limit, memory limit, network setup, and whether it's privileged or unprivileged.

Worth defining while we're here: a privileged container's root user maps directly to the host's root user, which is convenient but means a container breakout is a much bigger deal. An unprivileged container maps its root user to some unprivileged, high-numbered user ID on the host instead, so even "root" inside the container has effectively no power outside it. Proxmox defaults new containers to unprivileged for exactly this reason, and unless you have a specific driver or hardware-access requirement that forces your hand, I'd leave it that way.

Common Errors

  • "lxc-start: startup for container '101' failed" — often a mismatched or corrupted template, or a missing kernel feature the container's init system expects. Check pct config 101 against the template you actually downloaded.
  • Container can't mount extra storage or access a device — unprivileged containers are restricted from a lot of device and mount operations by design. This is the isolation working as intended, not a bug, though it does mean some passthrough scenarios need a privileged container instead.
  • "unable to open file '/etc/pve/nodes/.../lxc/101.conf'" — usually a cluster filesystem (pmxcfs) hiccup, or you're referencing a container ID that lives on a different node.
  • High load average on the host that doesn't match any single VM — check container cgroups with pct status <ctid> --verbose across all your CTs. Because containers share the kernel, a runaway process in one container shows up in host-level metrics differently than a VM's usage does.

Troubleshooting

If a container won't start, the most useful first move is pct start 101 --debug, which surfaces far more detail than the GUI's task log summary. Nine times out of ten the real error is an AppArmor restriction or a missing cgroup controller, both of which show up clearly in debug output but get compressed to a vague one-liner otherwise.

If networking looks broken inside a container but the host network is fine, check the container's net0 line in pct config — a wrong bridge name is an easy typo to make and an easy one to miss when you're scanning the config quickly.

If you genuinely need something an unprivileged container won't allow — certain FUSE filesystems, some USB devices, specific kernel modules — you have two real options: switch that specific container to privileged (accepting the reduced isolation) or move that workload to a VM instead. Don't reach for privileged mode as a default fix; reach for it only when you've confirmed unprivileged genuinely can't do the job.

Best Practices

  • Default to unprivileged containers unless you have a specific, confirmed reason not to.
  • Set memory and CPU limits deliberately instead of leaving containers uncapped — cgroups only protect you if you've told them what the boundaries are.
  • Keep one service per container where practical. It's a smaller blast radius if something goes wrong, and it makes backups and restores far more predictable.
  • Don't run untrusted or security-sensitive workloads in a privileged container on a host you actually care about.
  • Use official templates from the Proxmox template list rather than hand-rolled root filesystems unless you specifically know why you need to.

Frequently Asked Questions

Is an LXC container the same thing as a Docker container?

No, though they're built on similar kernel primitives. Docker is application-focused — typically one process per container, built from an image. LXC gives you a full, persistent Linux system inside the container, closer to a lightweight VM than a single app process. You can actually run Docker inside an LXC container, which a lot of homelab users do.

Can I run a different Linux distribution than my Proxmox host uses?

Yes. The container shares the host's kernel, but its userspace — the actual distribution, its packages, its filesystem — is independent. You can run an Alpine container on a Debian-based Proxmox host without issue.

Why can't I run Windows in an LXC container?

Because a container shares the host's Linux kernel instead of running its own. Windows needs its own kernel, so it has to go in a VM, not a container.

Are containers less secure than VMs?

The isolation boundary is thinner, yes — a kernel vulnerability can theoretically affect every container sharing that kernel, which isn't true across separate VMs. Unprivileged containers close most of the practical gap for typical homelab and small-business use, but for genuinely hostile or untrusted workloads, a VM's isolation is still stronger.

Do containers support snapshots and backups like VMs do?

Yes, both work the same way from Proxmox's side — snapshot and vzdump backup support cover LXC containers just like VMs, including restores through the same GUI and CLI tools.

Why does my container show almost no memory usage even though services are running inside it?

Cgroup memory accounting only counts what the container's processes are actually using, not a fixed reservation like a VM gets. A lightly loaded container can genuinely sit at 40–60 MB of real usage even with several services running, which surprises people used to VM memory numbers.

Conclusion

LXC isn't a lesser version of a VM, and it isn't trying to be one. It's a different tool built on a different idea — isolate at the kernel level instead of emulating hardware — and that tradeoff is exactly what makes containers so much lighter and faster to boot. Once you've actually watched a container's process IDs and cgroup limits from both sides, like we did above, "container" stops being an abstract word and starts being something you understand. That's worth ten minutes, even if you never think about it again after today.