Skip to content

WebSharks Ubuntu Bootstrap: VirtualBox + Vagrant + Landrush, running Ubuntu 16.04 LTS (Xenial Xersus) with your choice of Nginx or Apache + MariaDB (MySQL), PHP (choice of PHP 7.1, PHP 7.0, PHP 5.6, PHP 5.5), and WordPress.

wpsharks/ubuntu-bootstrap

Repository files navigation

Ubuntu Bootstrap

VirtualBox + Vagrant + Landrush, running Ubuntu 16.04 LTS (Xenial Xersus) with your choice of Nginx or Apache + MariaDB (MySQL), PHP (choice of PHP 7.1, PHP 7.0, PHP 5.6, PHP 5.5), and WordPress.

Installation Instructions

1.) Satisfy Software Requirements

You need VirtualBox, Vagrant, and a DNS plugin.
The following commands will do the trick for you.

$ brew install cask;
$ brew cask install virtualbox vagrant;

Tweak VirtualBox by running this line please. See details to learn more.

$ VBoxManage dhcpserver remove --netname HostInterfaceNetworking-vboxnet0;

Install a DNS plugin. See vagrant-hostsupdater vs. LandRush

$ vagrant plugin install vagrant-hostsupdater; # Easiest (recommended).
# vagrant plugin install landrush; # More difficult, but greater flexibility.

Optionally install the disksize plugin. See plugin details.
If installed, the Ubuntu Bootstrap will automatically allocate 20GB instead of the default 10GB.

$ vagrant plugin install vagrant-disksize;

Optionally install the triggers plugin. See plugin details.
This enables some additional bootstrapping magic that can improve your experience.

$ vagrant plugin install vagrant-triggers;

Optionally install a caching plugin. See plugin details.
This reduces the amount of downloading the Ubuntu Bootstrap needs to do over time.

$ vagrant plugin install vagrant-cachier;

2.) Clone Ubuntu Bootstrap

$ mkdir ~/vms && cd ~/vms;
$ git clone https://github.com/websharks/ubuntu-bootstrap my.vm;

Note the sub-directory name (my.vm) becomes your domain name.
Change it if you like. Must end with .vm please.

3.) Vagrant Up

$ cd ~/vms/my.vm;
$ vagrant up;

4.) Install Software

$ vagrant ssh;
$ sudo /bootstrap/src/installer --CFG_USE_WIZARD=0;

5.) Confirm Working

Open https://my.vm. Upon first visit, you'll run into an SSL security warning. You can avoid that warning altogether later using the details below. For now, please bypass this self-signed certificate warning and proceed. You should then see the WordPress installation page!

Q: What if https://my.vm doesn't work for me?
A: Try flushing your local DNS cache.

Tip: WordPress dev containers are available too. In addition to my.vm, you also have specific versions of PHP available at: php71.my.vm, php70.my.vm, php56.my.vm, php55.my.vm, and php54.my.vm. By default, the main my.vm web server runs Nginx, while all of the PHP version-specific dev containers run Apache.

Additional Steps (All Optional)

Install Root CA

If you'd like to always see a green SSL status for your local test sites (i.e., avoid https:// warnings on anything ending with .vm), you can download and install this root CA certificate file and set your trust settings to "Always Trust" for this certificate.

To clarify, any SSL certificates created by the Ubuntu Bootstrap will use that root CA certificate. Trusting the root CA (it's fake, and only for the Ubuntu Bootstrap project) will green-light all of your local .vm domains when accessing them over https://.

On a Mac, you can simply drag n' drop the certificate file onto your Keychain.app. Then open the settings for the certificate and choose "Always Trust" at the top.

Note: Prior to macOS Sierra, there was a nasty bug in Keychain.app that would lock your system when attempting to 'Always Trust'. If you're running an older OS X release try this command-line alternative given by @raamdev.

Add Files to Web Directory

Doc root: ~/vms/my.vm/src/app/src/

The latest version of WordPress will already be installed. However, you can add any additional application files that you'd like. e.g., phpBB, Drupal, Joomla, whatever you like. It's probably a good idea to put anything new inside a sub-directory; e.g., ~/vms/my.vm/src/app/src/phpBB

Understanding Environment Variables

  • $_SERVER['CFG_MYSQL_DB_HOST'] Database host.
  • $_SERVER['CFG_MYSQL_DB_NAME'] Database name.
  • $_SERVER['CFG_MYSQL_DB_USERNAME'] Database username.
  • $_SERVER['CFG_MYSQL_DB_PASSWORD'] Database password.

Tip: For a full list of all global environment variables, see: src/setups/env-vars in the repo. Or, from the command-line on your VM type: $ cat /etc/environment — shows you their values.

Access Web-Based Tools

A username/password is required for access. username: admin, password: admin

Tear it Down and Customize

$ cd ~/vms/my.vm;
$ vagrant destroy;

In the project directory you'll find a /src/vagrant/bootstrap-custom file. This bash script runs as the root user during vagrant up. So, you can install software and configure anything you like in this script. By default, this script does nothing. All of the software installation and system configuration takes place whenever you run /bootstrap/src/installer inside the VM.

Customization (Two Choices Available)

  1. Customize /src/installer and the associated setup files that it calls upon, which are located in: /src/setups/*. Note: If you go this route, there really is no reason to customize the /src/vagrant/bootstrap-custom file. You can leave it as-is.

  2. Or, instead of working with the more complex installer, you can keep things simple and add your customizations to the /src/vagrant/bootstrap-custom script, which is a very simple starting point. The /src/vagrant/bootstrap-custom runs whenever you type vagrant up, so this is a logical choice for beginners. Note: If you go this route, you can simply choose not to run /bootstrap/src/installer, because all of your customizations will be in the /src/vagrant/bootstrap-custom file; i.e., there will be no reason to run the installer.

When you're done with your customizations, type:

$ vagrant up;
If you decided to use the /bootstrap/src/installer option, also type:
$ vagrant ssh;
$ sudo /bootstrap/src/installer; # Presents a configuration dialog.
# Tip: to bypass configuration add the `--CFG_USE_WIZARD=0` argument to the installer.

Domain Name Tips & Tricks

Creating a Second VM w/ a Different Domain Name

$ git clone https://github.com/jaswrks/vagrant-ubuntu-lemp my-second.vm;

$ cd my-second.vm;
$ vagrant up && vagrant ssh;

$ sudo /bootstrap/src/installer; # Presents a configuration dialog.
# Tip: to bypass configuration add the `--CFG_USE_WIZARD=0` argument to the installer.

Understanding Domain Name Mapping

The URL which leads to your VM is based on the name of the directory that you cloned the repo into; e.g., my.vm or my-second.vm in the examples here. The directory that you clone into MUST end with .vm for this to work as expected. If the directory you cloned into doesn't end with .vm, the default domain name will be http://ubuntu.vm

If you're running the Landrush plugin for Vagrant, the domain name is also wildcarded. So my.vm, www.my.vm, wordpress.my.vm — these all map to the exact same document root: ~/vms/my.vm/app/src/, which is helpful when testing WordPress multisite networks. You can easily setup a sub-domain network, or even an MU domain mapping plugin and run additional tests.

If instead, you're running the vagrant-hostsupdater plugin, wildcard DNS is not possible, but the following sub-domains are mapped automatically by the Vagrantfile so you'll still have a few to work with; i.e., my.my.vm, dev.my.vm, io.my.vm, api.my.vm, cdn.my.vm, sub.my.vm, sub1.my.vm, sub2.my.vm, sub3.my.vm, and perhaps others if you choose to install WordPress dev containers when following prompts in the installer; e.g., php54.my.vm, php55.my.vm, php56.my.vm, php70.my.vm, php71.my.vm.

Testing WordPress Themes/Plugins

See /Vagrantfile where you will find this section already implemented. _~ See also: src/wordpress/install-symlinks_

wp_project_dirs = ( ENV["WP_#{_VM_HOSTNAME_UC_VAR}_PROJECTS_DIR"] || ENV['WP_PROJECTS_DIR'] || File.expand_path('~/projects/wordpress') ).split(/[:;]+/).map(&:strip);
wp_personal_project_dirs = ( ENV["WP_#{_VM_HOSTNAME_UC_VAR}_PERSONAL_PROJECTS_DIR"] || ENV['WP_PERSONAL_PROJECTS_DIR'] || File.expand_path('~/projects/personal/wordpress') ).split(/[:;]+/).map(&:strip);
wp_business_project_dirs = ( ENV["WP_#{_VM_HOSTNAME_UC_VAR}_BUSINESS_PROJECTS_DIR"] || ENV['WP_BUSINESS_PROJECTS_DIR'] || File.expand_path('~/projects/business/wordpress') ).split(/[:;]+/).map(&:strip);

wp_project_dirs.each_with_index do |dir, i|
  if File.directory?(dir)
    config.vm.synced_folder dir, "/wp-projects-#{i}", mount_options: ['defaults', 'ro'];
  end;
end;
wp_personal_project_dirs.each_with_index do |dir, i|
  if File.directory?(dir)
    config.vm.synced_folder dir, "/wp-personal-#{i}", mount_options: ['defaults', 'ro'];
  end;
end;
wp_business_project_dirs.each_with_index do |dir, i|
  if File.directory?(dir)
    config.vm.synced_folder dir, "/wp-business-#{i}", mount_options: ['defaults', 'ro'];
  end;
end;

↑ What is happening there?

The built-in default Vagrantfile is automatically mounting drives on your VM, sourced by a local ~/projects/wordpress directory — if you have that directory. So, put your WordPress themes and plugins in ~/projects/wordpress, i.e. in your local filesystem. These will be mounted on the VM automatically as /wp-projects-0/[themes|plugins]/[basename].

Then, in the included src/wordpress/install-symlinks file, the Ubuntu Bootstrap iterates through all /wp-projects-* directories that were mounted on the VM. It build symlinks for each of your themes and plugins automatically. This means when you log into your WordPress Dashboard on the VM you will have all of your themes and plugins available for testing. If you make edits locally in your favorite editor, those changes take effect in real-time on the VM.

The additional mounts: ~/projects/personal/wordpress and ~/projects/business/wordpress are simply alternate locations. There are also some interesting variables being scanned in the above snippet. Those variables implement some powerful dynamics you can take advantage of — discussed in greater detail below.

The default WordPress mapping looks like this:

  • ~/projects/wordpress in your local file system.
    • Is mounted on the VM as: /wp-projects-0
  • Then, on the VM, the src/wordpress/install-symlinks script symlinks each theme/plugin into:
    • /app/src/wp-content/[themes|plugins] appropriately.

What directory structure do I need exactly?

In your local file system, inside ~/projects/wordpress create two sub-directories.

  • ~/projects/wordpress/themes (put themes in this directory; e.g., .../my-theme/)
  • ~/projects/wordpress/plugins (put plugins here; e.g., .../my-plugin/)

When you run /bootstrap/src/installer from the VM, your local copy of ~/projects/wordpress/themes/my-theme becomes /app/src/wp-content/themes/my-theme on the VM. Your local copy of ~/projects/wordpress/plugins/my-plugin becomes /app/src/wp-content/plugins/my-plugin on the VM ... and so on... for each theme/plugin sub-directory, and for each of the three possible mounts listed above. This all happens automatically if you followed the instructions.

Can I override the default source directories for WordPress?

Yes. Looking over the snippet above, you can see three environment variables can be set in your ~/.profile. Setting them will override the default locations automatically. Here's a quick example showing how you might customize these in your own ~/.profile

export WP_PROJECTS_DIR=~/my-projects/wordpress;
export WP_PERSONAL_PROJECTS_DIR=~/my-personal-projects/wordpress;
export WP_BUSINESS_PROJECTS_DIR=~/my-business-projects/wordpress;

It's also possible to define hostname-specific environment variables. Take note of _MY_VM in the examples below. This correlates with my.vm (a specific hostname) converted to all uppercase with dots and hyphens now as _ underscores.

export WP_MY_VM_PROJECTS_DIR=~/my-projects/wordpress;
export WP_MY_VM_PERSONAL_PROJECTS_DIR=~/my-personal-projects/wordpress;
export WP_MY_VM_BUSINESS_PROJECTS_DIR=~/my-business-projects/wordpress;

It's also possible to set multiple locations in each environment variable by delimiting them with a colon : or semicolon ;. For example, if you work with multiple businesses.

export WP_BUSINESS_PROJECTS_DIR=~/business-1/wordpress:~/business-2/wordpress;

Or, by combining both techniques (hostname-specific and delimited).

export WP_MY_VM_BUSINESS_PROJECTS_DIR=~/business-1/wordpress:~/business-2/wordpress;

Bootstrap Command-Line Arguments

The following CLI arguments can be passed to /bootstrap/src/installer, just in case you'd like to avoid the configuration wizard entirely. These are all optional; i.e., if you don't provide these arguments you will be prompted to configure the bootstrap using a command-line dialog interface whenever the installer runs.

Tip: You can learn more about how these work and what the defaults are by looking through the src/setups/cfg/setup file carefully, and perhaps searching for their use in other files found in src/setups/*.


  • --CFG_4CI=0|1 Building as a base image for a CI server?
  • --CFG_4PKG=0|1 Building as a base image that will be packaged?

  • --CFG_USE_WIZARD=0|1 Set as 0 to bypass the wizard.

  • --CFG_HOST=my.cool.vm Host name.
  • --CFG_ROOT_HOST=cool.vm Root host name.

  • --CFG_SLUG=my-cool-vm Slug w/ dashes, no underscores.
  • --CFG_VAR=my_cool_vm Slug w/ underscores, no dashes.

  • --CFG_ADMIN_GENDER=[male|female] Admin gender.

  • --CFG_ADMIN_USERNAME=admin Admin username.
  • --CFG_ADMIN_PASSWORD=admin Admin password.


  • --CFG_ADMIN_PREFERRED_SHELL=/bin/zsh Or /bin/bash.
  • --CFG_ADMIN_STATIC_IP_ADDRESS=[ip] e.g., 123.456.789.0
  • --CFG_ADMIN_AUTHORIZED_SSH_KEYS=[file] e.g., /authorized_keys

  • --CFG_AWS_TRANSFER_ACCESS_KEY_ID=xxxxxxx... AWS access key ID.
  • --CFG_AWS_TRANSFER_SECRET_ACCESS_KEY=xxxxxxx... AWS secret access key.

  • --CFG_INSTALL_SWAP=0|1 Install swap space?

  • --CFG_INSTALL_WS_CA_FILES=0|1 Use WebSharks certificate authority?

  • --CFG_INSTALL_POSTFIX=0|1 Install Postfix?
  • --CFG_INSTALL_MAILHOG=0|1 Install MailHog instead of Postfix?

  • --CFG_INSTALL_OPENVPN=0|1 Install OpenVPN server?

  • --CFG_INSTALL_DOCKER=0|1 Install Docker?

  • --CFG_INSTALL_OAUTH_KEYS=0|1 Install OAuth keys?
  • --CFG_OAUTH_PUBLIC_KEY=[file] OAuth SSL public key file.
  • --CFG_OAUTH_PRIVATE_KEY=[file] OAuth SSL private key file.
  • --CFG_OAUTH_ENCRYPTION_KEY=xxxxxxx... OAuth 32-byte, base64-encoded key.

  • --CFG_INSTALL_MYSQL=0|1 Install MySQL?

  • --CFG_MYSQL_DB_HOST=127.0.0.1 MySQL DB host name.
  • --CFG_MYSQL_DB_PORT=3306 MySQL DB port number.

  • --CFG_MYSQL_SSL_KEY=[file] MySQL SSL key file.
  • --CFG_MYSQL_SSL_CRT=[file] MySQL SSL crt file.
  • --CFG_MYSQL_SSL_CA=[file] MySQL SSL ca file.
  • --CFG_MYSQL_SSL_CIPHER=[cipher] MySQL SSL cipher.

  • --CFG_MYSQL_SSL_ENABLE=0|1 MySQL over SSL?

  • --CFG_MYSQL_DB_CHARSET=utf8mb4 MySQL DB charset.
  • --CFG_MYSQL_DB_COLLATE=utf8mb4_unicode_ci MySQL DB collation.

  • --CFG_MYSQL_DB_NAME=db0 MySQL DB name.

  • --CFG_MYSQL_DB_USERNAME=client MySQL DB username.
  • --CFG_MYSQL_DB_PASSWORD=[password] Default is auto-generated.

  • --CFG_MYSQL_X_DB_USERNAME=x_client MySQL external DB username.
  • --CFG_MYSQL_X_DB_PASSWORD=[password] Default is auto-generated.

  • --CFG_MYSQL_X_REQUIRES_SSL=0|1 External connections require SSL?

  • --CFG_INSTALL_MEMCACHE=0|1 Install Memcached?
  • --CFG_INSTALL_RAMDISK=0|1 Install a RAM disk partition?

  • --CFG_INSTALL_PHP_CLI=0|1 Install PHP command-line interpreter?
  • --CFG_INSTALL_PHP_FPM=0|1 Install PHP-FPM process manager for Apache/Nginx?
  • --CFG_INSTALL_PHP_VERSION=[7.1|7.0|5.6|5.5] Which PHP version to install?

  • --CFG_ENABLE_PHP_OPCACHE=0|1 Enable the PHP OPcache extension?
  • --CFG_INSTALL_PHP_XDEBUG=0|1 Install PHP XDebug extension?
  • --CFG_ENABLE_PHP_PHAR_READONLY=0|1 Force PHAR readonly mode?
  • --CFG_ENABLE_PHP_ASSERTIONS=0|1 Enable PHP assertions?

  • --CFG_INSTALL_COMPOSER=0|1 Install Composer?

  • --CFG_INSTALL_PMA=0|1 Install PhpMyAdmin?
  • --CFG_PMA_BLOWFISH_KEY=[key] Blowfish key for PMA.

  • --CFG_INSTALL_PSYSH=0|1 Install Psysh?
  • --CFG_INSTALL_PHPCS=0|1 Install PHP Code Sniffer?
  • --CFG_INSTALL_PHING=0|1 Install Phing?
  • --CFG_INSTALL_PHPUNIT=0|1 Install PHPUnit?
  • --CFG_INSTALL_SAMI=0|1 Install Sami codex generator?
  • --CFG_INSTALL_APIGEN=0|1 Install APIGen codex generator?
  • --CFG_INSTALL_CACHETOOL=0|1 Install PHP-FPM cachetool?
  • --CFG_INSTALL_WP_CLI=0|1 Install WP CLI tool?
  • --CFG_INSTALL_WP_I18N_TOOLS=0|1 Install WP i18n tools?
  • --CFG_INSTALL_WEBSHARKS_CORE=0|1 Install WS Core?

  • --CFG_INSTALL_NGINX=0|1 Install Nginx?
  • --CFG_INSTALL_APACHE=0|1 Install Apache?

  • --CFG_WEB_SERVER_SSL_ONLY=0|1 Serve https:// requests only?
  • --CFG_MAINTENANCE_BYPASS_KEY=[key] Bypass key in maintenance mode.

  • --CFG_INSTALL_CASPERJS=0|1 Install CasperJS?

  • --CFG_INSTALL_APP_REPO=0|1 Install a Git repo?

  • --CFG_INSTALL_WORDPRESS=0|1 Install WordPress?
  • --CFG_INSTALL_WORDPRESS_VM_SYMLINKS=0|1 Install symlinks?

  • --CFG_INSTALL_WORDPRESS_DEV_CONTAINERS=0|1 Install WP dev containers?

  • --CFG_WORDPRESS_DEV_GENDER=[male|female] WP developer gender.

  • --CFG_WORDPRESS_DEV_USERNAME=[username] WP developer username.
  • --CFG_WORDPRESS_DEV_PASSWORD=[password] Default is auto-generated.

  • --CFG_WORDPRESS_DEV_NAME=[name] WP developer name.
  • --CFG_WORDPRESS_DEV_EMAIL=[email] WP developer email address.

  • --CFG_WORDPRESS_DEV_PREFERRED_SHELL=/bin/zsh Or /bin/bash.
  • --CFG_WORDPRESS_DEV_STATIC_IP_ADDRESS=[ip] e.g., 123.456.789.0
  • --CFG_WORDPRESS_DEV_AUTHORIZED_SSH_KEYS=[file] e.g., /authorized_keys

  • --CFG_INSTALL_DISCOURSE=0|1 Install Discourse?

  • --CFG_DISCOURSE_SMTP_HOST=email-smtp.us-east-1.amazonaws.com SMTP host name.
  • --CFG_DISCOURSE_SMTP_PORT=587 SMTP port number.

  • --CFG_DISCOURSE_SMTP_AUTH_TYPE=login SMTP authentication type.
  • --CFG_DISCOURSE_SMTP_USERNAME=[username] SMTP username.
  • --CFG_DISCOURSE_SMTP_PASSWORD=[password] SMTP password.

  • --CFG_INSTALL_FIREWALL=0|1 Install firewall?

  • --CFG_FIREWALL_ALLOWS_ADMIN_ONLY_VIA_22=0|1 Allow admin only?
    • Requires --CFG_ADMIN_STATIC_IP_ADDRESS ; for production use only.
  • --CFG_FIREWALL_ALLOWS_MYSQL_VIA_3306=0|1 Allow external connections to MySQL?
  • --CFG_FIREWALL_ALLOWS_MYSQL_INSIDE_VPN=0|1 Allow network-based connections?
  • --CFG_FIREWALL_ALLOWS_CF_ONLY_VIA_80_443=0|1 Allow only CloudFlare?

  • --CFG_INSTALL_FAIL2BAN=0|1 Install Fail2Ban?

  • --CFG_INSTALL_UNATTENDED_UPGRADES=0|1 Configure unattended upgrades?

  • --CFG_CONFIG_FILE=/app/.config.json This is for any purpose you like. The value that you set here becomes a global environment variable that your application can consume. If set, it should be a configuration file path on the VM. The file does not even need to exist when configured, it's simply an environment variable that you can use elsewhere in your application later.

vagrant-hostsupdater vs Landrush

The vagrant-hostsupdater plugin is the easiest way to get started. It's quite simple in that it merely updates the /etc/hosts file in macOS. This avoids any confusion. You can just $ sudo vi /etc/hosts and take a quick peek at what's been done after you vagrant up for the first time.

However, unlike the more powerful Landrush plugin, vagrant-hostsupdater doesn't automatically assign a new IP for each VM instance that you bring up. Instead, the IP is established by the Vagrantfile, and in the Ubuntu Bootstrap (if you run the vagrant-hostsupdater plugin), your VM's IP address will always be the default hard-coded: 192.168.42.42

You may eventually want to run multiple VMs at the same time; i.e., you'll need multiple IP addresses. To accomplish this with the vagrant-hostsupdater plugin you'll need to edit the Vagrantfile manually. Bump the IP from 192.168.42.42 (default), to 192.168.42.43, 192.168.42.44, etc. — for each of your additional VM instances.

The Landrush plugin is slightly heavier, but it's also more flexible. It spins up a small DNS server and redirects DNS traffic, automatically registering/unregistering IP addresses for VMs as they come up and go down. With Landrush there is no need to edit the Vagrantfile manually. You can run several VMs all at the same time, all on different IPs, and without needing to edit the Vagrantfile.

Bootstrapping Base Images for Custom Vagrant Boxes

Please see: Packaging a Custom Box for full instructions.