
A simple VMWare ESXi Guest Backup Script
The free license option for VMWare ESXi lacks the backup APIs enabled by a vSphere license. Here is a simple script that I use instead to backup my guest VMs on my VMWare ESXi running on a Raspberry Pi 4.
Assumptions
The script assumes:
- All files that make up a VM (disks, machine description, memory, etc) live within a single directory.
- The name of the directory that contains a VM's files matches the VM's name in the hypervisor.
- All of the VMs to be backed-up reside on a single datastore, although the script can be run multiple times to target different datastores
- That a retention schedule is required that automatically purges aged backups
Copy the script to your ESXi Host
Use SSH, WinSCP or similar to create a copy of the script on your host. I have a datastore directory for scripts, so I copied it there.
Make the script executable by running:
chmod +x /path/to/backupScript.sh
or by ticking the X box in WinSCPs file properties context menu.
Configure the script
Using a test editor like Nano, Vi or WinSCP, edit the first section of the script to match your environment and requirements, where:
Variable | Description | Example |
serversToBackup | Is a list of guest VMs to backup delimited by a single space, all enclosed in quotes | "GuestVm1 GuestVm2" |
retentionDays | An integer that describes how many days backups a retained for before being purged | 3 |
sourceFolder | The path to the datastore containing the guest VM folders to backup, all enclosed in quotes | "/vmfs/volumes/ GuestVmDatastore" |
The path to the destination datastore to which backups will be written, all enclosed in quotes | "/vmfs/volumes/ TargetBackupDatastore/ backupDirectory" |
The above example would look like:
serversToBackup="GuestVm1 GuestVm2"
retentionDays=3
sourceFolder="/vmfs/volumes/GuestVmDatastore"
destinationFolder="/vmfs/volumes/TargetBackupDatastore/backupDirectory"
Run the script interactively
At this point, you can invoke the script manually from the command line via SSH by simply running:
/path/to/backupScript.sh
However, it is useful to schedule the script to perform a regular automated backup.
Schedule the script to run automatically
Typically in Unix-like operating systems we could schedule job via the root crontab. Whilst this is true for ESXi, a security feature of the system means the content of the file is not persisted between reboots. We have to use a workaround to rewrite our root crontab on each reboot. To do so, edit:
/etc/rc.local.d/local.sh
and append:
kill $(cat /var/run/crond.pid)
echo '5 0 * * * /vmfs/path/to/backupScript.sh 2>&1' >> /var/spool/cron/crontabs/root
crond
exit 0
This snippet kills the cron service, appends our scheduled job to the crontab, and restarts the cron service. Upon restart, the crontab is reread persisting our scheduled job between reboots.
Restore
To recover from a backup, "Register an existing virtual machine" using ESXi and point the interface to the location of your backup files.
Script code
#!/bin/sh
serversToBackup="GuestVm1 GuestVm2"
retentionDays=3
sourceFolder="/vmfs/volumes/GuestVmDatastore"
destinationFolder="/vmfs/volumes/TargetBackupDatastore"
DATE=$(date +%F)
for SERVER in $serversToBackup;
do
echo "Processing server $SERVER"
mkdir ${destinationFolder}/`echo $SERVER`_`echo $DATE`
cp -rf ${sourceFolder}/`echo $SERVER`/`echo $SERVER`.vmx ${destinationFolder}/`echo $SERVER`_`echo $DATE`/`echo $SERVER`.vmx
cp -rf ${sourceFolder}/`echo $SERVER`/`echo $SERVER`.nvram ${destinationFolder}/`echo $SERVER`_`echo $DATE`/`echo $SERVER`.nvram
cp -rf ${sourceFolder}/`echo $SERVER`/`echo $SERVER`.vmsd ${destinationFolder}/`echo $SERVER`_`echo $DATE`/`echo $SERVER`.vmsd
#get vmid
vmid=$(vim-cmd vmsvc/getallvms | grep $SERVER | awk '{print $1}')
#take snap
vim-cmd vmsvc/snapshot.create $vmid backup 'Snapshot created by Backup Script' 0 0
#get disks
disks=`ls ${sourceFolder}/${SERVER}/*flat.vmdk`
echo $disks
disks=`echo $disks | sed 's/-flat//g'`
echo $disks
#copy snapped disks
for disk in ${disks};
do
targetDisk=`basename ${disk}`
vmkfstools -i \
${disk} \
${destinationFolder}/${SERVER}_${DATE}/${targetDisk} \
-d thin;
done
#delete latest (backup) snap
latestSnap=`vim-cmd vmsvc/snapshot.get $vmid | grep Id | awk '{print $NF}' | tail -1`
vim-cmd vmsvc/snapshot.remove $vmid $latestSnap;
#retention of x days, purge older
find ${destinationFolder}/${SERVER}* -mtime +$retentionDays -exec rm -r {} \;
done
echo "done"