Skip to content

Instantly share code, notes, and snippets.

@stigtsp
Last active February 16, 2025 11:26
Show Gist options
  • Save stigtsp/1cb604a5f91bf62226680cf930b0135d to your computer and use it in GitHub Desktop.
Save stigtsp/1cb604a5f91bf62226680cf930b0135d to your computer and use it in GitHub Desktop.
#!/usr/bin/env bash
# Opinionated Ubuntu 24.04 template generator for Proxmox
# - Enables SecureBoot
# - Sets a default firewall allowing ping and ssh
# - Sets up servers on vlan 22
# - Uses local-lvm for storage
#
# Copy this script to /root on your proxmox server, and run with ./proxmox-template-ubuntu-24.04.bash
#
# Stuff taken from:
# https://github.com/UntouchedWagons/Ubuntu-CloudInit-Docs
# https://forum.proxmox.com/threads/combining-custom-cloud-init-with-auto-generated.59008/page-3#post-428772
set -euo pipefail
VM_TEMPLATE_NAME="ubuntu-2404-template"
VM_IMAGE_URL=https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img
VM_IMAGE_RESIZE=32G
VM_ID=8244
VM_CORES=2
VM_MEM=2048
VM_VLAN=22
VM_IMAGE_FN=$(basename "$VM_IMAGE_URL")
VM_IMAGE_URL_BASE=$(dirname "$VM_IMAGE_URL")
VM_IMAGE_CHECKSUMS_URL=$VM_IMAGE_URL_BASE/SHA256SUMS
echo "Checking if ID $VM_ID already exists"
if qm show $VM_ID; then
echo "ERROR: A VM or template with ID $VM_ID already exists"
exit 2
else
echo "OK: We can use ID $VM_ID, lets continue"
fi
if [ -f "$VM_IMAGE_FN" ]; then
echo "OK: $VM_IMAGE_FN already downloaded"
else
TDIR=$(mktemp -d)
echo "Downloading SHA256 checksums from $VM_IMAGE_CHECKSUMS_URL"
curl --fail $VM_IMAGE_CHECKSUMS_URL | grep "*$VM_IMAGE_FN" > $TDIR/SHA256SUMS
echo "Downloading $VM_IMAGE_FN from $VM_IMAGE_URL"
curl --fail -o $TDIR/$VM_IMAGE_FN $VM_IMAGE_URL
echo "Checking that $VM_IMAGE_FN matches checksum"
(cd $TDIR && sha256sum -c SHA256SUMS)
mv -v $TDIR/$VM_IMAGE_FN $VM_IMAGE_FN
echo "Resizing $VM_IMAGE_FN to $VM_IMAGE_RESIZE"
qemu-img resize $VM_IMAGE_FN $VM_IMAGE_RESIZE
fi
VM_TEMPLATE_SNIPPET=/var/lib/vz/snippets/$VM_TEMPLATE_NAME.yaml
if [ -f "$VM_TEMPLATE_SNIPPET" ]; then
echo "$VM_TEMPLATE_SNIPPET already exists"
else
echo "Generating runcmd script $VM_TEMPLATE_SNIPPET"
mkdir -p /var/lib/vz/snippets
cat << EOF | tee $VM_TEMPLATE_SNIPPET
#cloud-config
package_reboot_if_required: true
package_update: true
package_upgrade: true
packages:
- qemu-guest-agent
runcmd:
- systemctl start qemu-guest-agent
EOF
fi
qm create $VM_ID --name "$VM_TEMPLATE_NAME" --ostype l26 \
--memory $VM_MEM \
--agent 1 \
--bios ovmf --machine q35 --efidisk0 local-lvm:0,efitype=4m,pre-enrolled-keys=1 \
--cpu host --socket 1 --cores $VM_CORES \
--vga serial0 --serial0 socket \
--net0 virtio,bridge=vmbr0,tag=$VM_VLAN,firewall=1
qm importdisk $VM_ID $VM_IMAGE_FN local-lvm
qm set $VM_ID --scsihw virtio-scsi-pci --virtio0 local-lvm:vm-$VM_ID-disk-1,discard=on,iothread=on
qm set $VM_ID --boot order=virtio0
qm set $VM_ID --ide2 local-lvm:cloudinit
qm set $VM_ID --tpmstate0 file=local-lvm:0,size=4M,version=v2.0
cat << EOF | tee /etc/pve/firewall/$VM_ID.fw
[OPTIONS]
enable: 1
policy_in: DROP
policy_out: ACCEPT
[RULES]
IN SSH(ACCEPT)
IN Ping(ACCEPT)
EOF
qm set $VM_ID --cicustom "vendor=local:snippets/$VM_TEMPLATE_NAME.yaml"
qm set $VM_ID --ciuser root
qm set $VM_ID --sshkeys ~/.ssh/authorized_keys
qm set $VM_ID --ipconfig0 ip=dhcp
qm template $VM_ID
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment