I would like to create a single shell script which creates, starts and configures a VirtualBox image with a minimal and secure Linux variant, without manual interaction or automation software.

Creating the VirtualBox image is easy, but after booting for the first time, I am currently forced to type the following before I can run the rest of my configuration script over SSH:

ifconfig eth1
adduser joe

I thought I could solve this by copying files or executing scripts from the host, but this seems to require "guest additions" which are not available for Alpine Linux, my current choice.

How do I fully automate this process without any manual interaction after starting the initial script?

  • You might also want to look into how archiveteam.org have solved basically the same problem. – a CVn Aug 20 '16 at 11:53
  • You want something like Vagrant (to handle starting/stopping the machine) and a configuration management tool like Ansible. I know you said you don't want automation software, but you didn't specify why. If your main concern is that you don't want to have to install anything special on the node, then Ansible is ideal as it only requires SSH. You can even ignore all of its modules and use it to run your own bash scripts over SSH, if you insist on reinventing the wheel (note that Python is also required on the nodes if you do decide to use Ansible's modules). – JBentley Aug 20 '16 at 18:45

I would suggest to add your custom commands at the end of:


this is the first file that runs after a distro is booted up.


Your task seems to be the automation of a Linux distribution installation. It would probably be more efficient to modify the installation image and incorporate your automation script.

Other options:

  • Somehow obtain a serial console and hope that a login shell is available. Then use expect to wait for the console to appear and issue the commands you are typing manually. (With QEMU this can be done, I have no idea how VBox handles this.)
  • Create a small disk holding your script and dependencies. Then all you need to type is something like:

    mount /dev/sdb1 /mnt && /mnt/script.sh
  • Ensure that you have some local network connectivity in your VM and do something like:

    curl | sh

Installation media for some distributions read a configuration URL from the kernel command line. Consult your distribution's documentation for details.


Assuming that you have a set of scripts that can be executed to configure the machine in the way that you want, you can, as ebal suggested, run them at the end of /etc/rc.local (or your distribution's equivalent). That script is executed at the end of the boot process, just before getty is spawned by init.

I suggest that you add towards the end of /etc/rc.local something like:

test -x /sbin/system-setup-step1.sh && /sbin/system-setup-step1.sh && reboot
test -x /sbin/system-setup-step2.sh && /sbin/system-setup-step2.sh && reboot
test -x /sbin/system-setup-step3.sh && /sbin/system-setup-step3.sh && reboot
# ... for however many steps are needed for your use case

Then, at the end of each of those scripts, remove the execute bit as an indication that it no longer needs to be executed (but leave the script on disk in case the user wants to see what it did), and store the name of the script somewhere, then check the previously executed script at the top of the next script in the sequence. For example, here's what system-setup-step2.sh might look like:


test $(cat /var/tmp/last-system-setup-step) = "system-setup-step1.sh" || exit 1

# ... do stuff ...

# indicate that this doesn't need to run again
/bin/chmod -x "$0"
printf '%s' $(basename "$0") > /var/tmp/last-system-setup-step
# finished successfully
exit 0

Adjust the test condition near the top for each script.

This way, the system will reboot however many times are required, and at the end will pass right through all those test conditions and reach a login prompt (or whatever else you might have configured) because none of the scripts will have the execute bit set. If something goes wrong, the configuration and rebooting process will simply stop.

In the original image, make sure that /var/tmp/last-system-setup-step exists and is empty, to avoid annoying errors.

Note that the above is untested (written in browser), but should get the gist across.


For the record, virtualbox-guest-additions package was available on testing.

Starting from 24 Jan 2017, they are available in community repository, for the edge version.

In order to use the testing repository, you should:

 export ALPINEVER=v3.5
 echo "http://dl-cdn.alpinelinux.org/alpine/$ALPINEVER/testing" >> /etc/apk/repositories

Of course, you should change ALPINEVER with the version of alpine you are actually using.


If you're trying to set up virtual machines (particularly in VirtualBox) you might want to consider using Vagrant.

You can define the VM in a simple text file like this:

# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure("2") do |config|

    # Specify the base image or "box"
    config.vm.box = "ubuntu/xenial64"

    # Define networking
    config.vm.network "private_network", ip: ""

    # Share folders between the host and the guest
    config.vm.synced_folder "../shared", "/shared"

    # Run "provisioners" that change the guest
    config.vm.provision :shell, :inline, "touch hello_world"
    config.vm.provision "shell", path: "script.sh"

    # You can even use tools like Ansible or Puppet:
    config.vm.provision "ansible" do |ansible|
        ansible.playbook = "playbook.yml"

Vagrant particularly makes it easy to manage networking on virtual machines but also to easily define how you want to setup your virtual machine. And because you now have a Vagrantfile to define your VM you can more easily share this with others or back it up (such as into a source control system such as Git) compared to a binary OVA or equivalent.

It gets even more interesting when you start looking at multi machine setups where you need all of the guests to be able to communicate between themselves.

If you want to use Alpine then you will want to take a look at the vagrant-alpine plugin.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.