208 lines
No EOL
6.5 KiB
Bash
208 lines
No EOL
6.5 KiB
Bash
#!/bin/bash
|
|
|
|
# Exit immediately if a command exits with a non-zero status.
|
|
set -e
|
|
|
|
# Function to check for required utilities
|
|
function check_utilities() {
|
|
local utilities=("qm" "wget" "xz" "sha256sum" "ssh-keygen")
|
|
for util in "${utilities[@]}"; do
|
|
command -v "$util" >/dev/null 2>&1 || { echo "$util not found. Please install it."; exit 1; }
|
|
done
|
|
}
|
|
|
|
# Function to set up SSH keys
|
|
function setup_ssh_keys() {
|
|
local default_ssh_key_dir="${HOME}/ssh-keys"
|
|
local ssh_key_dir="$default_ssh_key_dir"
|
|
|
|
while true; do
|
|
# Ensure the SSH key directory exists
|
|
if [[ ! -d "${ssh_key_dir}" ]]; then
|
|
echo "SSH key directory not found at ${ssh_key_dir}. Creating directory..."
|
|
mkdir -p "${ssh_key_dir}"
|
|
chmod 700 "${ssh_key_dir}"
|
|
fi
|
|
|
|
# Determine the SSH public key file
|
|
ssh_keyfile=$(ls "${ssh_key_dir}"/*.pub 2>/dev/null | head -n 1)
|
|
|
|
if [[ -z "${ssh_keyfile}" ]]; then
|
|
echo "No SSH public key found in ${ssh_key_dir}."
|
|
read -p "Do you want to generate a new SSH key pair in this directory? (yes/no): " generate_key
|
|
if [[ "${generate_key}" == "yes" ]]; then
|
|
ssh-keygen -t rsa -b 4096 -f "${ssh_key_dir}/id_rsa" -N ""
|
|
ssh_keyfile="${ssh_key_dir}/id_rsa.pub"
|
|
chmod 600 "${ssh_key_dir}/id_rsa"
|
|
chmod 644 "${ssh_key_dir}/id_rsa.pub"
|
|
echo "SSH key pair generated at ${ssh_key_dir}/id_rsa and ${ssh_keyfile}."
|
|
break
|
|
else
|
|
read -p "Do you want to specify a different directory for your SSH keys? (yes/no): " change_dir
|
|
if [[ "${change_dir}" == "yes" ]]; then
|
|
read -p "Please enter the full path to your SSH key directory: " ssh_key_dir
|
|
else
|
|
echo "Cannot proceed without an SSH public key. Exiting."
|
|
exit 1
|
|
fi
|
|
fi
|
|
else
|
|
echo "Using existing SSH public key: ${ssh_keyfile}"
|
|
break
|
|
fi
|
|
done
|
|
|
|
chmod 700 "${ssh_key_dir}"
|
|
chmod 600 "${ssh_key_dir}"/id_* 2>/dev/null || true
|
|
chmod 644 "${ssh_key_dir}"/*.pub 2>/dev/null || true
|
|
}
|
|
|
|
# Function to generate cloud-init user data with CloudPanel installation
|
|
function generate_cloud_init_config() {
|
|
local vm_id="$1"
|
|
cat > "vm-${vm_id}-cloud-init.yaml" << 'EOF'
|
|
#cloud-config
|
|
package_update: true
|
|
package_upgrade: true
|
|
packages:
|
|
- curl
|
|
- wget
|
|
- sudo
|
|
- apt-transport-https
|
|
- ca-certificates
|
|
|
|
runcmd:
|
|
- curl -sS https://installer.cloudpanel.io/ce/v2/install.sh -o /root/install.sh
|
|
- echo "a3ba69a8102345127b4ae0e28cfe89daca675cbc63cd39225133cdd2fa02ad36 /root/install.sh" | sha256sum -c
|
|
- DB_ENGINE=MARIADB_11.4 bash /root/install.sh
|
|
|
|
power_state:
|
|
mode: reboot
|
|
timeout: 1800
|
|
condition: True
|
|
EOF
|
|
|
|
# Import the cloud-init config
|
|
qm set "${vm_id}" --cicustom "user=local:snippets/vm-${vm_id}-cloud-init.yaml"
|
|
}
|
|
|
|
# Function to create or update a template
|
|
function create_template() {
|
|
local vm_id="$1"
|
|
local vm_name="$2"
|
|
local image_file="$3"
|
|
|
|
echo "Processing template ${vm_name} (${vm_id})"
|
|
|
|
# Compute the checksum of the image file
|
|
local image_checksum
|
|
image_checksum=$(sha256sum "${image_file}" | awk '{print $1}')
|
|
local checksum_file="checksums/${vm_id}.sha256"
|
|
|
|
# Check if template exists and handle accordingly
|
|
if qm status "${vm_id}" &>/dev/null; then
|
|
echo "Template with VM ID ${vm_id} already exists. Removing..."
|
|
qm destroy "${vm_id}" --destroy-unreferenced-disks yes
|
|
fi
|
|
|
|
echo "Creating template ${vm_name} (${vm_id})"
|
|
|
|
# Create new VM
|
|
qm create "${vm_id}" --name "${vm_name}" --ostype l26
|
|
|
|
# Set networking to default bridge
|
|
qm set "${vm_id}" --net0 virtio,bridge=vmbr0
|
|
|
|
# Set display to serial
|
|
qm set "${vm_id}" --serial0 socket --vga serial0
|
|
|
|
# Set memory and CPU (increased for CloudPanel requirements)
|
|
qm set "${vm_id}" --memory 2048 --cores 2 --cpu host
|
|
|
|
# Import the disk
|
|
qm set "${vm_id}" --scsi0 "${storage}:0,import-from=${PWD}/${image_file},discard=on"
|
|
|
|
# Set SCSI hardware as default boot disk
|
|
qm set "${vm_id}" --boot order=scsi0 --scsihw virtio-scsi-single
|
|
|
|
# Enable QEMU guest agent
|
|
qm set "${vm_id}" --agent enabled=1,fstrim_cloned_disks=1
|
|
|
|
# Add cloud-init device
|
|
qm set "${vm_id}" --ide2 "${storage}:cloudinit"
|
|
|
|
# Set cloud-init network configuration
|
|
qm set "${vm_id}" --ipconfig0 "ip=dhcp,ip6=auto"
|
|
|
|
# Import the SSH keyfile
|
|
if [[ -f "${ssh_keyfile}" ]]; then
|
|
qm set "${vm_id}" --sshkeys "${ssh_keyfile}"
|
|
else
|
|
echo "SSH key file not found at ${ssh_keyfile}"
|
|
exit 1
|
|
fi
|
|
|
|
# Add the user
|
|
qm set "${vm_id}" --ciuser "${username}"
|
|
|
|
# Generate and apply cloud-init config with CloudPanel installation
|
|
generate_cloud_init_config "${vm_id}"
|
|
|
|
# Resize the disk to 25G for CloudPanel requirements
|
|
qm disk resize "${vm_id}" scsi0 25G
|
|
|
|
# Convert the VM into a template
|
|
qm template "${vm_id}"
|
|
|
|
# Save the checksum
|
|
mkdir -p checksums
|
|
echo "${image_checksum}" > "${checksum_file}"
|
|
|
|
# Remove the image file when done
|
|
rm -f "${image_file}"
|
|
}
|
|
|
|
# Check for required utilities
|
|
check_utilities
|
|
|
|
# User-configurable variables
|
|
export username="hackiri" # Replace with your desired username
|
|
export storage="ceph_local" # Replace with your Proxmox storage name
|
|
|
|
# Validate variables
|
|
if [[ -z "${username}" || "${username}" == "your_username_here" ]]; then
|
|
echo "Please set a valid username in the script."
|
|
exit 1
|
|
fi
|
|
|
|
if ! pvesm status | grep -q "^${storage}\s"; then
|
|
echo "Storage '${storage}' not found. Please check your Proxmox storage configuration."
|
|
exit 1
|
|
fi
|
|
|
|
# Set up SSH keys
|
|
setup_ssh_keys
|
|
|
|
# CloudPanel works best with Ubuntu 24.04 (Lunar Lobster)
|
|
declare -a images=(
|
|
# Ubuntu 22.04 LTS (Jammy Jellyfish) with CloudPanel
|
|
"912|ubuntu-24.04-template|https://cloud-images.ubuntu.com/releases/24.04/release/ubuntu-24.04-server-cloudimg-amd64.img"
|
|
)
|
|
|
|
# Loop through the images array
|
|
for entry in "${images[@]}"; do
|
|
IFS='|' read -r vm_id vm_name image_url <<< "${entry}"
|
|
|
|
# Extract the filename from the URL
|
|
image_file="${image_url##*/}"
|
|
|
|
# Download the image with timestamping
|
|
echo "Downloading ${image_file}..."
|
|
if ! wget -N "${image_url}"; then
|
|
echo "Failed to download ${image_url}"
|
|
exit 1
|
|
fi
|
|
|
|
# Create or update the template
|
|
create_template "${vm_id}" "${vm_name}" "${image_file}"
|
|
done |