-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
[core]: cloud‐init.func
VM cloud-init configuration and first-boot setup module for Proxmox VEs, providing automatic system initialization, network configuration, user account setup, and SSH key management for virtual machines.
- Overview
- Cloud-Init Fundamentals
- Main Configuration Functions
- Interactive Configuration
- Configuration Parameters
- Data Formats
- Best Practices
- Troubleshooting
- Contributing
Cloud-init.func provides VM first-boot automation infrastructure:
- ✅ Cloud-init drive creation (IDE2 or SCSI fallback)
- ✅ User account and password configuration
- ✅ SSH public key injection
- ✅ Network configuration (DHCP or static IP)
- ✅ DNS and search domain setup
- ✅ Interactive whiptail-based configuration
- ✅ Credential file generation and display
- ✅ Support for Debian nocloud and Ubuntu cloud-init
- ✅ System package upgrade on first boot
# In Proxmox VM creation scripts
source <(curl -fsSL .../cloud-init.func)
# Basic setup:
setup_cloud_init "$VMID" "$STORAGE" "$HOSTNAME" "yes"
# Interactive setup:
configure_cloud_init_interactive "root"
setup_cloud_init "$VMID" "$STORAGE" "$HOSTNAME" "$CLOUDINIT_ENABLE"VM Power On
↓
Cloud-init boot phase
↓
Read cloud-init config
↓
Create/modify user account
↓
Install SSH keys
↓
Configure network
↓
Set DNS/search domain
↓
Upgrade packages (if configured)
↓
Boot completion
Cloud-init is a system that runs on the first boot of a VM/Instance to:
- Create user accounts
- Set passwords
- Configure networking
- Install SSH keys
- Run custom scripts
- Manage system configuration
Proxmox VE supports cloud-init natively via:
- Cloud-init drive: IDE2 or SCSI disk with cloud-init data
- QEMU parameters: User, password, SSH keys, IP configuration
- First-boot services: systemd services that execute on first boot
Proxmox uses the nocloud data source (no internet required):
- Configuration stored on local cloud-init drive
- No external network call needed
- Works in isolated networks
- Suitable for private infrastructure
Purpose: Configures Cloud-init for automatic VM first-boot setup.
Signature:
setup_cloud_init()Parameters:
-
$1- VMID (required, e.g., 100) -
$2- Storage name (required, e.g., local, local-lvm) -
$3- Hostname (optional, default: vm-${VMID}) -
$4- Enable Cloud-Init (yes/no, default: no) -
$5- User (optional, default: root) -
$6- Network mode (dhcp/static, default: dhcp) -
$7- Static IP (optional, CIDR format: 192.168.1.100/24) -
$8- Gateway (optional) -
$9- Nameservers (optional, space-separated, default: 1.1.1.1 8.8.8.8)
Returns: 0 on success, 1 on failure; exits if not enabled
Behavior:
# If enable="no":
# Returns immediately (skips all configuration)
# If enable="yes":
# 1. Create cloud-init drive (IDE2, fallback to SCSI1)
# 2. Set user account
# 3. Generate random password
# 4. Configure network
# 5. Set DNS servers
# 6. Add SSH keys (if available)
# 7. Save credentials to file
# 8. Export variables for calling scriptOperations:
| Operation | Command | Purpose |
|---|---|---|
| Create drive | qm set $vmid --ide2 $storage:cloudinit |
Cloud-init data disk |
| Set user | qm set $vmid --ciuser $ciuser |
Initial user |
| Set password | qm set $vmid --cipassword $cipassword |
Auto-generated |
| SSH keys | qm set $vmid --sshkeys $SSH_KEYS_FILE |
Pre-injected |
| DHCP network | qm set $vmid --ipconfig0 ip=dhcp |
Dynamic IP |
| Static network | qm set $vmid --ipconfig0 ip=192.168.1.100/24,gw=192.168.1.1 |
Fixed IP |
| DNS | qm set $vmid --nameserver $servers |
1.1.1.1 8.8.8.8 |
| Search domain | qm set $vmid --searchdomain local |
Local domain |
Environment Variables Set:
-
CLOUDINIT_USER- Username configured -
CLOUDINIT_PASSWORD- Generated password (in memory only) -
CLOUDINIT_CRED_FILE- Path to credentials file
Usage Examples:
# Example 1: Basic DHCP setup
VMID=100
STORAGE="local-lvm"
setup_cloud_init "$VMID" "$STORAGE" "myvm" "yes"
# Result: VM configured with DHCP, random password, root user
# Example 2: Static IP configuration
setup_cloud_init "$VMID" "$STORAGE" "myvm" "yes" "root" \
"static" "192.168.1.100/24" "192.168.1.1" "1.1.1.1 8.8.8.8"
# Result: VM configured with static IP, specific DNS
# Example 3: Disabled (no cloud-init)
setup_cloud_init "$VMID" "$STORAGE" "myvm" "no"
# Result: Function returns immediately, no configurationPurpose: Interactive whiptail-based configuration prompts for user preferences.
Signature:
configure_cloud_init_interactive()Parameters:
-
$1- Default user (optional, default: root)
Returns: 0 on success, 1 if whiptail unavailable; exports configuration variables
Environment Variables Exported:
-
CLOUDINIT_ENABLE- Enable (yes/no) -
CLOUDINIT_USER- Username -
CLOUDINIT_NETWORK_MODE- dhcp or static -
CLOUDINIT_IP- Static IP (if static mode) -
CLOUDINIT_GW- Gateway (if static mode) -
CLOUDINIT_DNS- DNS servers (space-separated)
User Prompts (5 questions):
- Enable Cloud-Init? (yes/no)
- Username? (default: root)
- Network Mode? (DHCP or static)
- Static IP? (if static, CIDR format)
- Gateway IP? (if static)
- DNS Servers? (default: 1.1.1.1 8.8.8.8)
Fallback Behavior:
- If whiptail unavailable: Shows warning and returns 1
- Auto-defaults to DHCP if error occurs
- Non-interactive: Can be skipped in scripts
Implementation Pattern:
configure_cloud_init_interactive() {
local default_user="${1:-root}"
# Check whiptail availability
if ! command -v whiptail >/dev/null 2>&1; then
echo "Warning: whiptail not available"
export CLOUDINIT_ENABLE="no"
return 1
fi
# Ask enable
if ! (whiptail --backtitle "Proxmox VE Helper Scripts" --title "CLOUD-INIT" \
--yesno "Enable Cloud-Init for VM configuration?" 16 68); then
export CLOUDINIT_ENABLE="no"
return 0
fi
export CLOUDINIT_ENABLE="yes"
# Username
CLOUDINIT_USER=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox \
"Cloud-Init Username" 8 58 "$default_user" --title "USERNAME" 3>&1 1>&2 2>&3)
export CLOUDINIT_USER="${CLOUDINIT_USER:-$default_user}"
# Network mode
if (whiptail --backtitle "Proxmox VE Helper Scripts" --title "NETWORK MODE" \
--yesno "Use DHCP for network configuration?" 10 58); then
export CLOUDINIT_NETWORK_MODE="dhcp"
else
export CLOUDINIT_NETWORK_MODE="static"
# ... prompt for static IP and gateway ...
fi
# DNS servers
CLOUDINIT_DNS=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox \
"DNS Servers (space-separated)" 8 58 "1.1.1.1 8.8.8.8" --title "DNS" 3>&1 1>&2 2>&3)
export CLOUDINIT_DNS
}Usage Examples:
# Example 1: Interactive configuration
configure_cloud_init_interactive "root"
# Prompts user for all settings interactively
# Exports variables for use in setup_cloud_init()
# Example 2: With custom default user
configure_cloud_init_interactive "debian"
# Suggests "debian" as default username
# Example 3: In script workflow
configure_cloud_init_interactive "$DEFAULT_USER"
setup_cloud_init "$VMID" "$STORAGE" "$HOSTNAME" "$CLOUDINIT_ENABLE" "$CLOUDINIT_USER"
# User configures interactively, then script sets up VM- Type: Integer (100-2147483647)
- Required: Yes
-
Example:
100 - Validation: Must be unique, >= 100 on Proxmox
- Type: String (storage backend name)
- Required: Yes
-
Examples:
local,local-lvm,ceph-rbd - Validation: Must exist in Proxmox
- Cloud-init Drive: Placed on this storage
- Type: String (valid hostname)
- Required: No (defaults to vm-${VMID})
-
Example:
myvm,web-server-01 - Format: Lowercase, alphanumeric, hyphens allowed
- Type: String (username)
- Required: No (defaults: root)
-
Example:
root,ubuntu,debian - Cloud-init: User account created on first boot
- Type: Enum (dhcp, static)
- Default: dhcp
-
Options:
-
dhcp- Dynamic IP from DHCP server -
static- Manual IP configuration
-
- Format: CIDR notation (192.168.1.100/24)
-
Example:
192.168.1.50/24,10.0.0.5/8 - Validation: Valid IP and netmask
- Required: If network mode = static
- Format: IP address (192.168.1.1)
-
Example:
192.168.1.1,10.0.0.1 - Validation: Valid IP
- Required: If network mode = static
- Format: Space-separated IPs
-
Default:
1.1.1.1 8.8.8.8 -
Example:
1.1.1.1 8.8.8.8 9.9.9.9
- Type: String
-
Default:
local -
Example:
example.com,internal.corp
Generated at: /tmp/${hostname}-${vmid}-cloud-init-credentials.txt
Format:
========================================
Cloud-Init Credentials
========================================
VM ID: 100
Hostname: myvm
Created: Tue Dec 01 10:30:00 UTC 2024
Username: root
Password: s7k9mL2pQ8wX
Network: dhcp
DNS: 1.1.1.1 8.8.8.8
========================================
SSH Access (if keys configured):
ssh root@<vm-ip>
Proxmox UI Configuration:
VM 100 > Cloud-Init > Edit
- User, Password, SSH Keys
- Network (IP Config)
- DNS, Search Domain
========================================
Stored in: /etc/pve/nodes/<node>/qemu-server/<vmid>.conf
Relevant Settings:
ide2: local-lvm:vm-100-cloudinit,media=cdrom
ciuser: root
cipassword: (encrypted)
ipconfig0: ip=dhcp
nameserver: 1.1.1.1 8.8.8.8
searchdomain: local
DHCP:
qm set 100 --ipconfig0 "ip=dhcp"Static IPv4:
qm set 100 --ipconfig0 "ip=192.168.1.100/24,gw=192.168.1.1"Static IPv6:
qm set 100 --ipconfig0 "ip6=2001:db8::100/64,gw6=2001:db8::1"Dual Stack (IPv4 + IPv6):
qm set 100 --ipconfig0 "ip=192.168.1.100/24,gw=192.168.1.1,ip6=2001:db8::100/64,gw6=2001:db8::1"# Ensure SSH keys available before cloud-init setup
CLOUDINIT_SSH_KEYS="/root/.ssh/authorized_keys"
if [ ! -f "$CLOUDINIT_SSH_KEYS" ]; then
mkdir -p /root/.ssh
# Generate or import SSH keys
fi
setup_cloud_init "$VMID" "$STORAGE" "$HOSTNAME" "yes"# After setup_cloud_init():
# Credentials file generated at $CLOUDINIT_CRED_FILE
# Copy to secure location:
cp "$CLOUDINIT_CRED_FILE" "/root/vm-credentials/"
chmod 600 "/root/vm-credentials/$(basename $CLOUDINIT_CRED_FILE)"
# Or display to user:
cat "$CLOUDINIT_CRED_FILE"# DHCP - suitable for dev/test
setup_cloud_init "$VMID" "$STORAGE" "$HOSTNAME" "yes" "root" "dhcp"
# Static - suitable for production
setup_cloud_init "$VMID" "$STORAGE" "$HOSTNAME" "yes" "root" \
"static" "192.168.1.100/24" "192.168.1.1"# Before setting up cloud-init, ensure:
# - Gateway IP is reachable
# - IP address not in use
# - DNS servers are accessible
ping -c 1 "$GATEWAY" || msg_error "Gateway unreachable"# After cloud-init setup:
qm start "$VMID"
# Wait for boot
sleep 10
# Check cloud-init status
qm exec "$VMID" cloud-init status
# Verify network configuration
qm exec "$VMID" hostname -I# Inside VM:
cloud-init status # Show cloud-init status
cloud-init analyze # Analyze cloud-init boot
cloud-init query # Query cloud-init datasource
# Check logs:
tail -100 /var/log/cloud-init-output.log
tail -100 /var/log/cloud-init.log# Verify cloud-init config in Proxmox:
cat /etc/pve/nodes/$(hostname)/qemu-server/100.conf
# Check cloud-init drive:
qm config 100 | grep ide2
# In VM, verify cloud-init wrote config:
cat /etc/netplan/99-cloudinit.yaml# Verify SSH keys set in Proxmox:
qm config 100 | grep sshkeys
# In VM, check SSH directory:
ls -la /root/.ssh/
cat /root/.ssh/authorized_keys# Regenerate cloud-init drive:
qm set 100 --delete ide2 # Remove cloud-init drive
qm set 100 --ide2 local-lvm:vm-100-cloudinit,media=cdrom # Re-create
# Set password again:
qm set 100 --cipassword "newpassword"- Add parameter to
setup_cloud_init()function signature - Add validation for parameter
- Add
qm setcommand to apply configuration - Update documentation with examples
- Test on actual Proxmox VE
- Add new whiptail dialog to
configure_cloud_init_interactive() - Export variable for use in setup
- Add validation logic
- Test with various input scenarios
Beyond nocloud, could support:
- ConfigDrive (cloud-init standard)
- ESXi (if supporting vSphere)
- Hyper-V (if supporting Windows)
- Cloud-init requires QEMU guest agent for optimal functionality
- Network configuration applied on first boot only
- Credentials file contains sensitive information - keep secure
- SSH keys are persisted and not displayed in credentials file
- Cloud-init is optional - VMs work without it