This article describes how to set up a VirtualBox server in Debian 9 (Stretch):
- Installing VirtualBox
- VirtualBox web interface: phpVirtualBox
- Set up and use VMs
- Automatically start PhpVirtualBox on boot
- Automatically pause VMs on reboot/shutdown and resume them on boot
- Set up a backup system
If this article has helped you please let me know by clicking some of the ads on this page. If you’re really euphoric there’s a donation button on the right ;) Thanks!
– Debian 9.3 (Stretch)
– VirtualBox 5.2
– phpVirtualBox 5.0.5
You have an up-to-date Debian 9 server with a working internet connection.
Create a file /etc/apt/sources.list.d/virtualbox.list and add:
deb http://download.virtualbox.org/virtualbox/debian stretch contrib
Check here which key you need (opens in a new tab). At the time of writing this is oracle_vbox_2016.asc. Download and install the key so apt doesn’t complain when using the source:
wget https://www.virtualbox.org/download/oracle_vbox_2016.asc -O- | apt-key add -
# aptitude update
Check which version of VirtualBox is current:
root@vorkian:/etc/apt/sources.list.d# aptitude search virtualbox v virtualbox - p virtualbox-5.0 - Oracle VM VirtualBox p virtualbox-5.1 - Oracle VM VirtualBox p virtualbox-5.2 - Oracle VM VirtualBox
Unless you have a reason to install an older version, install the most current:
# aptitude install VirtualBox-5.2
During installation VirtualBox will inform you it needs some more bits:
This system is currently not set up to build kernel modules. Please install the Linux kernel "header" files matching the current kernel for adding new hardware support to the system. The distribution packages containing the headers are probably: linux-headers-amd64 linux-headers-4.9.0-3-amd64 This system is currently not set up to build kernel modules. Please install the Linux kernel "header" files matching the current kernel for adding new hardware support to the system. The distribution packages containing the headers are probably: linux-headers-amd64 linux-headers-4.9.0-3-amd64 There were problems setting up VirtualBox. To re-start the set-up process, run /sbin/vboxconfig
Let’s install them:
# aptitude install linux-headers-amd64 linux-headers-4.9.0-3-amd64
Check the recommendation (“The distribution packages containing the headers are probably:” etc.) for the actual packages you need to install.
Rerun the VirtualBox configuration, as instructed:
Check here what url you should use for the latest extension pack.
# wget https://download.virtualbox.org/virtualbox/5.2.6/Oracle_VM_VirtualBox_Extension_Pack-5.2.6-120293.vbox-extpack
Install the extension pack:
# VBoxManage extpack install Oracle_VM_VirtualBox_Extension_Pack-5.2.6-120293.vbox-extpack
Set up an account for VirtualBox so it doesn’t run as root. If you have multiple users with their own VMs that’s ok too.
# useradd -d /home/vbox -m -g vboxusers -s /bin/bash vbox # passwd vbox
Remember the password, you’ll need it later on.
VirtualBox web interface: phpVirtualBox
Tell the system which user the web service will run as. In /etc/default/virtualbox add:
Start the vboxweb service as the dedicated user:
# sudo -u vbox vboxwebsrv --background
Install webserver and dependencies
# aptitude install apache2 php php-soap php-xml unzip
Note: it would go too far to talk about web server security here. You will understand that it is important for internet facing (and any other) servers to have decent security. If you’re building an internet facing production server you must implement supplemental security, otherwise you will find your servers compromised.
# cd /var/www/html # wget http://sourceforge.net/projects/phpvirtualbox/files/latest/download -O phpvirtualbox.zip # unzip phpvirtualbox.zip
If you can’t unzip phpvirtualbox.zip try different SourceForge mirrors. The German ones tend to work well for me.
Rename the folder for easier typing:
# mv phpvirtualbox-5.0-5/ phpvirtualbox
Change into the phpVirtualBox folder and copy the initial config file:
# cd /var/www/html/phpvirtualbox/ # cp config.php-example config.php
Open up the config file and add the vboxweb service credentials. In /var/www/html/phpvirtualbox/config.php change:
var $username = 'vbox'; var $password = 'P@55w0rd';
…Using the password you entered for the vbox user earlier.
Point your browser to http://yourserver/phpvirtualbox (use your own server name or IP address). The default credentials are admin/admin.
Optional: work around a version notification
At the time of writing phpVirtualBox and VirtualBox itself are not at the same version. PhpVirtualBox will complain about this but we can work around it. Note that this verion incongruity may result in unexpected behaviour and it’s best to keep an eye out for new versions.
In /var/www/html/phpvirtualbox/endpoints/lib/config.php change:
or the current version if later than 5.2.
For the wsdl file create a symlink with the same name:
ln -s /var/www/html/phpvirtualbox/endpoints/lib/vboxwebService-5.0.wsdl /var/www/html/phpvirtualbox/endpoints/lib/vboxwebService-5.2.wsdl
This will stop the version complaints. It should work immediately; no need to restart anything.
Set up and use VMs
Use the VirtualBox web interface to set up a virtual machine like you would with the GUI version.
Once you start it you can connect to it using an RDP session to your server’s host name or IP address on the port defined in the VM’s settings, 9000 by default.
My Debian VirtualBox server has IP address 172.21.135.36. On my Windows 10 box I connect to my Kubuntu VM with:
Note that you are not connecting to the VM’s address. You are connecting to the server’s address.
Automatically start PhpVirtualBox on boot
Since we’re running VirtualBox with a dedicated user we need to tell VirtualBox web service to use that account: in /etc/systemd/system/multi-user.target.wants/vboxweb-service.service, under the [Service] part, add the following:
The whole file should look like this:
[Unit] SourcePath=/usr/lib/virtualbox/vboxweb-service.sh Description= Before=runlevel2.target runlevel3.target runlevel4.target runlevel5.target shutdown.target After=vboxdrv.service Conflicts=shutdown.target [Service] User=vbox Group=vboxusers Type=forking Restart=no TimeoutSec=5min IgnoreSIGPIPE=no KillMode=process GuessMainPID=no RemainAfterExit=yes ExecStart=/usr/lib/virtualbox/vboxweb-service.sh start ExecStop=/usr/lib/virtualbox/vboxweb-service.sh stop [Install] WantedBy=multi-user.target
Reboot the server and verify PhpVirtualBox is started afterwards or just do
# systemctl daemon-reload
for good measure.
Automatically pause VMs on reboot/shutdown and resume them on boot
I would like my VMs to be automatically paused (‘status=saved’ in VirtualBox’s verbage) when I reboot or shutdown my server. It would also be nice if the VMs in question were automatically resumed when the server is back up. We can do that within Systemd.
We’ll create two scripts: one to pause VMs and one to restart them. Then call them from a Systemd unit. Note that you need to save the pause and restart scripts in a location where the vbox user can reach and execute them. From the unit file we’ll need the vbox user to execute them.
Which VMs do we pause? The ones that are running and the ones that are paused because paused VMs’ states wouldn’t survive a reboot. Which VMs do we resume? Just the ones that were running, not the ones that were paused, because we want the new overall state to resemble the old one as closely as possible (i.e. we do not want paused VMs to be suddenly running, so it’s better to keep them saved than running).
#!/bin/bash # Pause running VMs STATUSFILE=/home/vbox/vm-status # Clear the previous status file if it exists if [ -e $STATUSFILE ]; then rm $STATUSFILE; fi # List all VMs for VM in $(vboxmanage list vms | rev | cut -d' ' -f1 | rev) do # Get VM state STATE=$(vboxmanage showvminfo $VM --machinereadable | grep "VMState=" | cut -d'=' -f2) # Pause if state is running or paused, write to status file if [[ $STATE == \"running\" || $STATE == \"paused\" ]]; then vboxmanage controlvm $VM savestate # No need to restart paused vm's; just let them remain saved. if [[ $STATE == \"running\" ]]; then echo "$VM">>$STATUSFILE; fi fi done
#!/bin/bash # Restart VMs saved earlier STATUSFILE=/home/vbox/vm-status # If no status file exists then apparently there are no VMs to resume. if [ ! -f $STATUSFILE ]; then exit; fi while read VM; do vboxmanage startvm $VM --type headless done <$STATUSFILE
Make the scripts accessible to the vbox user and executable:
# cd /home/vbox # chown vbox pausevms.sh resumevms.sh # chmod +x pausevms.sh resumevms.sh
Create a unit file /etc/systemd/system/virtualmachines.service:
[Unit] Description=Save VirtualBox VMs before shutdown or reboot; resume them after boot. Wants=multi-user.target After=multi-user.target [Service] Type=oneshot RemainAfterExit=yes ExecStart=/usr/bin/sudo -u vbox /home/vbox/resumevms.sh ExecStop=/usr/bin/sudo -u vbox /home/vbox/pausevms.sh [Install] WantedBy=multi-user.target
Enable the new daemon:
# systemctl daemon-reload # systemctl enable virtualmachines.service
…But be aware that if you run it now it will put any running VMs in the saved status. So I recommend you stop/save any running VMs at this point, reboot your server, start one or more VMs, reboot and then check if they came back up. Check /var/log/syslog for troubleshooting hints if it doesn’t work.
The lines containing ‘multi-user.target’ make the script wait after boot until the multi-user.target is reached, which among other things contains the VirtualBox web service. It also makes the script wait on reboot/shutdown until all necessary VMs are saved before shutting down VirtualBox itself and rebooting/shutting down.
I tested this whole contraption on a virtual machine containing virtual machines. On one test run PhpVirtualBox wouldn’t start (but the VMs would) but upon reboot it did. Most of the time it would just work smoothly. Taking into consideration the VM-in-a-VM setup I am quite satisfied with this system.
Set up a backup system
This backup script is taken and adapted from this page (opens in a new tab), which also contains commentary and explanations.
I’ve put this in /home/vbox/backupvms.sh.
#!/bin/bash # Loop through all VirtualBox VMs, pause, export, # and restore them to their original states. # # Vorkbaard, 2012-02-01, 2018-02-09 # =============== Set your variables here =============== EXPORTDIR=/var/vmbackup LOGFILE=/home/vbox/export.log MYMAIL=root VBOXMANAGE="/usr/bin/VBoxManage -q" # ======================================================= # Generate a list of all VMs for VM in $(vboxmanage list vms | rev | cut -d' ' -f1 | rev) do ERR="nothing" SECONDS=0 # Get VM's friendly name FRIENDLYNAME=$(vboxmanage showvminfo --machinereadable $VM | grep "name=" | cut -d'"' -f2) # Delete old $LOGFILE file if it exists if [ -e $LOGFILE ]; then rm $LOGFILE; fi # Get the vm state VMSTATE=$(vboxmanage showvminfo $VM --machinereadable | grep "VMState=" | cut -f 2 -d "=") echo "$VM's state is: $VMSTATE." # If the VM's state is running or paused, save its state if [[ $VMSTATE == \"running\" || $VMSTATE == \"paused\" ]]; then vboxmanage controlvm $VM savestate if [ $? -ne 0 ]; then ERR="saving the state"; fi fi # Export the vm as appliance if [ "$ERR" == "nothing" ]; then vboxmanage export $VM --output $EXPORTDIR/$VM-new.ova &> $LOGFILE if [ $? -ne 0 ]; then ERR="exporting" else # Remove old backup and rename new one if [ -e $EXPORTDIR/$VM.ova ]; then rm $EXPORTDIR/$VM.ova; fi mv $EXPORTDIR/$VM-new.ova $EXPORTDIR/$VM.ova # Get file size FILESIZE=$(du -h $EXPORTDIR/$VM.ova | cut -f 1) fi else echo "Not exporting because the VM's state couldn't be saved." &> $LOGFILE fi # Resume the VM to its previous state if that state was paused or running if [[ $VMSTATE == \"running\" || $VMSTATE == \"paused\" ]]; then vboxmanage startvm $VM --type headless if [ $? -ne 0 ]; then ERR="resuming"; fi if [ $VMSTATE == \"paused\" ]; then vboxmanage controlvm $VM pause if [ $? -ne 0 ]; then ERR="pausing"; fi fi fi # Calculate duration duration=$SECONDS duration="Operation took $(($duration / 60)) minutes, $(($duration % 60)) seconds." # Notify the admin if [ "$ERR" == "nothing" ]; then MAILBODY="Virtual Machine $FRIENDLYNAME was exported succesfully!" MAILBODY="$MAILBODY"$'\n'"$duration" MAILBODY="$MAILBODY"$'\n'"Export filesize: $FILESIZE" MAILSUBJECT="VM $VM succesfully backed up" else MAILBODY="There was an error $ERR VM $VM." if [ "$ERR" == "exporting" ]; then MAILBODY=$(echo $MAILBODY && cat $LOGFILE) fi MAILSUBJECT="Error exporting VM $VM" fi # Send the mail echo "$MAILBODY" | mail -s "$MAILSUBJECT" $MYMAIL # Clean up if [ -e $LOGFILE ]; then rm $LOGFILE; fi done
Chown the script to the vbox user and make it executable:
# chown vbox /home/vbox/backupvms.sh # chmod +x /home/vbox/backupvms.sh
Then schedule it using cron or just run it whenever you like.
If you want the mail part to work configure mail or mailx for your system. Otherwise it’ll just send mail to local addresses. You can also use ssmtp if you don’t want to set up EXIM or Postfix; ssmtp is easy to set up and is used mainly for systems that just need to be able to send the occasional outgoing mail.
If you have any questions not related to PhpVirtualBox or VirtualBox itself (they are not my projects) feel free to ask them in the comment section below.
If you found this article helpful please click some of the ads on my page to help me pay for hosting this site, or consider donating any amount using the PayPal donation button on the top right of this page. Thanks :)
- Different versions of VirtualBox and the extension pack may lead to unexpected behavious and weird errors.
- Mouse or keyboard not working in RDP session may be caused by lack of video memory (<128MB) in the VM.
- Check /var/log/syslog for messages regarding VirtualBox and PhpVirtualBox.
- Unable to install certain packages: perhaps new versions have been published. Stop copying and pasting commands from this site and start actually reading what your server is telling you.
- Unable to unzip phpvirtualbox.zip: download from a different server. Try the German ones.
- PhpVirtualBox’s default username and password are both ‘admin’.
Thanks a lot my friend :)
This is a good tutorial.
Thanks, great tutorial!
Hi, and thanks for this tutorial. I have a question: Does the exported vm retains it’s (saved) state? I tried to restore one of the backups and the machine started offline, not in a saved state.
I thought it would but its easy to test: just perform the export and restore manually.
Great big thanks.
Pingback: Debian 9 安装 VirtualBOX和phpvirtualbox | 免费资源,低价vps,服务器配置,vps建站,免费空间贝壳主机网
Hi. Great script I used for two years already.
Recently I needed to restore the backed up copy and to my horror discovered that restoration fails with “file corrupted” message. It appears that the copy (13GB) was recorded with some error.
To my great luck I had one more copy (a bit older, but what can I do…) – so I restored the system.
But now I added the following to my (actually your) script:
vboxmanage export $VMNAME –output $EXPORTDIR/$VMNAME-new.ova &>>export.log
while [ true ] ; do
vboxmanage export $VMNAME –output $EXPORTDIR/$VMNAME-new.ova &>> export.log
if [ $? -ne 0 ]; then
cp stamdat $EXPORTDIR/$VMNAME-new1.ova &>> export.log
vboxmanage export $VMNAME –output $EXPORTDIR/$VMNAME-new1.ova &>> export.log
if [ $? -ne 0 ]; then
cmp $EXPORTDIR/$VMNAME-new.ova $EXPORTDIR/$VMNAME-new1.ova
if [ $? -ne 0 ]; then
echo “Copies not equal!” &>>export.log
mv $EXPORTDIR/$VMNAME-new1.ova $EXPORTDIR/$VMNAME-new.ova
and corresponding call to export() instead of straight “vboxmanage export”
It appears that you renewed the script and introduced some very nice changes.
So, I decided to write this to you – may be you would like to incorporate this change too?
Sorry, I see that the site eliminates formatting and the text is hardly readable.
In two word: I make the “vboxmanage export” twice, compare the copies and if not equal – remove the first and continue this till they will BE equal.
Thanks again! :-)
That’s a great idea! It doubles your backup time but this setup it not targeted for corporate use; personally I used it to back up my PfSense router in the middle of the night.
I’ll just let your comment remain here – if I’m going to integrate it in the article I would like to test it first and I haven’t the time for that. I am sure this will come in handy for other readers.
OK, the situation is worse.
Each run of “vboxmanage export” produces different results, thus files/backups are not compatible (cmp always fails).
OK, finally, this works.
What I did is:
– export VM locally on the disk
– copy it twice to backup media
– compare remote copies and copy again if needed
This works even better than the previous version, because making local export takes significantly less time than remote export. This locks out the VM for significantly less time.
The new version is at:
Google Drive content not there, again.
Can you upload it again?
ok i would like some help i installed debian 9 from a netstat disk saved on a usb stick you see I want the debian server to have as littlw as possible installed so if you do not mind please what is the lightest possible server and what lines should be in my sources file BEFORE I start instaaling virtualbox. sorry if this question is somewhat off topic.
Hi, thank you for this guide.
I have a problem. When I restart the server it stops the VM but it does not create a Statusfile. and because missing the status file it cant restart the vm after reboot. i tried also to change the statusfile directory but the same problem i dont know what i did wrong….
i dont use PhpVirtualBox so i skiped this part.
Hi Kapitein Vorkbaard.
I posted a tutorial for Installing Debian 10, Openmediavault 5, Virtualbox 6 and PHPVirtualbox on the Openmediavault Forum where I used and altered version of your Backup Script for Virtualbox VM’s.
I Modified it a bit. I have a machine that needs a reboot after exporting. When the machine recovers from Saved State the USB port doesn’t work anymore. An ACPI shutdown and start solved the problem.
Offcouse I made a reference to your website to indicate that you are the original writer of the script. If you do mind please let me know, i will remove the script from the Forum.