====== How to Setup VirtualBox as a Service in Linux ======
Brendan Kidwell\\
[[brendan@glump.net]]
29 October 2008\\
revised 26 February 2010
I run VirtualBox on my office desktop to provide not only a Windows desktop environment for sticky Windows-requiring apps, but also to provide MS SQL Server for my web development stack of JRun, ColdFusion, and MS SQL Server. As such, it would be useful to have an init script that starts and stops VirtualBox automatically when the host system boots up and shuts down. That way, I don't have to think about manually starting VirtualBox before I can interact with my web development environment, and this is particularly useful if I have to work remotely after calling in to ask my office mate to start my computer.
This guide shows you how to setup a virtual machine hosted by VirtualBox on a Linux host. The guest OS can be anything. The guest will be configured to **start or resume** when the host boots and **suspend** when the host shuts down. The guest can be started and stopped from the command prompt as well. I have only tested this setup on Ubuntu 8.04 and Ubuntu 9.10, but it should work fine on any Linux that uses ''init.d'' scripts to start and stop services.
/* **Warning: My experience over the last couple of days is that these instructions get you part of the way there but I can't get it to actually //resume// the virtual machine reliably during boot time.** (31 Oct 2008) */
**Alternate version available:**\\
[Spanish] [[http://cgacimartin.wordpress.com/2009/01/09/crear-servicio-para-virtualbox/|Crear servicio para VirtualBox]] -- based on this page, by Carlos Gacimartín. Thanks Carlos!
===== Prepare Your VirtualBox Virtual Machine =====
Install [[http://www.virtualbox.org/|VirtualBox]] in the usual way. Create your virtual machine. In particular I recommend these settings, but YMMV:
^ setting ^ value |
| Remote Display → Enable VRDP Server | true |
| Remote Display → Server Port | 3389 |
| Network → Adapter 1 → Attached to | NAT |
The reason I use NAT networking is because I feel it's easier to manage than any other networking. My network admin doesn't see any new mysterious MAC and IP addresses appearing on the network, and I know exactly what ports on the virtual machine are exposed to the outside world. If you prefer, you can use bridged networking instead.
Save your virtual machine, start it (in the GUI) and install your guest OS and VirtualBox Guest Additions. It's important that you install every kind of remote access you'll need, since the virtual machine's screen won't actually reside on your real desktop when you run the virtual machine as a service. I've found that VirtualBox's RDP server has some issues with catching screen updates, so I like to enable Windows' Remote Desktop server and forward it from an alternate port in VirtualBox's NAT.
(Aside: Most people wouldn't think of it for a Windows guest, but I find the [[http://pigtail.net/LRP/printsrv/cygwin-sshd.html|SSH server provided by Cygwin]] quite useful, especially for no-nonsense SFTP file transfers. If you choose to use it, you can copy your **host's** "''/etc/ssh/ssh_host_*''" to your **guest's** Cygwin "''/etc/''" folder and that will prevent SSH clients from complaining about different keys being used on different ports on your host IP address.)
To configure port forwarding in VirtualBox's NAT, follow the instructions in the [[http://www.virtualbox.org/wiki/Downloads|VirtualBox Manual]] at "Virtual Networking" → "Network Address Translation (NAT)" → "Configuring port forwarding with NAT" to setup up some port mappings. Here are examples from **my** setup.
^ setting path ^ value ^ comment |
| VBoxInternal/Devices/pcnet/0/LUN#0/Config/**mssql**/Protocol | TCP | MS SQL Server |
| VBoxInternal/Devices/pcnet/0/LUN#0/Config/**mssql**/GuestPort | 1433 | |
| VBoxInternal/Devices/pcnet/0/LUN#0/Config/**mssql**/HostPort | 1433 | |
| VBoxInternal/Devices/pcnet/0/LUN#0/Config/**vnc**/Protocol | TCP | VNC |
| VBoxInternal/Devices/pcnet/0/LUN#0/Config/**vnc**/GuestPort | 5900 | |
| VBoxInternal/Devices/pcnet/0/LUN#0/Config/**vnc**/HostPort | 5904 | (Use a port your host OS isn't already using.) |
| VBoxInternal/Devices/pcnet/0/LUN#0/Config/**rdp**/Protocol | TCP | **Windows'** Remote Desktop server |
| VBoxInternal/Devices/pcnet/0/LUN#0/Config/**rdp**/GuestPort | 3389 | |
| VBoxInternal/Devices/pcnet/0/LUN#0/Config/**rdp**/HostPort | 3390 | (Use 3390 since **VirtualBox's** server grabs 3389) |
| VBoxInternal/Devices/pcnet/0/LUN#0/Config/**ssh**/Protocol | TCP | SSH provided by Cygwin |
| VBoxInternal/Devices/pcnet/0/LUN#0/Config/**ssh**/GuestPort | 22 | |
| VBoxInternal/Devices/pcnet/0/LUN#0/Config/**ssh**/HostPort | 8022 | |
To test all these mapped ports, connect to them on "localhost" when the virtual machine is running:
rdesktop -g 1024x768 localhost # connect to VirtualBox RDP server
rdesktop -g 1024x768 localhost:3390 # connect to Windows RDP server
ssh -p 8022 localhost # connect to ssh
===== Create the init.d Script =====
Now that you've got your virtual machine setup and configured and tested, you're ready to create and configure scripts in "''/etc/init.d/''" to start and suspend the guest on demand.
First, if you look at "''/etc/init.d/vboxdrv''", the service manager script for the VirtualBox kernel driver, you'll see that it looks for a couple of options to tell it what to do with running virtual machines when vboxdrv stops. Create or edit the config file:
sudo touch /etc/default/virtualbox
sudo nano /etc/default/virtualbox
SHUTDOWN_USERS="user1 user2" # space-delimited list of users who might have runnings vms
SHUTDOWN=savestate # if any are found, suspend them to disk
Now, the above settings only cover the system shutdown process, not startup. VirtualBox itself doesn't provide any mechanism for starting virtual machines automatically. To do that, create a new service manager script of your own.
**Items that you need to fill in for yourself marked with "!!".** In all the example files and commands below, find those items and fill them in with strings that make sense for your personal setup.
sudo touch /etc/init.d/virtualbox-!!SHORTNAME #substitute your machine name here
sudo chmod +x /etc/init.d/virtualbox-!!SHORTNAME
sudo nano /etc/init.d/virtualbox-!!SHORTNAME
#! /bin/sh
### BEGIN INIT INFO
# Provides: virtualbox-!!SHORTNAME
# Required-Start: $local_fs $remote_fs vboxdrv vboxnet
# Required-Stop: $local_fs $remote_fs
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: !!LONGNAME virtual machine
# Description: !!LONGNAME virtual machine hosted by VirtualBox
### END INIT INFO
# Author: Brendan Kidwell
#
# Based on /etc/init.d/skeleton from Ubuntu 8.04. Updated for Ubuntu 9.10.
# If you are using Ubuntu <9.10, you might need to change "Default-Stop"
# above to "S 0 1 6".
# Do NOT "set -e"
# PATH should only include /usr/* if it runs after the mountnfs.sh script
PATH=/usr/sbin:/usr/bin:/sbin:/bin
DESC="!!LONGNAME virtual machine"
NAME=virtualbox-!!SHORTNAME
SCRIPTNAME=/etc/init.d/$NAME
MANAGE_CMD=VBoxManage
VM_OWNER=!!USERNAME
VM_NAME="!!LONGNAME" #This has to be the name exactly as it appears in your VirtualBox GUI control panel.
# Read configuration variable file if it is present
[ -r /etc/default/$NAME ] && . /etc/default/$NAME
# Load the VERBOSE setting and other rcS variables
[ -f /etc/default/rcS ] && . /etc/default/rcS
# Define LSB log_* functions.
# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
. /lib/lsb/init-functions
#
# Function that starts the daemon/service
#
do_start()
{
# Return
# 0 if daemon has been started
# 1 if daemon was already running
# 2 if daemon could not be started
sudo -H -u $VM_OWNER $MANAGE_CMD showvminfo "$VM_NAME"|grep "^State:\s*running" >/dev/null && {
echo "$VM_NAME" is already running.
return 1
}
sudo -H -u $VM_OWNER $MANAGE_CMD startvm "$VM_NAME" -type vrdp >/dev/null || {
echo Failed to start "$VM_NAME".
return 2
}
echo "$VM_NAME" started or resumed.
return 0
}
#
# Function that stops the daemon/service
#
do_stop()
{
# Return
# 0 if daemon has been stopped
# 1 if daemon was already stopped
# 2 if daemon could not be stopped
# other if a failure occurred
sudo -H -u $VM_OWNER $MANAGE_CMD showvminfo "$VM_NAME"|grep "^State:\s*running" >/dev/null || {
echo "$VM_NAME" is already stopped.
return 1
}
sudo -H -u $VM_OWNER $MANAGE_CMD controlvm "$VM_NAME" savestate || {
echo Failed to stop "$VM_NAME".
return 2
}
echo "$VM_NAME" suspended.
return 0
}
#
# Display "State" field from showinfo action
#
do_status()
{
sudo -H -u $VM_OWNER $MANAGE_CMD showvminfo "$VM_NAME"|grep "^State:\s*.*$"
}
case "$1" in
start)
[ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
do_start
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
stop)
[ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
do_stop
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
restart|force-reload)
#
# If the "reload" option is implemented then remove the
# 'force-reload' alias
#
log_daemon_msg "Restarting $DESC" "$NAME"
do_stop
case "$?" in
0|1)
do_start
case "$?" in
0) log_end_msg 0 ;;
1) log_end_msg 1 ;; # Old process is still running
*) log_end_msg 1 ;; # Failed to start
esac
;;
*)
# Failed to stop
log_end_msg 1
;;
esac
;;
status)
do_status
;;
*)
#echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload|status}" >&2
exit 3
;;
esac
//Thanks to Trevor White who emailed me and suggested I add the ''-H'' option to the ''sudo'' commands when I said this script wasn't working correctly during boot time.//
===== Test the init.d Script =====
Test the script's ''status'', ''start'', and ''start'' commands:
/etc/init.d/virtualbox-!!SHORTNAME status # Is the VM running?
/etc/init.d/virtualbox-!!SHORTNAME start # Start the VM
rdesktop localhost # Connect to the VM
/etc/inid.d/virtualbox-!!SHORTNAME stop # Stop the VM
===== Install the init.d Script =====
Use the ''update-rc.d'' command to install the script.
sudo update-rc.d virtualbox-!!SHORTNAME defaults
Now whenever you enter normal multiuser run mode (at boot time, for example) your VM will start, and when you exit multiuser mode (during shutdown, for example), your VM will be suspended to disk if it was running.