#!/usr/bin/env bash set -euo pipefail ### ====== SETTINGS (edit if needed) ====== VMID="${VMID:-9013}" NAME="${NAME:-debian-13-cloud}" STORAGE="${STORAGE:-local-lvm}" # e.g. local-lvm or local BRIDGE="${BRIDGE:-vmbr0}" CORES="${CORES:-2}" MEMORY="${MEMORY:-2048}" # MB DISK_SIZE="${DISK_SIZE:-40G}" # final disk size CIUSER="${CIUSER:-debian}" # Where to download image IMG_DIR="${IMG_DIR:-/var/lib/vz/template/iso}" IMG_URL="${IMG_URL:-https://cloud.debian.org/images/cloud/trixie/latest/debian-13-genericcloud-amd64.qcow2}" IMG_FILE="${IMG_FILE:-debian-13-genericcloud-amd64.qcow2}" # SSH public key source (prefer authorized_keys on Proxmox host) SSHKEY_SRC="${SSHKEY_SRC:-/root/.ssh/authorized_keys}" TMP_PUBKEY="/tmp/${NAME}-${VMID}-sshkey.pub" ### ======================================= need_cmd() { command -v "$1" >/dev/null 2>&1 || { echo "ERROR: missing command: $1"; exit 1; }; } need_cmd qm need_cmd wget need_cmd awk need_cmd sed echo "==> Checking SSH key source: $SSHKEY_SRC" if [[ ! -f "$SSHKEY_SRC" ]]; then echo "ERROR: $SSHKEY_SRC not found." echo "Fix: put your public key into /root/.ssh/authorized_keys or set SSHKEY_SRC=/path/to/key.pub" exit 1 fi # Take first valid ssh key line (ssh-rsa / ssh-ed25519 / ecdsa) awk '/^(ssh-rsa|ssh-ed25519|ecdsa-sha2-nistp256) /{print; exit}' "$SSHKEY_SRC" > "$TMP_PUBKEY" || true if [[ ! -s "$TMP_PUBKEY" ]]; then echo "ERROR: No SSH public key found in $SSHKEY_SRC" exit 1 fi echo "==> Downloading Debian 13 cloud image (if missing)" mkdir -p "$IMG_DIR" if [[ ! -f "$IMG_DIR/$IMG_FILE" ]]; then wget -O "$IMG_DIR/$IMG_FILE" "$IMG_URL" else echo " Image already exists: $IMG_DIR/$IMG_FILE" fi echo "==> Creating VM $VMID ($NAME)" # If VM exists, abort to avoid overwriting if qm status "$VMID" >/dev/null 2>&1; then echo "ERROR: VMID $VMID already exists. Choose another VMID (export VMID=xxxx)." exit 1 fi qm create "$VMID" \ --name "$NAME" \ --memory "$MEMORY" \ --cores "$CORES" \ --net0 "virtio,bridge=${BRIDGE}" echo "==> Importing disk into storage: $STORAGE" qm importdisk "$VMID" "$IMG_DIR/$IMG_FILE" "$STORAGE" echo "==> Attaching disk + enabling cloud-init" qm set "$VMID" --scsihw virtio-scsi-pci # Most storages name the imported disk as vm--disk-0 # Attach it as scsi0: qm set "$VMID" --scsi0 "${STORAGE}:vm-${VMID}-disk-0" # Cloud-init drive: qm set "$VMID" --ide2 "${STORAGE}:cloudinit" echo "==> Boot + console + QEMU agent" qm set "$VMID" --boot order=scsi0 qm set "$VMID" --serial0 socket --vga serial0 qm set "$VMID" --agent enabled=1 echo "==> Cloud-init parameters (user/ssh/network)" qm set "$VMID" --ciuser "$CIUSER" qm set "$VMID" --sshkeys "$TMP_PUBKEY" qm set "$VMID" --ipconfig0 ip=dhcp echo "==> Resizing disk to $DISK_SIZE" qm resize "$VMID" scsi0 "$DISK_SIZE" echo "==> Converting VM to template" qm template "$VMID" echo "✅ DONE: Debian 13 template created" echo " VMID: $VMID" echo " Name: $NAME" echo " Storage: $STORAGE" echo " Next: qm clone $VMID --name debian13-vps --full"