WireGuard needs exactly one kernel to own its interface, and that fact settles most of the Proxmox placement argument before performance enters the room. An LXC container is a namespace view of the host kernel, while a VM boots its own. So the useful question is not which option is lighter but which kernel you are willing to modify and which recovery path you can live with. Answer that and the host, container or VM choice usually makes itself.

An LXC guest works inside the host kernel

Installing wireguard-tools inside a container gives you the control program, not a private kernel. The wg0 interface you create is registered in the host's network stack and shows up in the host's module list. That is why a container can pass every package check and still fail at the first wg command when the host kernel lacks the module. The Proxmox container reference documents that shared-kernel model along with the namespace and privilege boundaries you are working inside.

Authority is the second constraint. Bringing an interface up and attaching addresses needs network-administration rights inside the namespace that owns it, and an unprivileged container maps those rights through its user namespace rather than holding them directly. Never reach for full privilege as the first answer; look at what the container is actually being asked to do, then grant that.

The host's kernel is also a shared dependency. A Proxmox kernel update changes the WireGuard implementation under every container at once, which is convenient until an update and a container's expectations disagree.

Host, container, VM: what each placement actually owns

Host placement puts the VPN in the hypervisor's own networking. Routes, firewall rules and the tunnel become part of host recovery, and a mistake there can take the management interface with it. That is acceptable for infrastructure routing on a host you can reach through a console, and painful on a remote box with no out-of-band access.

A container keeps the service packaged and restartable while still borrowing the host kernel. It suits a deliberate shared-kernel service and gives you a small unit to rebuild. It does not give you an independent kernel, so anything that needs a specific module build points away from this option.

PlacementKernel ownerTypical failure mode
Proxmox hostHypervisorA routing change breaks host management access
LXC containerHost kernel, container namespaceMissing capability or missing module at wg0 creation
Virtual machineGuest kernelExtra maintenance and a second patch cycle

A VM costs more memory and another system to patch, and in exchange the tunnel gets its own kernel, its own routing table and a snapshot boundary. When the VPN is the thing you roll back after a bad change, that snapshot is worth the overhead.

Three conditions that choose for you

If the tunnel needs a kernel version or a WireGuard feature the Proxmox host does not ship, stop here and use a VM. You cannot install a newer kernel into a container, and you should not replace the hypervisor kernel to satisfy one guest.

If the tunnel is the site's gateway for real LAN prefixes, ask who already owns the return route. A container can route traffic, but its interfaces sit in the host's stack, so the host ends up carrying part of the configuration whether you planned for that or not. Host placement is honest about this; container placement often is not.

Then weigh the blast radius of a mistake. Restarting a container is cheap, restoring a VM snapshot is predictable, and repairing host networking may need physical or console access. The right choice is the one whose worst case you can actually recover from at the hour it happens.

A fourth question is rarely decisive but worth stating: does anything else on the host need to see the tunnel interface? If yes, host or container placement keeps that visibility local, while a VM forces you to route between the guest and the host.

Prove the placement before you route traffic through it

Once installed, confirm which kernel is actually serving the interface and whether the container was granted enough authority to keep it:

$ pct config 101 | grep -E 'unprivileged|features'
unprivileged: 1
$ pct exec 101 -- wg show
interface: wg0
  listening port: 51820
$ pct exec 101 -- ip -4 addr show wg0
inet 10.60.0.2/24 scope global wg0

Then check the forwarding side from the host, because a handshake alone only proves the tunnel is up. Use ip route get for a client address and confirm the next hop and interface match the design, and confirm the return path exists on the far side.

Leave the deployment with a written owner: which kernel carries the implementation, which namespace holds the interface, and which prefixes the gateway is allowed to forward. That sentence prevents more incidents than any benchmark comparison of the three placements.

সম্পৰ্কিত প্ৰবন্ধ