#!/bin/bash # create-debian-template.sh # Creates a Debian Trixie Cloud-Init VM template on Proxmox. # # Usage: # ./create-debian-template.sh [STORAGE] [BRIDGE] # # Examples: # ./create-debian-template.sh 9000 debian-trixie-template # ./create-debian-template.sh 9000 debian-trixie-template local-lvm vmbr1 # # Defaults: # STORAGE = local-lvm # BRIDGE = vmbr1 set -euo pipefail VMID="${1:?Usage: $0 [STORAGE] [BRIDGE]}" NAME="${2:?Usage: $0 [STORAGE] [BRIDGE]}" STORAGE="${3:-local-lvm}" BRIDGE="${4:-vmbr1}" IMAGE="debian-13-genericcloud-amd64.qcow2" IMAGE_URL="https://cloud.debian.org/images/cloud/trixie/latest/${IMAGE}" TMPDIR="/tmp" echo "==> Downloading Debian Trixie cloud image..." wget -q --show-progress -O "${TMPDIR}/${IMAGE}" "${IMAGE_URL}" echo "==> Installing libguestfs-tools if needed..." apt-get install -y libguestfs-tools > /dev/null echo "==> Customizing image (installing base tools + Tailscale repo)..." virt-customize -a "${TMPDIR}/${IMAGE}" \ --install qemu-guest-agent,curl,wget,nano,rsync,htop,tmux,emacs-nox,nfs-common \ --run-command 'curl -fsSL https://pkgs.tailscale.com/stable/debian/trixie.noarmor.gpg -o /usr/share/keyrings/tailscale-archive-keyring.gpg' \ --run-command 'echo "deb [signed-by=/usr/share/keyrings/tailscale-archive-keyring.gpg] https://pkgs.tailscale.com/stable/debian trixie main" > /etc/apt/sources.list.d/tailscale.list' \ --run-command 'apt-get update -qq' \ --install tailscale \ --run-command 'mkdir -p /home/samantha/.ssh && echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPJq4fOOrPQKYAq5olwKWAXKGO5zv/rujveyTORxMrDp root@pve" > /home/samantha/.ssh/authorized_keys && chmod 700 /home/samantha/.ssh && chmod 600 /home/samantha/.ssh/authorized_keys' \ --run-command 'chown -R samantha:samantha /home/samantha' \ --run-command 'truncate -s 0 /etc/machine-id' \ --run-command 'rm -f /etc/ssh/ssh_host_*' \ --quiet echo "==> Creating VM ${VMID} (${NAME})..." qm create "${VMID}" \ --name "${NAME}" \ --memory 2048 \ --cores 2 \ --net0 "virtio,bridge=${BRIDGE}" \ --ostype l26 echo "==> Importing disk to ${STORAGE}..." qm importdisk "${VMID}" "${TMPDIR}/${IMAGE}" "${STORAGE}" echo "==> Configuring VM..." qm set "${VMID}" --scsihw virtio-scsi-pci --scsi0 "${STORAGE}:vm-${VMID}-disk-0" qm set "${VMID}" --boot c --bootdisk scsi0 qm set "${VMID}" --ide2 "${STORAGE}:cloudinit" qm set "${VMID}" --vga std qm set "${VMID}" --agent enabled=1 PUBKEY_FILE=$(mktemp) echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPJq4fOOrPQKYAq5olwKWAXKGO5zv/rujveyTORxMrDp root@pve" > "${PUBKEY_FILE}" qm set "${VMID}" --ciuser samantha --cipassword "changeme" --sshkeys "${PUBKEY_FILE}" rm -f "${PUBKEY_FILE}" qm set "${VMID}" --ipconfig0 ip=dhcp echo "==> Converting to template..." qm template "${VMID}" echo "==> Cleaning up..." rm -f "${TMPDIR}/${IMAGE}" echo "" echo "Done. Template ${VMID} (${NAME}) created." echo "Clone with: ./clone-vm.sh ${VMID} [CORES] [MEMORY_MB] [DISK_SIZE]" echo "" echo "After cloning, join the Headscale mesh:" echo " tailscale up --login-server --authkey mkey:..."