This article provides a detailed guide on setting up and maintaining Proxmox, based on years of experience. After experimenting with other solutions like TrueNAS, Unraid, and Docker, I found Proxmox to be the most reliable. The two main reasons for this are its stability and ease of reinstallation. Proxmox can run indefinitely without issues unless there is hardware failure, and rebuilding LXC containers is straightforward, with configurations often remembered automatically.
Today, due to some hardware adjustments, I decided to reinstall Proxmox VE (PVE) and all virtual machines, treating it as a Disaster Recovery Test (DIRT). The process went smoothly, and I documented it for future reference.
Installing PVE
Installing Proxmox VE is straightforward—just follow the official guide to install the latest version. For macOS users, there is an official guide for creating a bootable installer. I prefer reinstalling PVE rather than relying on backups (PBS or manual backups of /etc
and other files) because I like starting with a clean slate.
Initializing PVE
For users in China, the first step is to change the package sources. Here is a script that automates the process and performs additional optimizations:
#!/bin/bash
# Define a function for green text output
green_echo() {
echo -e "\e[32m$1\e[0m"
}
# Backup the current APT sources list
green_echo "Backing up current sources.list..."
cp /etc/apt/sources.list /etc/apt/sources.list.bak
# Replace sources with USTC mirror
green_echo "Updating sources.list to use USTC mirror..."
sed -i 's|http://ftp.debian.org/debian|http://mirrors.ustc.edu.cn/debian|g' /etc/apt/sources.list
sed -i 's|http://security.debian.org|http://mirrors.ustc.edu.cn/debian-security|g' /etc/apt/sources.list
# Add non-free repositories
sed -i '/^deb/ s/$/ non-free non-free-firmware/' /etc/apt/sources.list
# Update Proxmox no-subscription repository
PVE_LIST="/etc/apt/sources.list.d/pve-no-subscription.list"
if [ -f "$PVE_LIST" ]; then
green_echo "Updating Proxmox no-subscription repository to use USTC mirror..."
sed -i 's|http://download.proxmox.com/debian/pve|http://mirrors.ustc.edu.cn/proxmox/debian/pve|g' "$PVE_LIST"
else
green_echo "Adding Proxmox no-subscription repository from USTC mirror..."
echo "deb http://mirrors.ustc.edu.cn/proxmox/debian/pve bookworm pve-no-subscription" > "$PVE_LIST"
fi
# Remove enterprise repository list
ENTERPRISE_LIST="/etc/apt/sources.list.d/pve-enterprise.list"
if [ -f "$ENTERPRISE_LIST" ]; then
green_echo "Removing existing Proxmox enterprise repository..."
rm -f "$ENTERPRISE_LIST"
fi
# Update Ceph repository
if [ -f /etc/apt/sources.list.d/ceph.list ]; then
CEPH_CODENAME=$(ceph -v | grep ceph | awk '{print $(NF-1)}')
source /etc/os-release
echo "deb https://mirrors.ustc.edu.cn/proxmox/debian/ceph-$CEPH_CODENAME $VERSION_CODENAME no-subscription" > /etc/apt/sources.list.d/ceph.list
fi
# Update CT Template source
green_echo "Updating CT Template source to use USTC mirror..."
sed -i.bak 's|http://download.proxmox.com|https://mirrors.ustc.edu.cn/proxmox|g' /usr/share/perl5/PVE/APLInfo.pm
# Disable non-free firmware warnings
green_echo "Disabling non-free firmware warnings..."
echo 'APT::Get::Update::SourceListWarnings::NonFreeFirmware "false";' >/etc/apt/apt.conf.d/no-bookworm-firmware.conf
# Remove subscription nag from UI
green_echo "Removing subscription nag from UI..."
echo "DPkg::Post-Invoke { \"dpkg -V proxmox-widget-toolkit | grep -q '/proxmoxlib\.js$'; if [ \$? -eq 1 ]; then { echo 'Removing subscription nag from UI...'; sed -i '/.*data\.status.*{/{s/\!//;s/active/NoMoreNagging/}' /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js; }; fi\"; };" >/etc/apt/apt.conf.d/no-nag-script
apt --reinstall install proxmox-widget-toolkit &>/dev/null
# Disable PVE HA and corosync services if active
if systemctl is-active --quiet pve-ha-crm && systemctl is-active --quiet pve-ha-lrm; then
green_echo "PVE HA is active. Disabling related services..."
systemctl disable -q --now pve-ha-crm
systemctl disable -q --now pve-ha-lrm
fi
if systemctl is-active --quiet corosync; then
green_echo "Corosync is active. Disabling it..."
systemctl disable -q --now corosync
fi
# Update APT package index
green_echo "Updating APT package index..."
apt update
# Detect CPU vendor and install appropriate microcode package
cpu_vendor=$(lscpu | grep -i 'vendor id' | awk '{print $3}')
if [ "$cpu_vendor" == "GenuineIntel" ]; then
green_echo "Detected Intel CPU. Installing intel-microcode..."
apt install -y intel-microcode
elif [ "$cpu_vendor" == "AuthenticAMD" ]; then
green_echo "Detected AMD CPU. Installing amd64-microcode..."
apt install -y amd64-microcode
else
echo "Unknown CPU vendor. No microcode updates applied."
fi
green_echo "All Completed. You may want to do apt upgrade"
Additionally, I optimize CPU scheduling for power saving:
#!/bin/bash
# Desired CPU governor (e.g., "performance", "powersave", "userspace", "ondemand", "conservative", "schedutil")
DESIRED_GOVERNOR="powersave"
# Print all available CPU governors
available_governors=$(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors)
echo "Available CPU governors: $available_governors"
# Detect current governor
current_governor=$(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor)
echo "Current CPU governor: $current_governor"
# Set new governor
echo "$DESIRED_GOVERNOR" | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor >/dev/null
# Confirm governor change
current_governor=$(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor)
echo "CPU governor set to: $current_governor"
# Set in crontab to maintain settings after reboot
CRONTAB_COMMAND="(sleep 60 && echo \"$DESIRED_GOVERNOR\" | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor)"
CRONTAB_ENTRY="@reboot $CRONTAB_COMMAND"
(crontab -l 2>/dev/null | grep -Fv "scaling_governor"; echo "$CRONTAB_ENTRY") | crontab -
echo "Crontab setup completed (use 'crontab -e' to check)"
Setting Up Email Notifications
- Go to
Datacenter > Options > Email from address
and enter your email address. - Navigate to
Datacenter > Notifications > mail-to-root
and click the Test button to ensure you receive the test email.
Restoring Services
Mount the NAS server where backups are stored, and restore from the vzdump
files. Since the MAC addresses remain unchanged, the router will keep the previously assigned static IPs.
After restoring all services, I run a script to tag all LXC containers with their IP addresses for easy identification:
#!/bin/bash
# Fetch all LXC container IDs
lxc_ids=$(pct list | awk 'NR>1 {print $1}')
# Iterate through each LXC container
for id in $lxc_ids; do
# Get LXC container's IPv4 address
ip=$(pct exec $id -- ip -4 addr show eth0 | grep -oP '(?<=inet\s)\d+(\.\d+){3}')
# Extract the last part of the IPv4 address as a tag
if [[ ! -z "$ip" ]]; then
tag=${ip##*.}
# Set the tag
pct set $id --tags $tag
echo "LXC container $id tagged with $tag"
else
echo "No IPv4 address found for LXC container $id"
fi
done
Setting LXC Auto-Backup
Datacenter > Backup > Add:
- General
- Storage: NAS server
- Schedule: 11:00 (daily)
- Job Comment: daily