Automating Proxmox VM Deployment: A Modern Approach to Infrastructure ManagementIn the world of virtualization and infrastructure management, efficiency is ever...
In the world of virtualization and infrastructure management, efficiency is everything. Today, I'm excited to share our latest automation script that transforms the traditionally manual process of creating virtual machines in Proxmox into a streamlined, intelligent workflow.
The Challenge: Manual VM Creation at Scale
Anyone who has managed multiple VMs in Proxmox knows the drill: logging into the web interface, clicking through various configuration screens, setting up networking, configuring cloud-init, and hoping you didn't miss a critical setting. When you're managing dozens or even hundreds of VMs, this process becomes not just tedious, but error-prone.
We needed a solution that could:
Eliminate repetitive manual tasks
Ensure consistent VM configurations
Support both Debian and Ubuntu deployments
Provide intelligent resource allocation
Integrate cloud-init for automated provisioning
Track and manage our infrastructure efficiently
The Solution: Smart Automation with Choice
Our bash-based automation script brings together several powerful features that make VM deployment both fast and flexible.
Intelligent Resource Management
The script automatically manages critical resources behind the scenes, ensuring no conflicts occur when deploying multiple VMs. It maintains a centralized tracking system that monitors resource allocation across your entire infrastructure, preventing the common headaches that come with manual deployments.
Flexible CPU Configuration
One of the standout features is the intelligent CPU type selection. Rather than forcing a one-size-fits-all approach, the script offers three carefully chosen options:
Option 1: x86-64-v3 (Recommended for Modern AMD Processors) This is our recommended default, especially for AMD Ryzen 7950X processors. It enables advanced instruction sets including AVX and AVX2, providing excellent performance while maintaining compatibility for live migration scenarios. This strikes the perfect balance between performance and flexibility.
Option 2: Host CPU Passthrough For workloads that demand absolute maximum performance and where live migration isn't a priority, host passthrough gives your VM access to every CPU feature available on the physical hardware. This is ideal for high-performance computing tasks, specialized workloads, or development environments where you need access to specific CPU instructions.
Option 3: x86-64-v2-AES (Basic Compatibility) This option provides broad compatibility without advanced vector extensions. It's perfect for legacy workloads or when you need maximum compatibility across different hardware platforms.
Dual OS Support: Debian and Ubuntu
The script supports both Debian 13 (Trixie) and Ubuntu 24.04 LTS (Noble), automatically downloading and caching the cloud images. Once downloaded, images are stored locally, making subsequent VM deployments lightning-fast.
Debian 13 (Trixie): Perfect for those who prefer Debian's stability-focused approach and longer release cycles.
Ubuntu 24.04 LTS (Noble): Ideal for users who want access to newer packages and Ubuntu's extensive community support.
Cloud-Init Integration: Zero-Touch Configuration
One of the most powerful features is the integrated cloud-init setup. Each VM is automatically configured with:
Secure SSH access using public key authentication
Automatic package updates on first boot
Essential tools pre-installed including curl, wget, jq, htop, vim, git, unzip, and net-tools
Networking fully configured with static IP addressing
Service auto-start ensuring SSH is enabled and running
This means your VMs are production-ready the moment they boot. No manual configuration required.
Tagging System for Organization
The script includes optional VM tagging, allowing you to organize your infrastructure logically. Tags like production, webserver, database, or client-projectname make it easy to:
Filter VMs in the Proxmox interface
Create automation rules based on tags
Generate reports and track resources by category
Implement tag-based backup policies
The Deployment Workflow
Here's how the entire process works in practice:
1. Resource Selection
When you launch the script, you're first presented with resource management options. You can either let the system automatically assign the next available resources, or manually select from the available pool. This flexibility is crucial when you need to deploy VMs in specific network segments or have particular infrastructure requirements.
The script displays all available resources across your infrastructure, organized by subnet and showing current allocation status. This transparency ensures you always know what's available before making deployment decisions.
2. VM Configuration
Next, you specify your VM parameters:
VMID: 100
Name: webserver-prod-01
Cores: 8
Memory: 16384 MB
Disk: 100G
CPU Type: x86-64-v3
Tags: production,webserver,nginx
The script validates your VMID to ensure it's not already in use, preventing deployment conflicts.
3. Operating System Selection
Choose between Debian 13 or Ubuntu 24.04. The script automatically downloads the appropriate cloud image if it's not already cached locally.
4. Automated Deployment
Once you confirm your configuration, the script:
Creates the VM with your specified resources
Imports and configures the cloud image as the boot disk
Attaches a cloud-init configuration drive
Configures networking with your allocated resources
Resizes the disk to your specified size
Generates a custom cloud-init configuration file
Applies your tags
Updates resource tracking
Starts the VM
The entire process typically completes in under a minute.
5. Immediate Access
As soon as deployment completes, you get a clean summary:
=========================================
✅ VM 100 (webserver-prod-01) created successfully!
=========================================
SSH connection: ssh root@[VM_IP_ADDRESS]
Gateway: [GATEWAY_IP]
Tags: production,webserver,nginx
Use your private key to authenticate.
You can immediately SSH into your new VM and begin working. All packages are updated, all services are running, and the system is fully configured.
Real-World Benefits
We've been using this automation in production for managing our wholesale textile business infrastructure, and the results have been transformative:
Time Savings
What used to take 15-20 minutes per VM now takes less than 2 minutes, including the time to decide on configuration parameters. When you're deploying multiple VMs, this adds up quickly.
Consistency
Every VM deployed through this script has the same base configuration, security settings, and package set. This consistency makes troubleshooting easier and reduces configuration drift across your infrastructure.
Reduced Errors
Manual VM creation inevitably leads to mistakes: typos in IP addresses, forgotten package installations, misconfigured networking. Automation eliminates these human errors.
Better Documentation
The script itself serves as documentation of your VM deployment standards. New team members can understand your infrastructure setup by reading the script, and they can deploy VMs correctly from day one.
Resource Visibility
The integrated tracking system provides instant visibility into resource allocation across your entire infrastructure. You always know what's in use, what's available, and where you can deploy next.
Advanced Features for Power Users
Custom Cloud-Init Configurations
While the script provides sensible defaults, you can easily customize the cloud-init configuration for specific use cases. The generated cloud-init file is stored at /var/lib/vz/snippets/user-data-[VMID].yml, making it easy to modify before or after deployment.
Batch Deployment
Need to deploy multiple identical VMs? The script can be easily adapted to loop through a configuration file, deploying entire environments with a single command.
Integration with Configuration Management
The cloud-init setup makes these VMs perfect for integration with Ansible, Puppet, Chef, or Salt. You can include your configuration management bootstrap commands in the cloud-init script, creating fully autonomous deployments.
Best Practices We've Learned
Through extensive use of this automation, we've developed several best practices:
1. Use Descriptive VM Names
Instead of generic names like "vm-100" or "test-server," use descriptive names that indicate purpose and environment: webserver-prod-01, database-staging-02, api-dev-03. This makes management much easier as your infrastructure grows.
2. Tag Consistently
Develop a tagging standard early and stick to it. We use tags for:
Environment (production, staging, development)
Purpose (webserver, database, application)
Project or client name
Backup requirements (daily, weekly, monthly)
3. Document Your Subnet Strategy
Keep clear documentation of which subnets are used for which purposes. This helps prevent confusion when deploying new VMs.
4. Regular Resource Audits
Periodically review your resource allocation. Decommission unused VMs promptly to free up resources for new deployments.
5. Maintain Your Cloud Images
Keep your cached Debian and Ubuntu images updated. While the script downloads the latest images automatically, periodically clearing old cache files ensures you're always working with recent releases.
Security Considerations
The script includes several security-focused features:
SSH Key Authentication Only
Password authentication is not configured. All access requires your private SSH key, significantly reducing the attack surface.
Automatic Security Updates
Cloud-init is configured to update all packages on first boot, ensuring your VMs start with the latest security patches.
Minimal Package Set
Only essential packages are installed by default. This reduces the attack surface and makes security auditing easier.
Network Isolation
Each VM is deployed with its own network configuration, and you can leverage Proxmox's built-in firewall capabilities for additional security.
Future Enhancements
We're continuously improving this automation. Some planned enhancements include:
Storage backend selection: Choose between local storage, Ceph, NFS, or other Proxmox storage options
Multiple network interface support: For VMs that need connections to multiple networks
VLAN configuration: Automated VLAN tagging for network segmentation
Backup policy automation: Automatically configure Proxmox backup jobs based on VM tags
Monitoring integration: Automatic registration with monitoring systems like Prometheus or Zabbix
Template support: Create and deploy from custom VM templates for specialized workloads
Conclusion
Infrastructure automation doesn't have to be complex. This script proves that with thoughtful design and attention to common use cases, you can create powerful automation that's both flexible and easy to use.
Whether you're managing a handful of VMs or hundreds, automation like this pays dividends in time saved, errors prevented, and consistency maintained. The initial time investment in creating the script has been repaid many times over in our daily operations.
For businesses running on Proxmox, especially those in e-commerce, wholesale, or service industries like ours, having reliable, fast VM deployment is crucial for maintaining agility and responding to changing infrastructure needs.
The script handles the tedious details, tracks resources intelligently, and ensures every deployment follows best practices. This frees your team to focus on what really matters: building and running the applications that drive your business.
#!/bin/bash
set -e
# ============================================================================
# Proxmox VM Creation Script with Intelligent Resource Management
# ============================================================================
# This script automates the creation of VMs in Proxmox with:
# - Automatic IP address management and tracking
# - Cloud-init integration for zero-touch configuration
# - Support for Debian 13 and Ubuntu 24.04 LTS
# - Flexible CPU configuration options
# - VM tagging for organization
# - SSH key-based authentication
# - Created By Sohaib R. Khan
# SETUP REQUIRED:
# 1. Edit the initialize_ip_pool() function below to add YOUR IP addresses
# 2. Update SUBNET_GATEWAYS with YOUR gateway addresses
# 3. Replace the SSH public key with YOUR public key (two locations)
# 4. Ensure jq is installed: apt-get install jq
# ============================================================================
# IP Management Configuration
IP_POOL_FILE="/root/vm-ip-pool.json"
# ============================================================================
# CONFIGURATION SECTION - EDIT THIS FOR YOUR NETWORK
# ============================================================================
# Define your subnet gateway addresses
# Format: SUBNET_GATEWAYS["first.three.octets"]="gateway.ip.address"
# Example: SUBNET_GATEWAYS["192.168.1"]="192.168.1.1"
declare -A SUBNET_GATEWAYS
SUBNET_GATEWAYS["YOUR.SUBNET.1"]="YOUR.GATEWAY.1"
SUBNET_GATEWAYS["YOUR.SUBNET.2"]="YOUR.GATEWAY.2"
# Network configuration - adjust for your subnet size
NETMASK="255.255.255.248" # /29 subnet
CIDR_SUFFIX="29" # CIDR notation
# ============================================================================
# IP POOL INITIALIZATION - EDIT THIS TO ADD YOUR IP ADDRESSES
# ============================================================================
initialize_ip_pool() {
if [ ! -f "$IP_POOL_FILE" ]; then
echo "Initializing IP pool with all available IPs from your subnets..."
cat > "$IP_POOL_FILE" << 'EOF'
{
"ips": {
"YOUR.IP.ADDRESS.1": {"status": "used", "vmid": "existing", "vmname": "ExistingVM1", "gateway": "YOUR.GATEWAY.1"},
"YOUR.IP.ADDRESS.2": {"status": "used", "vmid": "existing", "vmname": "ExistingVM2", "gateway": "YOUR.GATEWAY.1"},
"YOUR.IP.ADDRESS.3": {"status": "free", "vmid": null, "vmname": null, "gateway": "YOUR.GATEWAY.1"},
"YOUR.IP.ADDRESS.4": {"status": "free", "vmid": null, "vmname": null, "gateway": "YOUR.GATEWAY.1"},
"YOUR.IP.ADDRESS.5": {"status": "free", "vmid": null, "vmname": null, "gateway": "YOUR.GATEWAY.1"},
"YOUR.IP.ADDRESS.6": {"status": "used", "vmid": "existing", "vmname": "ExistingVM3", "gateway": "YOUR.GATEWAY.2"},
"YOUR.IP.ADDRESS.7": {"status": "free", "vmid": null, "vmname": null, "gateway": "YOUR.GATEWAY.2"},
"YOUR.IP.ADDRESS.8": {"status": "free", "vmid": null, "vmname": null, "gateway": "YOUR.GATEWAY.2"},
"YOUR.IP.ADDRESS.9": {"status": "free", "vmid": null, "vmname": null, "gateway": "YOUR.GATEWAY.2"},
"YOUR.IP.ADDRESS.10": {"status": "free", "vmid": null, "vmname": null, "gateway": "YOUR.GATEWAY.2"}
}
}
EOF
echo ""
echo "⚠️ IMPORTANT: IP pool initialized with PLACEHOLDER addresses!"
echo "⚠️ Edit $IP_POOL_FILE and replace with your actual IP addresses"
echo "⚠️ Each IP should have: status (used/free), vmid, vmname, and gateway"
echo ""
read -p "Press Enter after you've updated the IP pool file..."
fi
}
# ============================================================================
# IP MANAGEMENT FUNCTIONS
# ============================================================================
get_available_ip() {
initialize_ip_pool
local free_ip=$(jq -r '.ips | to_entries[] | select(.value.status == "free") | .key' "$IP_POOL_FILE" | head -n 1)
if [ -z "$free_ip" ]; then
echo ""
else
echo "$free_ip"
fi
}
get_ip_gateway() {
local ip=$1
jq -r --arg ip "$ip" '.ips[$ip].gateway' "$IP_POOL_FILE"
}
mark_ip_used() {
local ip=$1
local vmid=$2
local vmname=$3
local gateway=$4
jq --arg ip "$ip" --arg vmid "$vmid" --arg vmname "$vmname" --arg gateway "$gateway" \
'.ips[$ip] = {"status": "used", "vmid": $vmid, "vmname": $vmname, "gateway": $gateway}' \
"$IP_POOL_FILE" > "${IP_POOL_FILE}.tmp" && mv "${IP_POOL_FILE}.tmp" "$IP_POOL_FILE"
}
mark_ip_free() {
local ip=$1
local gateway=$(get_ip_gateway "$ip")
jq --arg ip "$ip" --arg gateway "$gateway" \
'.ips[$ip] = {"status": "free", "vmid": null, "vmname": null, "gateway": $gateway}' \
"$IP_POOL_FILE" > "${IP_POOL_FILE}.tmp" && mv "${IP_POOL_FILE}.tmp" "$IP_POOL_FILE"
}
show_ip_status() {
initialize_ip_pool
echo ""
echo "=== IP Pool Status (All Subnets) ==="
echo ""
# Get unique subnet prefixes
local subnets=$(jq -r '.ips | keys[]' "$IP_POOL_FILE" | cut -d'.' -f1-3 | sort -u)
for subnet in $subnets; do
local gateway=$(jq -r --arg subnet "$subnet" '.ips | to_entries[] | select(.key | startswith($subnet)) | .value.gateway' "$IP_POOL_FILE" | head -n 1)
echo "Subnet ${subnet}.x (Gateway: $gateway):"
jq -r --arg subnet "$subnet" '.ips | to_entries[] | select(.key | startswith($subnet)) | "\(.key) - \(.value.status | ascii_upcase) \(if .value.status == "used" then "- VM \(.value.vmid) (\(.value.vmname))" else "" end)"' "$IP_POOL_FILE"
echo ""
done
local total_free=$(jq '[.ips[] | select(.status == "free")] | length' "$IP_POOL_FILE")
local total_used=$(jq '[.ips[] | select(.status == "used")] | length' "$IP_POOL_FILE")
echo "Summary: $total_free free, $total_used used"
echo "======================================"
echo ""
}
list_available_ips() {
initialize_ip_pool
echo ""
echo "=== Available IPs ==="
local count=1
while IFS= read -r ip; do
local gateway=$(jq -r --arg ip "$ip" '.ips[$ip].gateway' "$IP_POOL_FILE")
echo "$count) $ip (Gateway: $gateway)"
((count++))
done < <(jq -r '.ips | to_entries[] | select(.value.status == "free") | .key' "$IP_POOL_FILE" | sort)
echo "====================="
echo ""
}
# ============================================================================
# MAIN SCRIPT
# ============================================================================
# Create directory for OS images
mkdir -p /root/qcow
# Show current IP allocation status
show_ip_status
# IP Assignment Selection
echo "IP Assignment Options:"
echo "1) Auto-assign next available IP"
echo "2) Select IP from available pool"
read -p "Enter choice [1-2]: " IP_CHOICE
if [ "$IP_CHOICE" -eq 2 ]; then
list_available_ips
read -p "Enter the IP address you want to use: " SELECTED_IP
# Validate IP exists and is free
IP_STATUS=$(jq -r --arg ip "$SELECTED_IP" '.ips[$ip].status // "notfound"' "$IP_POOL_FILE")
if [ "$IP_STATUS" == "notfound" ]; then
echo "❌ ERROR: IP $SELECTED_IP not found in pool"
exit 1
elif [ "$IP_STATUS" == "used" ]; then
echo "❌ ERROR: IP $SELECTED_IP is already in use"
exit 1
fi
AVAILABLE_IP="$SELECTED_IP"
else
AVAILABLE_IP=$(get_available_ip)
fi
# Check if IP is available
if [ -z "$AVAILABLE_IP" ]; then
echo "❌ ERROR: No available IPs in the pool!"
echo ""
echo "All IPs are currently assigned. Please:"
echo "1. Order more IP addresses from your provider"
echo "2. Release unused VMs to free up IPs"
echo "3. Update the IP pool file: $IP_POOL_FILE"
echo ""
echo "Current IP assignments:"
show_ip_status
exit 1
fi
GATEWAY=$(get_ip_gateway "$AVAILABLE_IP")
echo "✅ Assigned IP: $AVAILABLE_IP/$CIDR_SUFFIX"
echo "✅ Gateway: $GATEWAY"
echo ""
# VMID validation
while true; do
read -p "Enter VMID (numeric only, e.g., 100, 101, 102): " VMID
if [[ "$VMID" =~ ^[0-9]+$ ]]; then
# Check if VMID already exists
if qm status $VMID &>/dev/null; then
echo "❌ ERROR: VMID $VMID already exists. Please choose a different VMID."
else
break
fi
else
echo "❌ ERROR: VMID must be numeric only (e.g., 100, 101, 102)"
fi
done
# VM Configuration
read -p "Enter number of CPU cores: " CORES
read -p "Enter memory in MB: " MEMORY
read -p "Enter disk size (e.g., 32G, 50G, 100G): " DISKSIZE
read -p "Enter VM name: " VMNAME
# CPU Type Selection
echo ""
echo "CPU Type Options:"
echo "1) x86-64-v3 (AVX, AVX2, best for modern AMD/Intel - RECOMMENDED)"
echo "2) host (All CPU features, best performance, no live migration)"
echo "3) x86-64-v2-AES (Basic, no AVX)"
read -p "Enter CPU type choice [1-3, default: 1]: " CPU_TYPE_CHOICE
CPU_TYPE_CHOICE=${CPU_TYPE_CHOICE:-1}
case $CPU_TYPE_CHOICE in
1)
CPU_TYPE="x86-64-v3"
echo "✅ Selected: x86-64-v3 (with AVX and AVX2 support)"
;;
2)
CPU_TYPE="host"
echo "✅ Selected: host (full CPU passthrough)"
;;
3)
CPU_TYPE="x86-64-v2-AES"
echo "✅ Selected: x86-64-v2-AES (basic)"
;;
*)
CPU_TYPE="x86-64-v3"
echo "✅ Default: x86-64-v3 (with AVX and AVX2 support)"
;;
esac
# VM Tags (optional)
echo ""
echo "Enter Proxmox tags (optional, comma-separated, e.g., production,webserver,client-abc):"
read -p "Tags: " TAGS
# Configuration Summary
echo ""
echo "=== VM Configuration Summary ==="
echo "VMID: $VMID"
echo "Name: $VMNAME"
echo "Cores: $CORES"
echo "Memory: $MEMORY MB"
echo "Disk: $DISKSIZE"
echo "CPU Type: $CPU_TYPE"
echo "IP: $AVAILABLE_IP/$CIDR_SUFFIX"
echo "Gateway: $GATEWAY"
if [ -n "$TAGS" ]; then
echo "Tags: $TAGS"
fi
echo "==============================="
read -p "Press Enter to continue or Ctrl+C to cancel..."
IPADDR="$AVAILABLE_IP/$CIDR_SUFFIX"
DNS="8.8.8.8"
# OS Selection
echo "Select OS:"
echo "1) Debian 13 (Trixie)"
echo "2) Ubuntu 24.04 LTS (Noble)"
read -p "Enter choice [1-2]: " OSCHOICE
if [ "$OSCHOICE" -eq 1 ]; then
OSIMG="https://cdimage.debian.org/images/cloud/trixie/latest/debian-13-generic-amd64.qcow2"
OSNAME="debian-13-generic-amd64.qcow2"
elif [ "$OSCHOICE" -eq 2 ]; then
OSIMG="https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img"
OSNAME="ubuntu-noble-cloudimg-amd64.qcow2"
else
echo "Invalid choice. Exiting."
exit 1
fi
# Download OS image if not cached
if [ ! -f "/root/qcow/$OSNAME" ]; then
echo "Downloading $OSNAME..."
wget -q --show-progress "$OSIMG" -O "/root/qcow/$OSNAME"
fi
# Create VM
echo "Creating VM $VMID..."
qm create $VMID \
--name "$VMNAME" \
--cpu $CPU_TYPE \
--cores $CORES \
--memory $MEMORY \
--net0 virtio,bridge=vmbr0 \
--scsihw virtio-scsi-pci \
--ostype l26
# Add tags if specified
if [ -n "$TAGS" ]; then
echo "Adding tags: $TAGS"
qm set $VMID --tags "$TAGS"
fi
# Import OS disk
echo "Importing OS image disk..."
IMPORT_OUTPUT=$(qm importdisk $VMID "/root/qcow/$OSNAME" local)
echo "$IMPORT_OUTPUT"
DISK_PATH=$(echo "$IMPORT_OUTPUT" | grep -o "local:$VMID/vm-$VMID-disk-[0-9]*\.[a-z]*")
if [ -z "$DISK_PATH" ]; then
echo "Error: Failed to extract disk path from import output"
echo "Import output was: $IMPORT_OUTPUT"
exit 1
fi
echo "Imported disk path: $DISK_PATH"
# Attach disk
echo "Attaching imported disk..."
qm set $VMID --scsi0 "$DISK_PATH"
# Add cloud-init drive
echo "Adding cloud-init drive..."
qm set $VMID --ide2 local:cloudinit
# Set boot order
qm set $VMID --boot order=scsi0
# ============================================================================
# CONFIGURE CLOUD-INIT - REPLACE SSH KEY WITH YOUR PUBLIC KEY
# ============================================================================
echo "Configuring Cloud-Init..."
qm set $VMID \
--ciuser root \
--sshkeys <(echo "YOUR_SSH_PUBLIC_KEY_HERE") \
--ipconfig0 "ip=$IPADDR,gw=$GATEWAY" \
--nameserver "$DNS" \
--cicustom "user=local:snippets/user-data-$VMID.yml"
# Create cloud-init user-data file
mkdir -p /var/lib/vz/snippets
cat > "/var/lib/vz/snippets/user-data-$VMID.yml" << 'EOF'
#cloud-config
users:
- name: root
ssh_authorized_keys:
- YOUR_SSH_PUBLIC_KEY_HERE
package_update: true
package_upgrade: true
packages:
- curl
- wget
- jq
- htop
- vim
- git
- unzip
- net-tools
runcmd:
- echo "Package installation completed" > /var/log/cloud-init-packages.log
- systemctl enable ssh
- systemctl start ssh
final_message: "VM setup completed successfully with all packages installed!"
EOF
echo "Created cloud-init user-data file at /var/lib/vz/snippets/user-data-$VMID.yml"
# Resize disk
echo "Resizing disk to use full $DISKSIZE..."
qm resize $VMID scsi0 $DISKSIZE
# Mark IP as used in pool
mark_ip_used "$AVAILABLE_IP" "$VMID" "$VMNAME" "$GATEWAY"
echo "✅ IP $AVAILABLE_IP marked as used for VM $VMID"
# Start VM
echo "Starting VM $VMID..."
qm start $VMID
# Success message
echo ""
echo "========================================="
echo "✅ VM $VMID ($VMNAME) created successfully!"
echo "========================================="
echo "SSH connection: ssh root@$AVAILABLE_IP"
echo "Gateway: $GATEWAY"
echo "Subnet: $(echo $AVAILABLE_IP | cut -d'.' -f1-3).x"
if [ -n "$TAGS" ]; then
echo "Tags: $TAGS"
fi
echo "Use your private key to authenticate."
echo ""
# Show updated IP status
show_ip_statusGetting Started
The beauty of this automation is its simplicity. It's a single bash script with no external dependencies beyond what's already on your Proxmox server. You can start using it immediately and customize it to fit your specific needs.
If you're still creating VMs manually in Proxmox, I encourage you to explore automation. The time you'll save and the consistency you'll gain make it an investment that pays off from the very first deployment.
Enjoyed this article?
Show your appreciation with a clap
You might also like
View allComments (0)
No comments yet. Be the first to comment!



