14 KiB
Cloud-Init.func Wiki
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.
📋 Table of Contents
- Overview
- Cloud-Init Fundamentals
- Main Configuration Functions
- Interactive Configuration
- Configuration Parameters
- Data Formats
- Best Practices
- Troubleshooting
- Contributing
Overview
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
Integration Pattern
# 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"
First-Boot Sequence
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 Fundamentals
What is Cloud-Init?
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 Cloud-Init Integration
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
Nocloud Data Source
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
Main Configuration Functions
setup_cloud_init()
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 script
Operations:
| 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 configuredCLOUDINIT_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 configuration
configure_cloud_init_interactive()
Purpose: 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- UsernameCLOUDINIT_NETWORK_MODE- dhcp or staticCLOUDINIT_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
Configuration Parameters
VMID (Virtual Machine ID)
- Type: Integer (100-2147483647)
- Required: Yes
- Example:
100 - Validation: Must be unique, >= 100 on Proxmox
Storage
- 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
Hostname
- Type: String (valid hostname)
- Required: No (defaults to vm-${VMID})
- Example:
myvm,web-server-01 - Format: Lowercase, alphanumeric, hyphens allowed
User
- Type: String (username)
- Required: No (defaults: root)
- Example:
root,ubuntu,debian - Cloud-init: User account created on first boot
Network Mode
- Type: Enum (dhcp, static)
- Default: dhcp
- Options:
dhcp- Dynamic IP from DHCP serverstatic- Manual IP configuration
Static IP
- 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
Gateway
- Format: IP address (192.168.1.1)
- Example:
192.168.1.1,10.0.0.1 - Validation: Valid IP
- Required: If network mode = static
Nameservers
- 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
DNS Search Domain
- Type: String
- Default:
local - Example:
example.com,internal.corp
Data Formats
Cloud-Init Credentials File
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
========================================
Proxmox Cloud-Init Config
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
Network Configuration Examples
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"
Best Practices
1. Always Configure SSH Keys
# 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"
2. Save Credentials Securely
# 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"
3. Use Static IPs for Production
# 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"
4. Validate Network Configuration
# 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"
5. Test First Boot
# 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
Troubleshooting
Cloud-Init Not Applying
# 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
Network Not Configured
# 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
SSH Keys Not Installed
# 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
Password Not Set
# 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"
Contributing
Adding New Configuration Options
- 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
Enhancing Interactive Configuration
- Add new whiptail dialog to
configure_cloud_init_interactive() - Export variable for use in setup
- Add validation logic
- Test with various input scenarios
Supporting New Data Sources
Beyond nocloud, could support:
- ConfigDrive (cloud-init standard)
- ESXi (if supporting vSphere)
- Hyper-V (if supporting Windows)
Notes
- 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