Proxmox VE (PVE) is an open-source server virtualization environment based on Debian, integrating KVM for VMs and LXC for containers with a central web management UI.
Installation & Setup
Repository Configuration
# Add PVE repository (subscription required)
echo "deb https://enterprise.proxmox.com/debian/pve bookworm pve-enterprise" > /etc/apt/sources.list.d/pve-enterprise.list
# Add no-subscription repository (free, no license key)
echo "deb http://download.proxmox.com/debian/pve bookworm pve-no-subscription" > /etc/apt/sources.list.d/pve-no-subscription.list
# Or disable enterprise and add no-subscription in one step
sed -i 's/^deb/#deb/' /etc/apt/sources.list.d/pve-enterprise.list
echo "deb http://download.proxmox.com/debian/pve bookworm pve-no-subscription" > /etc/apt/sources.list.d/pve-no-subscription.list
# Add the Proxmox repository key
wget -qO- https://download.proxmox.com/debian/proxmox-release-bookworm.gpg | gpg --dearmor -o /etc/apt/trusted.gpg.d/proxmox.gpg
# Install PVE (from Debian)
apt update && apt install -y proxmox-ve postfix open-iscsiPost-Install Configuration
# Remove Debian kernel (replaced by PVE kernel)
apt remove -y linux-image-amd64 linux-image-6.1.0-*-amd64
# Update GRUB
update-grub
# Set hostname and hosts properly
hostnamectl set-hostname pve1.example.com
echo "192.168.1.10 pve1.example.com pve1" >> /etc/hosts
# Verify installation
pveversion
# Output: pve-manager/8.2.xRemoving Subscription Nag
# Method 1: Comment out the nag line in JS (patches web UI)
sed -E "s/(data.status !== 'Active')/false \&\& \1/" /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js
# Method 2: Restart pveproxy after modifying
systemctl restart pveproxy
# Method 3: Free subscription notice via no-subscription repo
# The nag appears only with enterprise repo — using no-subscription avoids it entirelyWeb UI & CLI
Web Interface
# Access URL
# https://<server-ip>:8006
# Default credentials: root user with the system root password
# Restart web proxy (if UI is unresponsive)
systemctl restart pveproxy
# Check proxy status
systemctl status pveproxy
# View access log
tail -f /var/log/pveproxy/access.logCLI — pvesh
# List all API endpoints
pvesh ls /
# Get node status
pvesh get /nodes/{nodename}/status
# Get cluster resources
pvesh get /cluster/resources
# Get VM configuration
pvesh get /nodes/{nodename}/qemu/{vmid}/config
# Set VM option (e.g., memory)
pvesh set /nodes/{nodename}/qemu/{vmid}/config --memory 4096
# Create a VM
pvesh create /nodes/{nodename}/qemu --vmid 101 --name test-vm --memory 2048 --cores 2
# List storage
pvesh get /storage
# Get task log
pvesh get /nodes/{nodename}/tasks/{upid}/logCLI — Additional Tools
# VM monitor (QEMU monitor)
qm monitor {vmid}
# Show VM config
qm config {vmid}
# List all VMs with status
qm list
# List all containers
pct list
# Show storage usage
pvesm status
# List ISO templates on storage
pvesm list {storage}VM Management (KVM/QEMU)
Creating VMs
# Create a VM with basic settings
qm create 100 --name webserver --memory 2048 --cores 2 --sockets 1 \
--net0 virtio,bridge=vmbr0 --ostype l26
# Create VM with disk on specific storage
qm create 101 --name db-server --memory 4096 --cores 4 \
--scsi0 local-lvm:32 --scsihw virtio-scsi-pci \
--net0 virtio,bridge=vmbr0
# Create VM from template (clone)
qm clone 9000 102 --name cloned-vm --full 1
# Create linked clone (snapshot-based, faster)
qm clone 9000 103 --name linked-clone --full 0
# Start VM with CD-ROM ISO
qm create 104 --name installer --cdrom local:iso/debian-12.iso --boot cStarting & Stopping
# Start a VM
qm start {vmid}
# Stop a VM (ACPI shutdown)
qm stop {vmid}
# Force stop (power off)
qm stop {vmid} --skiplock
# Shutdown gracefully
qm shutdown {vmid}
# Reboot VM
qm reboot {vmid}
# Reset VM (cold reboot)
qm reset {vmid}
# Suspend/resume
qm suspend {vmid}
qm resume {vmid}VM Configuration
# Set memory (MB) on a running VM (hot-plug requires qemu-guest-agent)
qm set {vmid} --memory 8192
# Add CPU cores (hot-plug)
qm set {vmid} --cores 8
# Add a network interface
qm set {vmid} --net1 e1000,bridge=vmbr1
# Add a raw disk
qm set {vmid} --scsi1 local-lvm:16
# Resize disk (add 10G to scsi0)
qm resize {vmid} scsi0 +10G
# Set boot order
qm set {vmid} --boot order=scsi0;ide2;net0
# Attach USB device
qm set {vmid} --usb0 host=002:003
# Enable QEMU guest agent
qm set {vmid} --agent 1Migration & Snapshots
# Live migrate VM to another node
qm migrate {vmid} target-node --online
# Offline migration
qm migrate {vmid} target-node
# Create snapshot
qm snapshot {vmid} pre-upgrade --description "Before kernel upgrade"
# List snapshots
qm listsnapshot {vmid}
# Rollback to snapshot
qm rollback {vmid} pre-upgrade
# Delete snapshot
qm delsnapshot {vmid} pre-upgrade
# Create backup via CLI
vzdump {vmid} --mode snapshot --storage backup-storage --compress zstd
# Template operations
qm template {vmid} # Convert VM to templateAdvanced VM Operations
# Move disk to different storage
qm move_disk {vmid} scsi0 target-storage --delete 1
# Import disk image
qm importdisk {vmid} /path/to/disk.raw local-lvm
# Attach cloud-init image
qm set {vmid} --ide2 local-lvm:cloudinit
# Generate cloud-init password
qm set {vmid} --cipassword my-secure-password
# Set VM description
qm set {vmid} --description "Production web server"
# Destroy VM (irreversible)
qm destroy {vmid}Container Management (LXC)
Downloading Templates
# List available templates
pveam list local
# Update template list
pveam update
# Download a template
pveam download local ubuntu-22.04-standard_22.04-1_amd64.tar.zst
# List templates from all storage
pveam availableCreating Containers
# Create a container
pct create 200 local:vztmpl/ubuntu-22.04-standard_22.04-1_amd64.tar.zst \
--hostname container1 --storage local-lvm --rootfs 8 \
--net0 name=eth0,bridge=vmbr0,ip=dhcp
# Create with static IP
pct create 201 local:vztmpl/debian-12-standard_12.0-1_amd64.tar.zst \
--hostname mail-server --storage local-lvm --rootfs 16 \
--net0 name=eth0,bridge=vmbr0,ip=192.168.1.50/24,gw=192.168.1.1
# Create unprivileged container (recommended for security)
pct create 202 local:vztmpl/ubuntu-24.04-standard_24.04-1_amd64.tar.zst \
--hostname unpriv-ct --storage zfs-pool --rootfs 10 \
--unprivileged 1 --features nesting=1Starting & Stopping Containers
# Start a container
pct start {vmid}
# Stop a container
pct stop {vmid}
# Shutdown gracefully
pct shutdown {vmid}
# Reboot
pct reboot {vmid}
# Suspend/resume
pct suspend {vmid}
pct resume {vmid}Container Management
# Enter a container (like SSH but direct)
pct enter {vmid}
# Execute command inside container
pct exec {vmid} -- apt update
# Set container resources
pct set {vmid} --memory 2048 --swap 1024 --cores 2
# Mount a bind mount from host
pct set {vmid} --mp0 /mnt/data,mp=/mnt/host-data
# Add mount point
pct set {vmid} --mp1 local-lvm:4,mp=/var/www
# Resize rootfs
pct resize {vmid} rootfs +4G
# Migrate container
pct migrate {vmid} target-node
# Clone container
pct clone {vmid} 203 --hostname cloned-ct
# Convert container to template
pct template {vmid}
# Destroy container
pct destroy {vmid}
# List all containers
pct listContainer Features & Permissions
# Enable NFS mounting inside container
pct set {vmid} --features keyctl=1,nesting=1,fuse=1
# Allow container to use Docker (nesting + NFS)
pct set {vmid} --features nesting=1
# Set container's /etc/pve permissions
pct set {vmid} --cmode shell # Console mode: shell, tty, or console
# Set autostart on boot
pct set {vmid} --onboot 1 --startup order=1,up=30,down=60Storage Management
Storage Pool Types
# List all configured storage
pvesm status
# Show detailed storage config
pvesh get /storage
# Create directory-based storage
pvesm add dir backup --path /mnt/backup
# Create LVM-thin storage
pvesm add lvmthin local-lvm --thinpool data --vgname pve
# Create ZFS pool
zpool create -f -o ashift=12 zfspool /dev/sda /dev/sdb
pvesm add zfspool zfspool --pool zfspool --blocksize 4k
# Create NFS mount storage
pvesm add nfs nfs-backup --server 192.168.1.100 --export /volume1/backups
# Create iSCSI storage
pvesm add iscsi iscsi-storage --portal 192.168.1.200 --target iqn.2001-05.com.example:storageLVM & LVM-thin
# List physical volumes
pvdisplay
# List volume groups
vgdisplay
# List logical volumes
lvdisplay
# Create LVM-thin pool
lvcreate -L 100G -T pve/data
# Extend thin pool
lvextend -L +50G pve/data
# Add disk to existing VG
pvcreate /dev/sdc
vgextend pve /dev/sdcZFS
# Create zpool
zpool create -f -o ashift=12 tank mirror /dev/sda /dev/sdb
# Add cache/log device
zpool add tank cache /dev/sdc
zpool add tank log /dev/sdd
# Create dataset
zfs create tank/vmdata
# Set compression
zfs set compression=lz4 tank
# Set quota
zfs set quota=500G tank/vmdata
# List zpools & datasets
zpool list
zfs list
# Scrub a zpool
zpool scrub tank
# Check scrub status
zpool status -v tank
# Replace failed disk
zpool replace tank /dev/sda /dev/sdb
# Remove ZFS storage from PVE
pvesm remove tankNFS & iSCSI
# Mount NFS manually for testing
mount -t nfs 192.168.1.100:/volume1/backups /mnt/backup
# Add NFS storage with options
pvesm add nfs backup-nfs --server 192.168.1.100 --export /volume1/backups \
--options vers=4.2,rsize=1048576,wsize=1048576
# Discover iSCSI targets
iscsiadm -m discovery -t st -p 192.168.1.200
# Login to iSCSI target
iscsiadm -m node -T iqn.2001-05.com.example:storage -l
# List iSCSI sessions
iscsiadm -m session -P 3Backup & Restore
vzdump (Built-in Backup)
# Backup a single VM
vzdump {vmid} --mode snapshot --storage backup-storage --compress zstd
# Backup with specific dump directory
vzdump {vmid} --dumpdir /mnt/backup/dump --compress gzip --mode suspend
# Backup all VMs and containers
vzdump --all --mode snapshot --storage backup-storage --compress zstd
# Backup with email notification
vzdump {vmid} --mode snapshot --storage backup-storage --compress zstd \
--mailto [email protected] --mailnotification always
# Stop mode backup (longest downtime, most consistent)
vzdump {vmid} --mode stop
# Exclude specific VMs in --all backup
vzdump --all --exclude 100,105,110Restoring Backups
# Restore VM from backup
qmrestore /mnt/backup/dump/vzdump-qemu-100-2024_01_15-10_00_00.vma.zst 100
# Restore with new VM ID
qmrestore /mnt/backup/dump/vzdump-qemu-100-2024_01_15-10_00_00.vma.zst 200
# Restore container from backup
pct restore 200 /mnt/backup/dump/vzdump-lxc-200-2024_01_15-10_00_00.tar.zst \
--storage local-lvm --rootfs 8
# List contents of backup archive
vzdump --list /path/to/backup.vma.zst
# Extract single file from backup
zstdcat backup.vma.zst | vma extract - /tmp/extract/Proxmox Backup Server (PBS) Integration
# Add PBS datastore
pvesm add pbs pbs-backups --server pbs.example.com --datastore main \
--username root@pam --password-file /etc/pve/pbs-pass
# Backup to PBS (same vzdump command, different storage)
vzdump {vmid} --storage pbs-backups --mode snapshot
# PBS verify backup
proxmox-backup-client verify --repository root@[email protected]:main backup-id
# List PBS snapshots
proxmox-backup-client snapshot list --repository root@[email protected]:main
# Mount PBS backup as FUSE filesystem
proxmox-backup-client mount backup-id backup-time /mnt/restore \
--repository root@[email protected]:mainScheduling Backups
# Edit backup schedule via web UI or CLI
# Datacenter > Backup > Add
# CLI: Set backup job via API
pvesh create /cluster/backup \
--id hourly-backup \
--schedule "0 * * * *" \
--storage pbs-backups \
--mode snapshot \
--compress zstd \
--all 1 \
--vmid 100,101,102Network Configuration
Linux Bridge
# Default bridge configuration (/etc/network/interfaces)
auto vmbr0
iface vmbr0 inet static
address 192.168.1.10/24
gateway 192.168.1.1
bridge-ports eno1
bridge-stp off
bridge-fd 0
# Create an internal bridge (no physical port)
auto vmbr1
iface vmbr1 inet static
address 10.10.10.1/24
bridge-ports none
bridge-stp off
bridge-fd 0
# Add bridge via CLI
pvesh create /nodes/{nodename}/network \
--type bridge --iface vmbr2 --cidr 172.16.0.1/24
# Apply network changes
ifreload -aBonding
# LACP (802.3ad) bond — requires switch support
auto bond0
iface bond0 inet manual
bond-slaves eno1 eno2
bond-mode 802.3ad
bond-miimon 100
bond-lacp-rate 1
bond-xmit_hash_policy layer3+4
auto vmbr0
iface vmbr0 inet static
address 192.168.1.10/24
bridge-ports bond0
bridge-stp off
bridge-fd 0
# Active-backup bond (no switch config needed)
auto bond1
iface bond1 inet manual
bond-slaves eno3 eno4
bond-mode active-backup
bond-miimon 100
# Check bond status
cat /proc/net/bonding/bond0VLAN
# VLAN on bridge (tagged)
auto vmbr0.100
iface vmbr0.100 inet manual
vlan-raw-device vmbr0
# VLAN-aware bridge (single bridge passes all VLANs)
auto vmbr0
iface vmbr0 inet manual
bridge-ports eno1
bridge-stp off
bridge-fd 0
bridge-vlan-aware yes
bridge-vids 2-4094
# Create tagged VLAN interface
ip link add link vmbr0 name vmbr0.200 type vlan id 200
# Assign VM to specific VLAN via bridge+vlan tag
# In VM config: tag=100 on the bridged network interface
qm set {vmid} --net0 virtio,bridge=vmbr0,tag=100Cluster Management
Creating a Cluster
# On the first node, create the cluster
pvecm create mycluster
# Verify cluster status
pvecm status
# Show cluster nodes
pvecm nodes
# Join a node to the cluster (run on joining node)
pvecm add 192.168.1.10 --password 0
# Rejoin with force (if node was wiped but cluster expects it)
pvecm add 192.168.1.10 --forceCluster Filesystem (/etc/pve)
# Cluster config files are synced via pmxcfs (SQLite-based)
ls -la /etc/pve/
# View cluster configuration
cat /etc/pve/corosync.conf
# View datacenter config
cat /etc/pve/datacenter.cfg
# Edit storage config (changes propagate to all nodes)
cat /etc/pve/storage.cfg
# Force sync cluster filesystem
pmxcfs -l
# Test pmxcfs status
pmxcfs -iQuorum & Node Management
# Check quorum status
pvecm status | grep Quorum
# Expected votes / Total votes info
pvecm status
# Remove a node from cluster
pvecm del {nodename}
# Set expected votes (2-node cluster needs expected=2)
pvecm expected 2
# Check cluster firewall status
pvefirewall status
# Force remove node from corosync (run on remaining node)
pvecm expected 1
pvecm del {nodename}
# Then manually remove from /etc/corosync/corosync.confCeph Basics
# Install Ceph on cluster
pveceph install --version reef
# Create initial Ceph monitor
pveceph init --network 10.10.10.0/24
# Create Ceph OSD
pveceph osd create /dev/sda
# List OSDs
ceph osd tree
# Create Ceph pool
ceph osd pool create vms 128
ceph osd pool create images 128
# Set pool replication
ceph osd pool set vms size 3
# Show Ceph status
ceph status
ceph -s
# Show Ceph disk usage
ceph df
# Enable Ceph dashboard
ceph mgr module enable dashboard
ceph dashboard set-login-credentials admin $passwordUpdates & Maintenance
Package Management
# Update package lists
pveupdate
# Or manually
apt update
# Upgrade PVE packages
pveupgrade
# Full dist-upgrade
apt dist-upgrade
# List installable PVE kernel versions
apt list --installed | grep proxmox
# Check current kernel
uname -r
# View available PVE kernels
apt search proxmox-kernel
# Install specific kernel
apt install proxmox-kernel-6.8Version & System Info
# Show PVE version
pveversion
# Show detailed version info
pveversion -v
# Show system info
pvesh get /nodes/{nodename}/status
# Check subscription status
pvesh get /nodes/{nodename}/subscription
# List available updates
pvesh get /nodes/{nodename}/aptupdate
# Show release info
cat /etc/os-releaseReboot & Shutdown
# Graceful node reboot (migrates VMs if HA enabled)
reboot
# Node shutdown
poweroff
# Reboot with pending migrations check
pvesh create /nodes/{nodename}/status --command reboot
# Drain node (migrate all VMs off, then shutdown)
for vmid in $(qm list | awk 'NR>1{print $1}'); do
qm migrate $vmid target-node --online
doneBacking Up PVE Host Config
Config Backup
# Backup /etc/pve (cluster config)
tar czf /root/pve-etc-backup-$(date +%Y%m%d).tar.gz /etc/pve/
# Backup network interfaces
cp /etc/network/interfaces /root/interfaces.backup
# Backup entire host config
cat /root/pve-host-config-$(date +%Y%m%d).sh << 'EOF'
#!/bin/bash
tar czf /root/pve-config-$(date +%Y%m%d).tar.gz \
/etc/pve/ \
/etc/network/interfaces \
/etc/hosts \
/etc/hostname \
/etc/resolv.conf \
/etc/apt/sources.list \
/etc/apt/sources.list.d/ \
/etc/corosync/corosync.conf \
/var/lib/pve-cluster/config.db
EOF
# Automatic daily config backup via cron
cat > /etc/cron.daily/pve-config-backup << 'SCRIPT'
#!/bin/bash
BACKUP_DIR=/root/pve-config-backups
mkdir -p $BACKUP_DIR
tar czf "$BACKUP_DIR/pve-config-$(date +%Y%m%d-%H%M).tar.gz" \
/etc/pve/ /etc/network/interfaces /etc/hosts \
/etc/hostname /etc/resolv.conf /etc/corosync/corosync.conf
find $BACKUP_DIR -name "*.tar.gz" -mtime +30 -delete
SCRIPT
chmod +x /etc/cron.daily/pve-config-backupRestoring Config
# Restore /etc/pve from backup (on same node)
tar xzf pve-etc-backup-20240101.tar.gz -C /
# Restore cluster config on new node
# Install PVE, then:
pvecm create restored-cluster
cp pve-config-20240101.tar.gz /root/
tar xzf /root/pve-config-20240101.tar.gz -C / --skip-old-files
systemctl restart pve-cluster pvedaemon pveproxy
# Recreate storage config
cat /etc/pve/storage.cfg | grep -E "^(dir|zfspool|lvmthin|nfs|pbs)"
# Re-add each storage manually from the config backupTroubleshooting
Logs & Diagnostics
# Main PVE system log
journalctl -u pvedaemon -n 100 -f
# PVE proxy logs
journalctl -u pveproxy -n 50
# Cluster logs
journalctl -u pve-cluster -n 50
# Task log (specific task ID from web UI)
cat /var/log/pve/tasks/index/{task-upid}
# All recent PVE logs
journalctl -t pvedaemon --since "1 hour ago"
# QEMU guest agent logs
cat /var/log/qemu-ga/qemu-ga.log
# VM serial console log (if configured)
cat /var/log/pve/tasks/serial/serial-{vmid}.logVM/Container Start Failures
# Check why a VM failed to start
journalctl -u qemu-server -n 50
# or
cat /var/log/pve/tasks/* | grep -i "error"
# Verify VM config
qm config {vmid}
# Check disk availability
pvesm status
# Test disk access
pvesh get /nodes/{nodename}/storage/{storage}/content
# Check if disk image exists
ls -lah /var/lib/vz/images/{vmid}/
ls -lah /dev/pve/vm-{vmid}-disk-*
# Locked VM fix (remove lock file)
qm unlock {vmid}
# Check for port conflicts
netstat -tulpn | grep -E "(5900|5901|6000|6001)"Storage Issues
# Check storage status
pvesm status
# Scan storage for new content
pvesm scan
# Check ZFS pool health
zpool status -x
# Check LVM status
lvdisplay
vgdisplay
dmeventd -d
# Check NFS mount
mount | grep nfs
showmount -e 192.168.1.100
# Repair corrupted ZFS pool
zpool import -f -F tank
zpool clear tank
# Check disk health
smartctl -a /dev/sda
smartctl -H /dev/sda
# Check disk I/O
iostat -x 2
iotop -oNetwork Troubleshooting
# Check bridge configuration
bridge link show
bridge vlan show
# Check bond status
cat /proc/net/bonding/bond0
# Test cluster connectivity
pvecm status
# Verify corosync
corosync-cfgtool -s
corosync-quorumtool -l
# Ping all nodes from cluster perspective
pvecm nodes
# Check firewall rules
pvefirewall status
cat /etc/pve/firewall/cluster.fw
# Port checks (SSH, Web UI, cluster)
ss -tlnp | grep -E "(22|8006|5404|5405)"Performance & Resource Issues
# Check CPU/memory
htop
free -h
# Check disk I/O wait
iostat -x 1
# Check running VMs resource usage
qm list | while read id name status mem; do
[ "$status" = "running" ] && qm monitor $id <<< "info cpus"
done
# Check balloon memory
qm monitor {vmid} <<< "info balloon"
# Set CPU limit for VM
qm set {vmid} --cpulimit 50
# Check IOPS limits
qm set {vmid} --scsi0 local-lvm:32,iops_rd=1000,iops_wr=500
# View real-time VM statistics
qemu-img info /dev/pve/vm-{vmid}-disk-0