This is a set of script to automatically deploy some of the components via KVM/virsh
Tested on Fedora 42
This is a set of script to automatically deploy some of the components via KVM/virsh
Tested on Fedora 42
| echo "deleting $1" | |
| virsh undefine $1 && virsh undefine $1 --nvram --remove-all-storage |
| #!/bin/bash | |
| RNAME=$1 | |
| echo "Executing QR Magic on $RNAME" | |
| SEC=$(date +%s) | |
| HUMAN=1 | |
| virsh send-key --domain $RNAME KEY_ENTER | |
| sleep $HUMAN | |
| virsh send-key --domain $RNAME KEY_ENTER | |
| sleep $(($HUMAN*2)) | |
| virsh screenshot $RNAME --file qr.png && zbarimg qr.png | grep otpauth > authcode-$RNAME-$SEC.txt | |
| TOTPCODE=$(python3 -c "import oathtool;print(oathtool.generate_otp('$(cat authcode-$RNAME-$SEC.txt | cut -f2 -d=)'))") | |
| sleep $HUMAN | |
| virsh send-key --domain $RNAME KEY_ESC | |
| sleep $HUMAN | |
| echo "Sending $TOTPCODE" | |
| for (( i=0; i<${#TOTPCODE}; i++ )); do | |
| virsh send-key --domain $RNAME --codeset linux --holdtime 500 KEY_LEFTSHIFT "KEY_${TOTPCODE:$i:1}" | |
| sleep $HUMAN | |
| done | |
| sleep $(($HUMAN*2)) | |
| virsh send-key --domain $RNAME KEY_ENTER |
sudo dnf install zbar-libs zbar
mkdir -p oathtool && curl -o oathtool/__init__.py https://raw.githubusercontent.com/jaraco/oathtool/refs/heads/main/oathtool/__init__.py
sh qrmagic.sh $RNAME
| #!/bin/sh | |
| #$1 < should be the file that was created earlier eg authcode-<vm>-<utime> | |
| #$2 < should be the name of the vm, eg repo002 | |
| RNAME=$2 | |
| HUMAN=1 | |
| TOTPCODE=$(python3 -c "import oathtool;print(oathtool.generate_otp('$(cat $1 | cut -f2 -d=)'))") | |
| echo "Sending $TOTPCODE" | |
| for (( i=0; i<${#TOTPCODE}; i++ )); do | |
| virsh send-key --domain $RNAME --codeset linux --holdtime 500 KEY_LEFTSHIFT "KEY_${TOTPCODE:$i:1}" | |
| sleep $HUMAN | |
| done | |
| sleep $(($HUMAN*2)) | |
| virsh send-key --domain $RNAME KEY_ENTER |
First we will set up a bridged network. This is not required and you can skip a lot of the config if you don't do it but this way VBR will be available on the network
Use nmcli to show your current network adapter. Since we will move this adapater, you might want to run all of these commands localy and not over ssh
nmcli connection showsudo nmcli connection add type bridge con-name br0 ifname br0
sudo nmcli connection modify br0 connection.autoconnect yes
sudo nmcli connection add type bridge-slave con-name br0-slave-eth ifname <yournetadapaterfromnmcli> master br0
sudo nmcli connection modify br0-slave-eth connection.autoconnect yes
sudo nmcli connection delete "Wired connection 1"
sudo nmcli connection up br0Now will need to disable complete filtering on the bridge so the VMs get all the traffic
cat <<EOF | sudo tee -a /etc/sysctl.d/99-netfilter-bridge.conf
net.bridge.bridge-nf-call-ip6tables = 0
net.bridge.bridge-nf-call-iptables = 0
net.bridge.bridge-nf-call-arptables = 0
EOFcat <<EOF | sudo tee -a /etc/modules-load.d/br_netfilter.conf
br_netfilter
EOFIf you reboot now, everything should be set, for the bridge but if you don't want to reboot, you can load everything dynamically
sudo modprobe br_netfiltersudo sysctl -p /etc/sysctl.d/99-netfilter-bridge.conf
``
Now we need to allow qemu to use this bridge
```bash
echo "allow br0" | sudo tee -a /etc/qemu/bridge.conf Finally we can define the network at the hypervisor level
cat <<EOF | tee -a bridgenet.xml
<network>
<name>br0</name>
<forward mode="bridge" />
<bridge name="br0" />
</network>
EOF
virsh net-define bridgenet.xml
virsh net-start br0
virsh net-autostart br0Well this is the easy part since we use a tool called virt-v2v. You do need to install it though. Then you can convert the appliance
Notice that I'm importing into the gnome-boxes storage pool. This is the default for Fedora 42 (latest in 09/2025)
sudo yum install virt-v2v -y
virt-v2v -i ova VeeamSoftwareAppliance_13.0.0.4967_20250822.ova -of qcow2\
--os gnome-boxes --bridge br0 --on vbrFedora also doesn't like the "VNC" protocol and there seems no way to change this with virt-v2v. We will just dump the config, remove the vm, update the config and redefine it
virsh dumpxml vbr > vbr.xml
xmllint vbr.xml --shell <<EOF
cd //graphics/@type
set spice
save
bye
EOF
virsh undefine --domain vbr --nvram
virsh define vbr.xml
virsh start vbrIf you now open up gnome boxes, you will see VBR running on your main network
sudo dnf install virt-install -yIf you want the data disk on another drive set (eg /dev/sdb mounted to /mnt/backup)
sudo mkdir /mnt/backup/$USER
sudo chown $USER:$USER /mnt/backup/$USER
mkdir /mnt/backup/$USER/data
virsh pool-define-as dataimages dir - - - - /mnt/backup/$USER/data
virsh pool-build dataimages
virsh pool-autostart dataimages
Download the VeeamSoftwareAppliance iso in /home/$USER/iso. We copy the vbr kickstart to modify it and update it on the fly
This just changes the timezone and the keyboard but of course you could also inject the network settings
ISOPATH=/home/$USER/iso
cd $ISOPATH
mkdir tmp
sudo mount VeeamSoftwareAppliance*.iso tmp
cat tmp/vbr-ks.cfg > vbr-ks-mod.cfg
sed -i 's/keyboard.*/keyboard --xlayouts='"'"be"'"'/' vbr-ks-mod.cfg
sed -i 's/^timezone.*/timezone Europe\/Brussels --utc/' vbr-ks-mod.cfg
sed -i 's/^timesource .*$/timesource --ntp-server time.cloudflare.com --nts/g' vbr-ks-mod.cfg
Let's check how the default vbr installation boots and copy of some of it statements
cat $ISOPATH/tmp/EFI/BOOT/grub.cfg | grep "Backup &" -A 4
submenu 'Veeam Backup & Replication' {
menuentry 'Install - fresh install, wipes everything (including local backups)' --class fedora --class gnu-linux --class gnu --class os {
linuxefi /images/pxeboot/vmlinuz inst.stage2=hd:LABEL=Rocky-9-2-x86_64 inst.ks=hd:LABEL=Rocky-9-2-x86_64:/vbr-ks.cfg quiet
initrdefi /images/pxeboot/initrd.img
}
R setup allows you to use the command over and over again to reinstall. --location is required to inject our modified kickstart script and pass the initrd parameters
virsh send-key $RNAME KEY_ENTER, sends a the enter key to confirm that we want to erase all the data on our clean discs. 60 secs might be a bit high but 30 secs is too low. Depends on your hardware.
R=$(($R+1))
RNAME=$(printf "vbr%03d" $R)
virt-install \
-n $RNAME \
--description "$(printf 'Veeam Backup & Replication VBR vbr%03d' $R)" \
--graphics=spice \
--boot=uefi \
--os-variant=rocky9 \
--ram=4096 \
--vcpus=4 \
--disk pool=dataimages,bus=virtio,size=240 \
--disk pool=dataimages,bus=virtio,size=250 \
--location $(ls $ISOPATH/VeeamSoftwareAppliance*.iso) \
--initrd-inject=$ISOPATH/vbr-ks-mod.cfg \
--extra-args="inst.stage2=hd:LABEL=Rocky-9-2-x86_64 inst.ks=file:/vbr-ks-mod.cfg quiet" \
--network network=br0 \
--noautoconsole && sleep 60 && virsh send-key $RNAME KEY_ENTER
echo "waiting";while [ -z "$(virsh domstate $RNAME | grep off)" ];do echo -n ".";sleep 3;done
virsh start $RNAME
sleep 10;virt-viewer $RNAME &
sudo dnf install virt-install -yIf you want the data disk on another drive set (eg /dev/sdb mounted to /mnt/backup)
sudo mkdir /mnt/backup/$USER
sudo chown $USER:$USER /mnt/backup/$USER
mkdir /mnt/backup/$USER/data
virsh pool-define-as dataimages dir - - - - /mnt/backup/$USER/data
virsh pool-build dataimages
virsh pool-autostart dataimages
Download the JeOS (infrastructure) iso os in /home/$USER/iso. We copy the hardened repo kickstart to modify it and update it on the fly
This just changes the timezone and the keyboard but of course you could also inject the network settings
ISOPATH=/home/$USER/iso
cd $ISOPATH
mkdir tmp
sudo mount *JeOS*.iso tmp
cat tmp/hardened-repo-ks.cfg > hardened-repo-ks-mod.cfg
sed -i 's/keyboard.*/keyboard --xlayouts='"'"be"'"'/' hardened-repo-ks-mod.cfg
sed -i 's/^timezone.*/timezone Europe\/Brussels --utc/' hardened-repo-ks-mod.cfg
sed -i 's/^timesource .*$/timesource --ntp-server time.cloudflare.com --nts/g' hardened-repo-ks-mod.cfg
Let's check how the default hardened repo boots and copy of some of it statements
cat $ISOPATH/tmp/EFI/BOOT/grub.cfg | grep "Hardened Repo" -A 4
should yield something like
submenu 'Veeam Hardened Repository' {
menuentry 'Install - fresh install, wipes everything (including local backups)' --class fedora --class gnu-linux --class gnu --class os {
linuxefi /images/pxeboot/vmlinuz inst.stage2=hd:LABEL=Rocky-9-2-x86_64 inst.ks=hd:LABEL=Rocky-9-2-x86_64:/hardened-repo-ks.cfg quiet
initrdefi /images/pxeboot/initrd.img
}
R setup allows you to use the command over and over again to reinstall. --location is required to inject our modified kickstart script and pass the initrd parameters
virsh send-key $RNAME KEY_ENTER, sends a the enter key to confirm that we want to erase all the data on our clean discs. 60 secs might be a bit high but 30 secs is too low. Depends on your hardware.
R=$(($R+1))
IPSTART=80
RNAME=$(printf "repo%03d" $R)
SUBN="192.168.0"
NETCONFIG="network --bootproto=static --ip=$SUBN.$(($IPSTART+$R)) --netmask=255.255.255.0 --gateway=$SUBN.1 --nameserver=$SUBN.1 --hostname=$RNAME"
sed -i "s/^network --bootproto=.*$/$NETCONFIG/g" hardened-repo-ks-mod.cfg
virt-install \
-n $RNAME \
--description "$(printf 'Veeam Backup & Replication REPO repo%03d' $R)" \
--graphics=spice \
--boot=uefi \
--os-variant=rocky9 \
--ram=4096 \
--vcpus=4 \
--disk pool=gnome-boxes,bus=virtio,size=120 \
--disk pool=dataimages,bus=virtio,size=150 \
--location $ISOPATH/VeeamJeOS_13.0.0.4967_20250822.iso \
--initrd-inject=$ISOPATH/hardened-repo-ks-mod.cfg \
--extra-args="inst.stage2=hd:LABEL=Rocky-9-2-x86_64 inst.ks=file:/hardened-repo-ks-mod.cfg quiet" \
--network network=br0 \
--noautoconsole && sleep 60;virsh send-key $RNAME KEY_ENTER
while [ -z "$(virsh domstate $RNAME | grep off)" ];do echo "waiting";sleep 10;done
virsh start $RNAME
sleep 10;virt-viewer $RNAME &