LUNAROPS · OPERATIONAL UPLINK 100% UPTIME 1,247d POSTS 893 JEFF.MOON@LUNAROPS.DEV UTC --:--:--

Proxmox VE: The Ultimate Homelab Hypervisor

proxmoxvirtualizationhomelablxckvmstorageclusteringself-hosting
Contents

At some point every homelabber reaches the same inflection point: three physical machines running three workloads, none of them fully utilized, each one drawing power around the clock. The natural answer is consolidation — run everything on one or two powerful hosts, isolated in virtual machines and containers. For that job, Proxmox Virtual Environment has become the undisputed homelab standard, and for good reason.

Proxmox VE is a free, open-source Type-1 hypervisor built on a foundation of Debian Linux, KVM (Kernel-based Virtual Machine), and LXC (Linux Containers). It wraps those battle-tested technologies in a polished web UI, adds built-in support for ZFS, Ceph, enterprise clustering, live migration, and high availability, and ships it all under the AGPL license — free to use, forever, no license key required. The enterprise support subscription is optional and brings nothing you actually need for a homelab.

This guide is the full walkthrough: installation through clustering, storage through GPU passthrough, VMs through LXC containers. It assumes you are comfortable with Linux and want to understand what you are doing, not just copy-paste commands.


Part 1: What Is Proxmox VE?

The Technology Stack

Proxmox VE is not a hypervisor invented from scratch. It is a carefully integrated distribution that assembles existing Linux infrastructure:

  • Debian Linux as the base OS (Proxmox VE 8.x runs on Debian 12 Bookworm)
  • KVM for hardware-accelerated full virtualization — every VM is a standard KVM/QEMU virtual machine
  • LXC for OS-level containerization — shared kernel, much lower overhead than full VMs
  • QEMU as the device emulation layer for VMs
  • Corosync for cluster communication and quorum
  • DRBD / Ceph for distributed storage
  • ZFS via the native Linux ZFS kernel module (OpenZFS)
  • pve-manager — the web UI and API layer that ties everything together

Why Proxmox Won the Homelab

VMware ESXi was the free homelab hypervisor of choice for years, but Broadcom’s 2024 decision to kill the free ESXi tier ended that era. Proxmox was already the better choice for most homelab use cases:

Feature Proxmox VE ESXi (Broadcom) Hyper-V Bare Metal
Cost Free (AGPL) Paid subscription Included with Windows Server Free
Web UI Yes (excellent) Yes Requires SCVMM for full features N/A
ZFS support Native No No Yes (manual)
LXC containers Yes No No Yes (manual)
Clustering Yes (built-in) Yes (vCenter) Yes (costly) N/A
GPU passthrough Yes Yes Yes N/A
Live migration Yes (free) Yes Yes N/A
Ceph integration Yes (built-in) No No Manual
Community Large, active Shrinking Enterprise N/A

Hyper-V is a fine hypervisor but ties you to Windows Server. Running VMs directly on bare metal (e.g., Docker on Ubuntu) gives up isolation, snapshots, live migration, and the ability to run non-Linux workloads. Proxmox threads the needle: full type-1 hypervisor performance with a management layer that actually works.

Community vs Enterprise Subscription

Proxmox GmbH offers paid enterprise subscriptions at several tiers. The enterprise subscription gives you access to the enterprise package repository (more thoroughly tested packages) and commercial support. For a homelab, you need neither. The no-subscription repository receives the same software; it just reaches it a week or two later and without a guaranteed SLA. Save your money.


Part 2: Installation

Hardware Requirements

Proxmox VE will install on modest hardware, but to run it well:

Minimum:

  • 64-bit CPU with Intel VT-x or AMD-V virtualization extensions (required for KVM)
  • 4 GB RAM (8 GB practical minimum; 32+ GB if you plan to run multiple VMs)
  • Local storage for the OS — SSD or NVMe strongly recommended

Recommended for a serious homelab host:

  • Intel Core or Xeon with VT-d (for PCIe passthrough), or AMD Ryzen/EPYC with AMD-Vi
  • ECC RAM — Proxmox often runs ZFS, and ZFS with non-ECC RAM is a common point of debate. ZFS does not require ECC, but RAM corruption can cause data loss. Used Xeon/EPYC platforms with ECC are popular for this reason.
  • NVMe for the Proxmox OS drive (ZFS mirror of two small NVMe drives is ideal)
  • Separate storage for VM data — additional NVMe, SAS/SATA SSDs, or spinning disks for bulk storage
  • At least two network ports for separating cluster traffic from VM traffic

Intel N100 mini PCs, retired Xeon workstations, HP EliteDesk/ProDesk units, and Lenovo ThinkCentre systems are all popular Proxmox platforms. A used Dell R720 or HP DL380 gives you a lot of RAM and storage capacity for very little money.

Creating the Installer USB

Download the Proxmox VE ISO from the official site:

1
2
# Verify the checksum after download
sha256sum proxmox-ve_8.x-1.iso

Write it to a USB drive (replace /dev/sdX with your USB device — verify with lsblk first):

1
dd if=proxmox-ve_8.x-1.iso of=/dev/sdX bs=1M status=progress conv=fsync

On macOS, use diskutil unmountDisk /dev/diskN first, then dd. On Windows, Rufus or Etcher work well.

Installer Walkthrough

Boot from the USB. The installer is straightforward but a few choices deserve attention:

Target disk and filesystem: The installer asks which disk to install to, and whether to use ext4, xfs, ZFS (RAID0/1/10), or btrfs. For the Proxmox OS drive:

  • ZFS mirror is the best choice if you have two drives to dedicate to the OS. You get a bootable, redundant OS with checksumming and the ability to take snapshots of the OS itself.
  • ext4 on a single NVMe is fine and simple. This is what most single-drive installs use.
  • btrfs is supported but less common in the Proxmox ecosystem.
Filesystem: zfs (RAID1)
Disk 0: /dev/nvme0n1
Disk 1: /dev/nvme1n1

Hostname: Set a meaningful FQDN — e.g., pve01.lan.example.com. The hostname becomes the node name in a cluster, and renaming a node after the fact is painful.

Network: Set a static IP for the management interface. Proxmox uses this IP for the web UI and cluster communication.

Password and email: The root password for the node. The email address is used for system notifications (disk failures, backup reports, etc.). Point it at a real mailbox or a notification relay.

After installation, the system boots directly into Proxmox VE. Access the web UI at:

https://YOUR_IP:8006

Log in as root with the password you set. Accept the self-signed certificate warning for now (you can add your own certificate later via Datacenter → pve → Certificates).

Post-Install: Fix the APT Sources

Out of the box, Proxmox points at the enterprise repository, which requires a subscription key. apt update will fail with a 401 error. Fix it immediately:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# Remove or comment out the enterprise repo
echo "# Enterprise repo disabled" > /etc/apt/sources.list.d/pve-enterprise.list

# Add the no-subscription repo
echo "deb http://download.proxmox.com/debian/pve bookworm pve-no-subscription" \
  > /etc/apt/sources.list.d/pve-no-subscription.list

# Also disable the Ceph enterprise repo if present
echo "# Ceph enterprise repo disabled" > /etc/apt/sources.list.d/ceph.list

# Update and upgrade
apt update && apt dist-upgrade -y

Reboot after the upgrade, particularly if a new kernel was installed.

Disabling the Subscription Nag

Proxmox shows a “No valid subscription” popup on every login when you are not on an enterprise subscription. This is entirely cosmetic. Two common approaches:

Option 1 — pve-nag-buster (community script):

1
2
wget https://raw.githubusercontent.com/foundObjects/pve-nag-buster/master/install.sh
bash install.sh

This installs a dpkg hook that re-patches the nag on every package update.

Option 2 — Direct JS patch (manual, must redo after upgrades):

1
2
3
sed -i.bak "s/data.status !== 'Active'/false/g" \
  /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js
systemctl restart pveproxy

Neither option affects functionality. Both survive reboots but not package upgrades (the package manager will overwrite the patched file).


Part 3: Storage Configuration

Storage is where Proxmox setup gets interesting, and where a little planning pays dividends later.

Storage Types

Proxmox supports several storage backends, each suited to different use cases:

Type Use Case Snapshots Shared
dir (directory) ISOs, backups, CT templates No Via NFS mount
LVM VM disks (thick provisioned) No No
LVM-thin VM disks (thin provisioned) Yes No
ZFS VM disks, NAS-like features Yes (native) No (local)
NFS Shared storage from NAS No (on client) Yes
SMB/CIFS Backups, ISOs from Windows share No Yes
Ceph RBD Clustered VM storage Yes Yes (cluster)

LVM-thin is the default for VM disk storage in a fresh Proxmox install and is a sensible choice: it thin-provisions disk space (VMs only use space they actually write to) and supports snapshots, which are essential for live cloning and backup.

ZFS is the better choice if you care about data integrity, want native snapshots and send/receive, or are already using ZFS for other purposes. ZFS also allows you to tune I/O scheduler, compression, and recordsize per dataset, which matters for different workload types.

Adding a ZFS Pool

If you have additional drives not used for the Proxmox OS, add a ZFS pool for VM storage:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# Mirror (RAID1 equivalent) — two drives, recommended minimum
zpool create -o ashift=12 vmdata mirror /dev/sda /dev/sdb

# RAIDZ1 (RAID5 equivalent) — three drives, one drive can fail
zpool create -o ashift=12 vmdata raidz /dev/sda /dev/sdb /dev/sdc

# RAIDZ2 (RAID6 equivalent) — four+ drives, two drives can fail
zpool create -o ashift=12 vmdata raidz2 /dev/sda /dev/sdb /dev/sdc /dev/sdd

# Check pool status
zpool status vmdata

The ashift=12 option sets the pool’s sector size to 4096 bytes, matching modern SSDs and HDDs that use 4K physical sectors. Always set this at pool creation time; it cannot be changed afterward.

After creating the pool, add it to Proxmox via the web UI (Datacenter → Storage → Add → ZFS) or via CLI:

1
pvesm add zfspool vmdata --pool vmdata --content images,rootdir

Enable compression on the pool for better space efficiency:

1
zfs set compression=lz4 vmdata

Adding NFS/SMB Storage

If you have a NAS, add it as a storage target:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# NFS
pvesm add nfs nas-backups \
  --server 192.168.1.10 \
  --export /volume1/proxmox-backups \
  --content backup \
  --options vers=4.1

# SMB/CIFS
pvesm add cifs nas-isos \
  --server 192.168.1.10 \
  --share proxmox-isos \
  --username proxmox \
  --password secretpass \
  --content iso

Organizing Storage

A clean storage layout avoids confusion:

Storage Name Backend Content Types Purpose
local dir (/var/lib/vz) iso, vztmpl, backup ISOs, CT templates, small backups
local-lvm LVM-thin images, rootdir VM disks and CT rootfs (default)
vmdata ZFS images, rootdir Primary VM disk storage
nas-backups NFS backup Backup destination on NAS
nas-isos NFS iso ISO library on NAS

Keep ISOs and backups off the storage you use for running VMs. A NAS is ideal for both.

pvesm CLI

Manage storage from the command line:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# List all storage
pvesm status

# Show available content types for a storage
pvesm list local

# Scan for available ISOs on a storage
pvesm scan nfs 192.168.1.10

# Remove storage definition (does not delete data)
pvesm remove nas-isos

Part 4: Creating Virtual Machines

Uploading ISOs

Upload ISO images to local storage via the UI (local → ISO Images → Upload) or download directly from the host:

1
2
3
# Download directly to ISO storage on the Proxmox host
wget -P /var/lib/vz/template/iso/ \
  https://releases.ubuntu.com/24.04/ubuntu-24.04-live-server-amd64.iso

VM Creation Wizard

In the web UI, click Create VM. Key decisions at each step:

General: Set VMID (Proxmox assigns these automatically, starting at 100), name, and resource pool.

OS: Select the OS type. This affects which defaults Proxmox sets for drivers and BIOS. Select the ISO you uploaded.

System:

  • BIOS: SeaBIOS (legacy BIOS) or OVMF (UEFI). UEFI is required for Secure Boot and is recommended for Windows VMs and modern Linux installs. Use SeaBIOS for older OSes or simpler setups.
  • Machine type: q35 is the modern machine type and supports PCIe, which is required for GPU passthrough. Use q35 for any VM you might want to pass hardware into. i440fx is the legacy option.
  • SCSI controller: VirtIO SCSI for best performance. Do not use the legacy IDE or LSI controllers unless you have a specific reason.
  • Qemu Agent: Enable it if you plan to install the guest agent.

Disks:

  • Bus/Device: VirtIO Block for the best raw disk performance, or SCSI with the VirtIO SCSI controller.
  • Cache: None (uses host page cache) is the safe default. writeback is faster but risks data loss on power failure without a UPS. Write through is a reasonable middle ground.
  • Discard: Enable if using thin-provisioned storage (LVM-thin, ZFS). This allows the guest to trim unused blocks back to the host.
  • IO thread: Enable for better multi-disk performance.

CPU:

  • Sockets and Cores: Assign conservatively — you can always change it later. Remember that CPU overcommit is possible (total vCPU across all VMs can exceed physical cores), but only if workloads are not simultaneously CPU-bound.
  • Type: host is the best choice for performance. It passes through the actual CPU model and features, enabling the guest to use all available instruction sets (AVX-512, etc.). The downside is that you cannot live-migrate to a host with a different CPU family. kvm64 is the safe cross-architecture baseline. Specific CPU models (like Skylake-Server) are useful in clusters with heterogeneous CPUs.

Memory:

  • Enable Ballooning for dynamic memory allocation. With the balloon driver installed in the guest, Proxmox can reclaim idle memory from VMs and reallocate it to ones that need it. Set a minimum and maximum.

Network:

  • Model: VirtIO (paravirtualized) for best performance. The E1000 emulated NIC is useful only for older guests that lack VirtIO drivers.
  • Bridge: vmbr0 (the default Linux bridge connected to your physical NIC).
  • VLAN Tag: Assign a VLAN ID here if you are using a VLAN-aware bridge.

VirtIO Drivers

VirtIO drivers are paravirtualized device drivers that eliminate the overhead of emulating real hardware. The guest OS knows it is running in a VM and uses an efficient hypercall interface instead. Always use VirtIO for disk, network, and memory balloon in Linux guests — the drivers are built into the kernel since 2.6.25.

For Windows guests, download the VirtIO driver ISO from the Fedora Project:

1
2
wget -P /var/lib/vz/template/iso/ \
  https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/stable-virtio/virtio-win.iso

Attach this ISO as a second CD-ROM during Windows installation so you can load the storage driver when the installer cannot find the disk.

Cloud-Init: VM Templates the Right Way

Cloud-init is the standard way to provision Linux VMs with pre-configured networking, SSH keys, and users — without interactive installation. The workflow is: download a cloud image, import it as a disk, convert the VM to a template, clone the template.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# Download Ubuntu 24.04 cloud image
wget -P /tmp/ https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img

# Create a VM (no disk yet)
qm create 9000 \
  --name ubuntu-2404-template \
  --memory 2048 \
  --cores 2 \
  --net0 virtio,bridge=vmbr0 \
  --machine q35 \
  --bios ovmf \
  --scsihw virtio-scsi-pci

# Import the cloud image disk into your storage pool
qm importdisk 9000 /tmp/noble-server-cloudimg-amd64.img vmdata

# Attach the imported disk
qm set 9000 --scsi0 vmdata:vm-9000-disk-0,discard=on

# Resize the disk to something useful
qm resize 9000 scsi0 20G

# Add the EFI disk (required for UEFI/OVMF)
qm set 9000 --efidisk0 vmdata:0,efitype=4m,pre-enrolled-keys=0

# Add a cloud-init drive (IDE or SCSI — IDE2 is conventional)
qm set 9000 --ide2 vmdata:cloudinit

# Set boot order
qm set 9000 --boot order=scsi0

# Set cloud-init options in the UI or via CLI
qm set 9000 \
  --ciuser adminuser \
  --sshkeys ~/.ssh/authorized_keys \
  --ipconfig0 ip=dhcp

# Enable the QEMU guest agent
qm set 9000 --agent enabled=1

# Convert to template (this is irreversible — make sure you are done configuring)
qm template 9000

To deploy a new VM from this template, clone it:

1
2
3
4
5
6
7
8
# Full clone — independent copy, does not depend on template storage
qm clone 9000 101 --name webserver-01 --full --storage vmdata

# Linked clone — shares base disk with template, uses less space but requires template
qm clone 9000 102 --name webserver-02

# Start the new VM
qm start 101

QEMU Guest Agent

The QEMU guest agent runs inside the VM and allows Proxmox to:

  • Get accurate IP addresses from the VM
  • Freeze the filesystem before taking a snapshot (for consistent backups)
  • Gracefully shut down the guest from the Proxmox UI

Install inside the guest VM:

1
2
3
4
5
6
7
# Debian/Ubuntu
apt install qemu-guest-agent
systemctl enable --now qemu-guest-agent

# RHEL/Fedora/Rocky
dnf install qemu-guest-agent
systemctl enable --now qemu-guest-agent

Enable in Proxmox (VM → Options → QEMU Guest Agent → Enable) or via CLI:

1
qm set 101 --agent enabled=1,fstrim_cloned_disks=1

VM Operations

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# Start / stop / reboot
qm start 101
qm shutdown 101    # graceful, uses guest agent if available
qm stop 101        # hard stop (like pulling the power)
qm reboot 101

# Take a snapshot
qm snapshot 101 clean-install --description "Fresh Ubuntu install before config"

# List snapshots
qm listsnapshot 101

# Roll back to snapshot
qm rollback 101 clean-install

# Clone
qm clone 101 201 --name webserver-02 --full --storage vmdata

# Migrate to another node (requires cluster)
qm migrate 101 pve02 --online     # live migration (requires shared storage)
qm migrate 101 pve02              # offline migration

# Delete a VM
qm destroy 101 --purge            # --purge also removes from backup schedules

Part 5: LXC Containers

VMs vs LXC: When to Use Each

LXC containers share the Proxmox host kernel. They have no hardware emulation overhead, start in under a second, and consume dramatically less RAM than full VMs. The tradeoff: they only run Linux, and the kernel is shared (though namespaces provide strong isolation).

Use LXC for:

  • Linux-only services: web servers, databases, DNS, monitoring agents, home automation
  • High-density deployments where you want dozens of isolated services on a single host
  • Workloads where the small overhead of a VM matters

Use KVM VMs for:

  • Windows or other non-Linux OSes
  • Workloads that require a specific kernel version incompatible with the host
  • Security-critical services where you want hardware-level isolation
  • Anything requiring device passthrough (GPU, USB, etc.)

Downloading Container Templates

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# List available templates from the official catalog
pveam update
pveam available

# Download a specific template
pveam download local debian-12-standard_12.7-1_amd64.tar.zst
pveam download local ubuntu-24.04-standard_24.04-1_amd64.tar.zst

# List locally downloaded templates
pveam list local

Creating a Container

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
pct create 200 local:vztmpl/ubuntu-24.04-standard_24.04-1_amd64.tar.zst \
  --hostname docker-host \
  --storage vmdata \
  --rootfs vmdata:20 \
  --cores 4 \
  --memory 4096 \
  --swap 1024 \
  --net0 name=eth0,bridge=vmbr0,ip=dhcp \
  --nameserver 1.1.1.1 \
  --searchdomain lan.example.com \
  --password mysecretpassword \
  --ssh-public-keys /root/.ssh/authorized_keys \
  --unprivileged 1 \
  --start 1

Privileged vs Unprivileged Containers

Unprivileged containers (recommended) run with UID/GID mapping: root inside the container (UID 0) maps to a high unprivileged UID on the host (e.g., 100000). Even if a process escapes the container namespace, it has no host privileges. This is the secure default.

Privileged containers run with no UID mapping: root inside the container is root on the host. Required for some use cases (running Docker inside LXC with certain configurations, loading kernel modules) but represents a security boundary weakening. Use only when necessary.

1
2
3
4
# Check current mode
pct config 200 | grep unprivileged

# Cannot toggle after creation — create a new container with the desired mode

Bind Mounts: Sharing Host Directories

Bind mounts let you expose a directory from the Proxmox host into an LXC container. Useful for sharing data between containers or passing in a dataset managed by ZFS.

1
2
3
4
5
6
7
# Add a bind mount (host path → container path)
pct set 200 --mp0 /mnt/data/media,mp=/mnt/media

# For unprivileged containers, you need to ensure the host directory
# is owned by the UID/GID mapping used inside the container
# Host root maps to container UID offset: usually offset 100000
chown -R 100000:100000 /mnt/data/media

Running Docker Inside LXC

Running Docker inside an LXC container is popular for keeping Docker isolated without the overhead of a full VM. It requires a privileged container or specific feature flags:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# Create container with Docker-compatible settings
pct create 201 local:vztmpl/ubuntu-24.04-standard_24.04-1_amd64.tar.zst \
  --hostname docker-lxc \
  --storage vmdata \
  --rootfs vmdata:40 \
  --cores 4 \
  --memory 8192 \
  --net0 name=eth0,bridge=vmbr0,ip=dhcp \
  --unprivileged 1 \
  --features keyctl=1,nesting=1

# After creation, edit the config to add required mounts
# /etc/pve/lxc/201.conf

Add to /etc/pve/lxc/201.conf:

features: keyctl=1,nesting=1

nesting=1 enables support for running containers inside containers. keyctl=1 enables the kernel keyring for Docker’s credential store. This combination allows Docker to run in an unprivileged container on modern kernels.

pct CLI Reference

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# Start / stop / restart
pct start 200
pct shutdown 200
pct stop 200
pct reboot 200

# Open a console
pct enter 200           # attach to container shell
pct console 200         # VNC/serial console

# Execute a command inside the container
pct exec 200 -- systemctl status nginx

# Copy files in and out
pct push 200 /tmp/myfile.conf /etc/myfile.conf
pct pull 200 /etc/nginx/nginx.conf /tmp/nginx.conf

# Take a snapshot
pct snapshot 200 before-update
pct rollback 200 before-update

# List all containers
pct list

# Show config
pct config 200

# Resize rootfs
pct resize 200 rootfs 40G

Part 6: Networking

Linux Bridges

Proxmox networking is built on Linux bridges. A bridge acts like a virtual switch: physical NICs and VM/LXC virtual interfaces are plugged into it, and traffic flows between them.

The default bridge vmbr0 is created during installation and connected to your primary NIC. Inspect and manage network config:

1
2
3
4
5
# View current network config
cat /etc/network/interfaces

# Apply changes without reboot
ifreload -a

A typical /etc/network/interfaces:

auto lo
iface lo inet loopback

auto enp1s0
iface enp1s0 inet manual

auto vmbr0
iface vmbr0 inet static
    address 192.168.1.50/24
    gateway 192.168.1.1
    bridge-ports enp1s0
    bridge-stp off
    bridge-fd 0
    dns-nameservers 192.168.1.1

VLANs

To use VLANs, make vmbr0 VLAN-aware:

auto vmbr0
iface vmbr0 inet static
    address 192.168.1.50/24
    gateway 192.168.1.1
    bridge-ports enp1s0
    bridge-stp off
    bridge-fd 0
    bridge-vlan-aware yes
    bridge-vids 2-4094

With a VLAN-aware bridge, assign VLAN tags to individual VMs and containers in their network device configuration. The bridge handles the tagging transparently. Your upstream switch port should be configured as a trunk port passing all relevant VLANs.

For the Proxmox management interface itself, create a dedicated VLAN interface:

auto enp1s0.10
iface enp1s0.10 inet manual

auto vmbr10
iface vmbr10 inet static
    address 10.10.10.50/24
    gateway 10.10.10.1
    bridge-ports enp1s0.10
    bridge-stp off
    bridge-fd 0

Network Bonding

Bond two physical NICs for redundancy (active-backup) or increased throughput (LACP/802.3ad):

auto bond0
iface bond0 inet manual
    bond-slaves enp1s0 enp2s0
    bond-miimon 100
    bond-mode active-backup   # or 802.3ad for LACP

auto vmbr0
iface vmbr0 inet static
    address 192.168.1.50/24
    gateway 192.168.1.1
    bridge-ports bond0
    bridge-stp off
    bridge-fd 0

LACP (802.3ad) requires switch support. Active-backup works with any switch configuration.

SDN: Software Defined Networking

Proxmox 8 introduced a stable SDN subsystem that provides VNets (virtual networks), zones, and subnets — abstractions that work across a cluster without manually configuring each node. SDN is configured in Datacenter → SDN and is particularly useful in clustered environments where you want VMs on different nodes to share a layer-2 network without VXLAN complexity exposed to the operator.

Enable the SDN plugin:

1
apt install libpve-network-perl

Then create zones and VNets in the UI. SDN supports simple (single node), VLAN, VXLAN, and Evpn zone types.


Part 7: Backups

Built-in Backup with vzdump

Proxmox includes vzdump for backing up both VMs and LXC containers. Three backup modes:

  • snapshot — Creates a point-in-time snapshot and backs up from that. Zero downtime, requires snapshot-capable storage (LVM-thin, ZFS).
  • suspend — Suspends the VM briefly to get a consistent state, then resumes. Short downtime (seconds).
  • stop — Stops the VM, backs up, restarts. Guaranteed consistency but full downtime.
1
2
3
4
5
6
7
8
# Backup VM 101 to NFS storage, snapshot mode
vzdump 101 --storage nas-backups --mode snapshot --compress zstd

# Backup all VMs and containers
vzdump --all --storage nas-backups --mode snapshot --compress zstd

# Backup specific LXC container
vzdump 200 --storage nas-backups --mode snapshot

Scheduling Backups

Configure scheduled backups in the UI at Datacenter → Backup → Add. You can schedule backups for all VMs, specific VMs by ID, or by node. Set retention policies (keep last N daily, weekly, monthly backups) to manage storage.

The schedule creates a cron job under the hood. You can also see and edit the raw job:

1
cat /etc/pve/jobs.cfg

Proxmox Backup Server (PBS)

PBS is a separate Proxmox product (also free) that runs on its own machine and acts as a dedicated backup target. It provides:

  • Deduplication and incremental backups — Only changed blocks are transmitted after the first backup. A 20 GB VM backup might take 200 MB incremental after the first run.
  • Chunk-based storage — Efficient storage of many VM versions.
  • Backup verification — PBS can verify that stored backups are readable and uncorrupted.
  • Encryption — Client-side encryption before data leaves the Proxmox node.
  • Pruning and GC — Automated retention management with garbage collection.

Running PBS on a separate physical machine (even a small one like an N100 mini PC with a large drive) is the recommended backup architecture for any serious homelab. The space savings from deduplication make it far more efficient than dumping vzdump archives to NFS.

Add PBS as a storage target:

1
2
3
4
5
6
7
pvesm add pbs pbs-main \
  --server 192.168.1.20 \
  --datastore main \
  --username backup@pbs \
  --password yourpassword \
  --content backup \
  --fingerprint AA:BB:CC:...   # PBS server fingerprint from PBS web UI

Restoring from Backup

1
2
3
4
5
6
7
8
# Restore VM 101 from backup (creates new VM or overwrites existing)
qmrestore /mnt/nas-backups/dump/vzdump-qemu-101-2026_03_25-02_00_00.vma.zst 101

# Restore to a different VMID
qmrestore vzdump-qemu-101-2026_03_25-02_00_00.vma.zst 150 --storage vmdata

# Restore LXC container
pct restore 200 vzdump-lxc-200-2026_03_25-02_00_00.tar.zst --storage vmdata

In the web UI, navigate to the backup storage, select the backup file, and click Restore.


Part 8: Clustering

What Clustering Gives You

A Proxmox cluster connects multiple Proxmox nodes into a single management unit. From the web UI, you manage all nodes, all VMs, and all containers through one interface. Beyond convenience, clustering enables:

  • Live migration: Move a running VM from one node to another with no downtime (requires shared storage, or offline migration without it)
  • High Availability: Automatically restart VMs on other nodes if a node fails
  • Centralized storage: Ceph provides shared storage across all nodes without a separate NAS
  • Resource pooling: Treat the entire cluster as a single resource pool

Quorum and the 3-Node Rule

Proxmox uses Corosync for cluster communication and Votequorum for quorum management. Quorum prevents split-brain: if the cluster cannot reach agreement (because nodes cannot communicate), it refuses to make changes rather than risk inconsistency.

A two-node cluster has no quorum by default — if one node loses network connectivity, neither node can determine whether the other is dead or just unreachable, and both stop accepting changes. Proxmox provides a qdevice (quorum device) daemon for two-node clusters, which acts as a tiebreaker using a third small machine (even a Raspberry Pi).

Three nodes is the practical minimum for a proper cluster: losing one node still leaves two, which have quorum. For HA to be useful (fencing a failed node and restarting its VMs), you need at least three nodes.

Creating a Cluster

On the first node (future cluster master):

1
2
3
4
pvecm create mycluster

# Verify
pvecm status

On each additional node:

1
2
3
4
# Join the cluster (run on the node being added)
pvecm add 192.168.1.50    # IP of the first/existing node

# You will be prompted for the root password of the existing node

After joining, the new node appears in the UI under all cluster nodes. All cluster config is stored in /etc/pve/ which is a distributed filesystem (pmxcfs) backed by Corosync.

Cluster Network

Corosync cluster traffic is latency-sensitive. For production use, dedicate a separate network interface for cluster communication:

1
pvecm create mycluster --link0 192.168.1.50 --link1 10.0.0.50

Using two links provides both redundancy and the ability to separate cluster heartbeat traffic from VM traffic. Even in a homelab, using a second NIC or VLAN for cluster traffic is good practice — if your main switch is saturated, you do not want cluster heartbeats to drop and trigger false failovers.

1
2
3
4
5
6
7
8
# Check cluster status
pvecm status

# List cluster nodes
pvecm nodes

# Check Corosync ring status (network paths)
corosync-cfgtool -s

Live Migration

Live migration moves a running VM between cluster nodes. Requirements:

  • Shared storage: The VM’s disk must be accessible from both nodes (NFS, Ceph, iSCSI). If using local storage on both nodes, only offline migration (which stops the VM) is possible.
  • Same or compatible CPU type: If using host CPU type, migration between nodes with different CPU families fails. Use a named CPU type (e.g., Skylake-Server) for migrateable VMs.
  • Sufficient resources on the target node: Enough free RAM for the migrating VM.
1
2
3
4
5
# Online (live) migration — VM keeps running
qm migrate 101 pve02 --online --with-local-disks

# Offline migration — VM is stopped, transferred, restarted
qm migrate 101 pve02

High Availability

HA in Proxmox monitors VMs and containers and restarts them on surviving nodes if their host fails. Enable HA:

  1. Navigate to Datacenter → HA → Add and add a VM to HA.
  2. Assign it to an HA group (a group of nodes it is allowed to run on).
  3. Set the max restart and max relocate counts.

HA requires at least three nodes for quorum and a working fencing mechanism. Fencing (STONITH — Shoot The Other Node In The Head) ensures that a failed node is truly dead before its VMs are restarted elsewhere. Without fencing, restarting a VM on a new node while the old node might still be running it risks data corruption.

Proxmox supports hardware fencing via IPMI/IDRAC/iLO:

1
2
# In Datacenter → HA → Fencing, configure a hardware watchdog
# or IPMI-based fence agent

For homelabs without IPMI, you can use the watchdog-based fencing (softdog), which is less reliable but better than nothing.


Part 9: GPU Passthrough (PCIe Passthrough)

Why Passthrough

PCIe passthrough gives a VM direct, exclusive access to a hardware device — typically a GPU, but also NICs, USB controllers, or NVMe drives. Use cases:

  • Gaming VM with full GPU performance
  • AI/ML workloads with CUDA on a dedicated GPU
  • Plex/Jellyfin hardware transcoding in a VM
  • Separating networking hardware into a firewall VM

Requirements

  1. CPU with IOMMU support: Intel VT-d or AMD AMD-Vi, enabled in BIOS/UEFI
  2. Proper IOMMU groups: Devices must be in their own IOMMU group, or in a group where you can pass through all devices in it
  3. VFIO kernel modules loaded on the host
  4. Host GPU drivers blacklisted so the host does not bind to the GPU you want to pass through

Step 1: Enable IOMMU

Edit GRUB config:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# Intel CPU
nano /etc/default/grub
# Change GRUB_CMDLINE_LINUX_DEFAULT to:
GRUB_CMDLINE_LINUX_DEFAULT="quiet intel_iommu=on iommu=pt"

# AMD CPU
GRUB_CMDLINE_LINUX_DEFAULT="quiet amd_iommu=on iommu=pt"

update-grub
reboot

iommu=pt (passthrough mode) improves performance for devices not being passed through.

Verify IOMMU is active after reboot:

1
2
3
4
5
6
7
8
9
dmesg | grep -e DMAR -e IOMMU
# Should see: "IOMMU enabled" or "Intel-IOMMU: enabled"

# Check IOMMU groups
for d in /sys/kernel/iommu_groups/*/devices/*; do
  n=${d#*/iommu_groups/*}; n=${n%%/*}
  printf 'IOMMU Group %s ' "$n"
  lspci -nns "${d##*/}"
done

Your GPU should appear in its own IOMMU group. If it shares a group with other devices (commonly the case with consumer motherboards), you either need to pass through all devices in the group, or use the ACS override kernel patch (which weakens IOMMU isolation guarantees).

Step 2: Load VFIO Modules

1
2
3
4
5
6
echo "vfio" >> /etc/modules
echo "vfio_iommu_type1" >> /etc/modules
echo "vfio_pci" >> /etc/modules
echo "vfio_virqfd" >> /etc/modules

update-initramfs -u -k all

Step 3: Blacklist Host GPU Drivers

Prevent the host from binding to the GPU:

1
2
3
4
5
6
7
# For NVIDIA GPU
echo "blacklist nouveau" >> /etc/modprobe.d/blacklist.conf
echo "blacklist nvidia" >> /etc/modprobe.d/blacklist.conf

# For AMD GPU
echo "blacklist radeon" >> /etc/modprobe.d/blacklist.conf
echo "blacklist amdgpu" >> /etc/modprobe.d/blacklist.conf

Bind the device to vfio-pci instead. Get the PCI IDs first:

1
2
3
lspci -nn | grep -i nvidia
# 01:00.0 VGA compatible controller [0300]: NVIDIA Corporation RTX 4070 [10de:2786]
# 01:00.1 Audio device [0403]: NVIDIA Corporation [10de:22bc]
1
2
3
echo "options vfio-pci ids=10de:2786,10de:22bc" > /etc/modprobe.d/vfio.conf
update-initramfs -u -k all
reboot

Step 4: Add GPU to VM

In the VM’s hardware settings, add a PCI device. Select the GPU’s PCI address. Enable:

  • All Functions (passes the GPU and its audio device together)
  • Primary GPU if this is the only display output (no virtual display)
  • ROM-Bar (usually required for NVIDIA)
  • PCI-Express (for PCIe devices)

Set the machine type to q35 and the BIOS to OVMF (UEFI). Remove the virtual display (Display: None) if you want the GPU as the sole display output.

Common Pitfalls

  • IOMMU group contamination: If your GPU shares a group with a PCIe root port or another device, you must pass through the entire group or use an ACS-patched kernel. The community Proxmox kernel builds sometimes include the ACS patch.
  • NVIDIA code 43 in Windows: Older NVIDIA drivers refused to work in VMs. Modern drivers (since 465.x) removed this restriction, but you may need to hide the VM hypervisor signature: cpu: host,hidden=1 in the VM config.
  • Reset bug: Some GPUs (particularly AMD) cannot be reset cleanly after the VM stops, requiring a host reboot. The vendor-reset kernel module addresses this for many affected GPUs.

Part 10: Tips, Tools, and Optimizations

pveperf — Quick Benchmark

1
2
3
pveperf
# Runs a quick benchmark of CPU, memory, and storage I/O
# Useful for comparing nodes or validating storage performance after changes

Dark Theme

The community Proxmox Dark theme applies a dark mode to the web UI. Install via the Proxmox helper scripts or manually:

1
2
wget https://raw.githubusercontent.com/Weilbyte/PVEDiscordDark/master/PVEDiscordDark.sh
bash PVEDiscordDark.sh install

Proxmox Helper Scripts (Community tteck Scripts)

The community Proxmox Helper Scripts (originally by tteck, now maintained at community-scripts.github.io) provide one-line installers for dozens of common homelab services as optimized LXC containers:

1
2
3
4
5
# Example: Deploy Home Assistant OS in a VM
bash -c "$(wget -qLO - https://github.com/community-scripts/ProxmoxVE/raw/main/vm/haos-vm.sh)"

# Deploy Pi-hole LXC
bash -c "$(wget -qLO - https://github.com/community-scripts/ProxmoxVE/raw/main/ct/pihole.sh)"

These scripts create a pre-configured container or VM with sensible defaults and automatic updates. They are the fastest way to get common services running.

Monitoring with InfluxDB and Grafana

Proxmox has built-in metrics export to InfluxDB. Configure it in Datacenter → Metric Server → Add → InfluxDB:

Server: 192.168.1.30
Port: 8086
Protocol: UDP (or HTTP for InfluxDB v2)
Organization: homelab
Bucket: proxmox
Token: your-influxdb-token

Once metrics are flowing into InfluxDB, import the community Proxmox Grafana dashboard (available on grafana.com, search for “Proxmox”) to get node CPU, memory, disk I/O, network throughput, and per-VM resource usage in a polished dashboard.

Log Inspection

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# All Proxmox services
journalctl -u pve* --since "1 hour ago"

# Specific services
journalctl -u pvedaemon        # Main daemon
journalctl -u pveproxy         # Web UI proxy
journalctl -u pve-cluster      # Cluster service
journalctl -u corosync         # Cluster communication

# VM/CT specific logs
journalctl -u qemu-server@101  # VM 101

# Cluster log (distributed across all nodes)
journalctl -u pve-cluster -f

CPU and Memory Overcommit

Proxmox allows you to allocate more vCPUs and RAM than physically available. For CPU, overcommit is safe as long as workloads are not simultaneously CPU-bound — a 16-core host can run 32 vCPUs across multiple VMs if they are not all maxing out simultaneously. For memory, overcommit is riskier: if VMs actually try to use more RAM than is physically available, the host will start swapping, performance degrades dramatically, and the OOM killer may start terminating processes.

Use memory ballooning and set realistic minimums per VM. Monitor actual usage with:

1
2
3
4
5
6
# Memory usage summary for all VMs
for vmid in $(qm list | awk 'NR>1 {print $1}'); do
  name=$(qm config $vmid | grep ^name | awk '{print $2}')
  mem=$(qm monitor $vmid <<< 'info balloon' 2>/dev/null | grep -oP '\d+(?= MB)')
  echo "VM $vmid ($name): ${mem} MB actual"
done

Nested Virtualization

Run VMs inside VMs — useful for testing Proxmox itself, Kubernetes setups, or hypervisor development:

1
2
3
4
5
6
7
8
9
# Enable nested virtualization on the host
echo "options kvm-intel nested=1" > /etc/modprobe.d/kvm-intel.conf
# or for AMD
echo "options kvm-amd nested=1" > /etc/modprobe.d/kvm-amd.conf

modprobe -r kvm-intel && modprobe kvm-intel   # reload without reboot

# Verify
cat /sys/module/kvm_intel/parameters/nested   # should print Y or 1

Set the VM’s CPU type to host or a specific model that exposes VMX/SVM flags. The nested VM will then be able to run KVM.


Putting It All Together

A practical homelab Proxmox architecture for a single powerful host might look like this:

  • OS: Proxmox VE 8 on a ZFS mirror of two NVMe drives
  • VM storage: A ZFS pool (vmdata) on four SSDs in RAIDZ1
  • Backup storage: PBS running on a separate small machine, targeting a large HDD pool
  • Network: vmbr0 VLAN-aware, trunk to managed switch; VMs and LXC containers assigned to appropriate VLANs
  • VMs: Windows gaming VM (GPU passthrough), pfSense/OPNsense firewall VM, Ubuntu server for critical services requiring VM isolation
  • LXC containers: Home Assistant, Nextcloud, Jellyfin, Pi-hole, Uptime Kuma, monitoring stack — all in lightweight unprivileged containers

For two or three nodes, add clustering: Ceph for shared VM storage, HA for critical VMs, a dedicated cluster network on a second NIC or VLAN.

Proxmox scales from a single mini PC to a 32-node enterprise cluster running the same software. The learning curve is steeper than Docker Compose, shallower than Kubernetes, and the skills transfer directly to enterprise environments running the same KVM/LXC stack. For consolidating homelab hardware and running a mix of VMs and containers with serious management tooling, nothing else comes close.

Comments