# ============================================================================== # Proxmox SafeSquid Appliance VM Creation Script # ============================================================================== # INSTRUCTIONS: # Simply modify the variables below to match your environment, and run this script # directly in your Proxmox shell. # # ADVANCED NETWORKING: # The script dynamically generates your network config using the WAN/LAN arrays. # If you require advanced features (BGP, Static Routes, Interface Renaming), # download and provide a custom 'network-config.yaml' at the following path: # /var/lib/vz/snippets/network-config.yaml # If that file is detected, the script will automatically bind it and bypass the arrays! # ============================================================================== # --- System & Identity --- VMID=0 # Set to 0 to auto-generate. If an existing ID is used, it auto-generates. VM_NAME="safesquid-appliance" # The Proxmox VM Name AND the Linux OS Hostname DOMAIN="safesquid.network" # Domain name used for FQDN and DNS search domain SSH_KEY="" # Optional: Public SSH Key to inject (e.g., "ssh-rsa AAAA...") # --- Hardware Allocation --- MEMORY=8192 # Recommended: 8192 (8GB), Minimum: 4096 (4GB) CORES=8 # Recommended: 8, Minimum: 4 OS_DISK_SIZE="15G" # SafeSquid base OS requirement DATA_DISK_SIZE="32" # Secondary disk for SafeSquid data (LVM, in GB) NIC_MODEL="virtio" # Network model (virtio, e1000, vmxnet3). VirtIO enables Multiqueue. STORAGE="local" # Proxmox storage target (e.g., local, local-lvm) IMAGE="/var/lib/vz/template/iso/debian-13-genericcloud-amd64.qcow2" # --- Networking (Standard Bridged) --- declare -A WAN declare -A LAN WAN[IP]="10.200.1.161/24" # Use "dhcp" or CIDR format WAN[GW]="10.200.1.1" # Leave empty if using DHCP WAN[BRIDGE]="vmbr3" # Proxmox bridge interface (e.g., vmbr0) LAN[IP]="192.168.100.130/24" # Use "dhcp" or CIDR format LAN[GW]="192.168.100.1" # Leave empty if using DHCP LAN[BRIDGE]="" # Optional: Internal network. Leave empty for single NIC appliance. NAMESERVERS="8.8.8.8 1.1.1.1" # Optional: Space-separated DNS servers # --- Networking (SR-IOV PCI Passthrough) --- # If SRIOV_PCI_WAN is populated, the script bypasses standard bridges and uses PCIe Passthrough! SRIOV_PCI_WAN="" # PCI ID for the WAN Virtual Function (e.g., "03:10.0") SRIOV_PCI_LAN="" # PCI ID for the LAN Virtual Function (e.g., "03:10.1") # 0. Download SafeSquid Cloud-Config and Ensure Debian Image exists echo "Downloading SafeSquid cloud-init payload..." if ! wget -S -O /var/lib/vz/snippets/safesquid-cloud-config.yaml https://downloads.safesquid.com/appliance/safesquid-cloud-config.yaml; then echo "ERROR: Failed to download cloud-config.yaml from SafeSquid repository!" exit 1 fi if [ ! -s "/var/lib/vz/snippets/safesquid-cloud-config.yaml" ]; then echo "ERROR: Downloaded cloud-config.yaml is empty! (Possible 404 error)" exit 1 fi if [ -n "$SSH_KEY" ]; then echo "Injecting custom SSH key into cloud-config..." # Append the SSH key directly to the ssh_authorized_keys array in the downloaded YAML sed -i "/ssh_authorized_keys:/a \ - \"$SSH_KEY\"" /var/lib/vz/snippets/safesquid-cloud-config.yaml fi # Inject Hostname and Domain into cloud-config echo "Configuring Hostname ($VM_NAME) and FQDN ($VM_NAME.$DOMAIN)..." sed -i "s/^hostname:.*/hostname: $VM_NAME/" /var/lib/vz/snippets/safesquid-cloud-config.yaml sed -i "s/^fqdn:.*/fqdn: $VM_NAME.$DOMAIN/" /var/lib/vz/snippets/safesquid-cloud-config.yaml if [ ! -f "$IMAGE" ]; then echo "Image not found! Downloading Debian 13 (Stable) Cloud-Init image to $IMAGE..." wget -O "$IMAGE" https://cloud.debian.org/images/cloud/trixie/latest/debian-13-genericcloud-amd64.qcow2 fi # Determine the final VMID if [ "$VMID" = "0" ] || [ -f "/etc/pve/qemu-server/$VMID.conf" ] || [ -f "/etc/pve/lxc/$VMID.conf" ]; then NEXT_ID=$(pvesh get /cluster/nextid) if [ "$VMID" != "0" ]; then echo "Warning: VMID $VMID already exists! Automatically assigning next available ID: $NEXT_ID" fi VMID=$NEXT_ID fi echo "Creating VM $VMID ($VM_NAME)..." # Extract expected MAC addresses from the downloaded network-config.yaml (if it exists) WAN_MAC="" LAN_MAC="" if [ -f "/var/lib/vz/snippets/network-config.yaml" ]; then echo "Custom network-config.yaml detected. Extracting MAC addresses..." WAN_MAC=$(awk '/wan:/{flag=1} flag && /macaddress:/{print $2; flag=0}' /var/lib/vz/snippets/network-config.yaml | tr -d '"'\''\r') LAN_MAC=$(awk '/lan:/{flag=1} flag && /macaddress:/{print $2; flag=0}' /var/lib/vz/snippets/network-config.yaml | tr -d '"'\''\r') else echo "No custom network-config.yaml found. Falling back to native Proxmox IP configuration." fi # 1. Create the base VM if [ -n "$SRIOV_PCI_WAN" ]; then echo "Configuring VM for SR-IOV (PCI Passthrough)..." # Use q35 machine type for proper PCIe passthrough NETWORK_ARGS="--machine q35 --hostpci0 $SRIOV_PCI_WAN,pcie=1" if [ -n "$SRIOV_PCI_LAN" ]; then NETWORK_ARGS="$NETWORK_ARGS --hostpci1 $SRIOV_PCI_LAN,pcie=1" fi echo "Warning: MAC addresses from network-config.yaml cannot be auto-injected for PCI passthrough devices." else NETWORK_ARGS="--net0 $NIC_MODEL,bridge=${WAN[BRIDGE]}" # Enable Multiqueue only if using VirtIO if [ "$NIC_MODEL" = "virtio" ]; then NETWORK_ARGS="$NETWORK_ARGS,queues=$CORES" fi if [ -n "$WAN_MAC" ]; then echo "Applying WAN MAC address: $WAN_MAC" NETWORK_ARGS="$NETWORK_ARGS,macaddr=$WAN_MAC" fi if [ -n "${LAN[BRIDGE]}" ]; then LAN_ARGS="--net1 $NIC_MODEL,bridge=${LAN[BRIDGE]}" if [ "$NIC_MODEL" = "virtio" ]; then LAN_ARGS="$LAN_ARGS,queues=$CORES" fi if [ -n "$LAN_MAC" ]; then echo "Applying LAN MAC address: $LAN_MAC" LAN_ARGS="$LAN_ARGS,macaddr=$LAN_MAC" fi NETWORK_ARGS="$NETWORK_ARGS $LAN_ARGS" fi fi # Create the base VM and enable the QEMU Guest Agent to prevent AF_VSOCK errors qm create $VMID --name $VM_NAME --memory $MEMORY --core $CORES $NETWORK_ARGS --scsihw virtio-scsi-pci --agent enabled=1 # 2 & 3. Import and attach the Debian Cloud-Init OS disk automatically (Modern PVE 7.2+ syntax) qm set $VMID --scsi0 $STORAGE:0,import-from=$IMAGE # 4. Resize the OS disk (SafeSquid base OS requirement) qm resize $VMID scsi0 $OS_DISK_SIZE # 5. Create and attach the secondary disk for SafeSquid data (scsi1) # The custom cloud-init script will automatically format and LVM-provision this disk! qm set $VMID --scsi1 $STORAGE:$DATA_DISK_SIZE # 6. Configure Network and Bind cloud-init snippets BEFORE attaching the drive if [ -f "/var/lib/vz/snippets/network-config.yaml" ]; then qm set $VMID --cicustom "user=local:snippets/safesquid-cloud-config.yaml,network=local:snippets/network-config.yaml" else IP_STR_WAN="ip=${WAN[IP]}" if [ -n "${WAN[GW]}" ] && [ "${WAN[IP]}" != "dhcp" ]; then IP_STR_WAN="${IP_STR_WAN},gw=${WAN[GW]}" fi qm set $VMID --ipconfig0 $IP_STR_WAN if [ -n "${LAN[BRIDGE]}" ] || [ -n "$SRIOV_PCI_LAN" ]; then IP_STR_LAN="ip=${LAN[IP]}" if [ -n "${LAN[GW]}" ] && [ "${LAN[IP]}" != "dhcp" ]; then IP_STR_LAN="${IP_STR_LAN},gw=${LAN[GW]}" fi qm set $VMID --ipconfig1 $IP_STR_LAN fi if [ -n "$NAMESERVERS" ]; then qm set $VMID --nameserver "$NAMESERVERS" fi if [ -n "$DOMAIN" ]; then qm set $VMID --searchdomain "$DOMAIN" fi qm set $VMID --cicustom "user=local:snippets/safesquid-cloud-config.yaml" fi # 7. Add the Cloud-Init CD-ROM drive (This triggers ISO generation!) qm set $VMID --ide2 $STORAGE:cloudinit # Force a cloud-init update just to be absolutely certain Proxmox flushes the config qm cloudinit update $VMID # 8. Configure boot order (Standard VGA Console) qm set $VMID --boot c --bootdisk scsi0 echo "VM $VMID successfully created! You can now start it with:" echo "qm start $VMID"