Copy from Holger Woltersdorf Github
Before we start setting things up, I assume this is what you know / what you have:
- What vagrant is and how it basically works (obviously!)
- How to set up a webserver like nginx or apache2
- Basic knowledge about working with linux systems
- A public or private webserver where you can run/configure a webserver (nginx/apache2) and upload/download files.
- A host system with a GUI (e.g. Windows, Mac OS X, etc.)
The tutorial uses an installation of Ubuntu 14.04.2 LTS as the guest machine, VirtualBox at version 5.0.0 as provider and Vagrant at version 1.7.4.
- Download and install VirtualBox 5.0.0 at http://download.virtualbox.org/virtualbox/5.0.0/ (Choose the installer that fits your system)
- Download and install Vagrant 1.7.4 at https://dl.bintray.com/mitchellh/vagrant/ (Choose the installer that fits your system)
- Download a VirtualBox image of Ubuntu 14.04.2 LTS, e.g. at http://virtualboxes.org/images/ubuntu-server/ (all the following steps refer to this image)
- Open the VirtualBox GUI and choose
File > Import appliance ..., select the.ovafile you downloaded before. - Change the appliance settings to fit your needs, for now I'll only change the name of the machine from
ubuntu-14.04-server-amd64todevops-template. - Important: Make sure to activate
Reinitialize the MAC address of all network cardscheckbox! - Click
Importand you'll have a new virtual machine added to VirtualBox after a few minutes ready to run.
- Select the newly imported vm named
devops-templatein VirtualBox GUI and clickSettings - Select the tab
Network - Activate
Enable Network Adapter(if not already activated) under the tabAdapter 1 - Select
Attached to:NAT(this is a requirement by Vagrant) - Leave everything else as is.
- Select the vm named
devops-templatein VirtualBox GUI and clickStart(wait until you see theubuntu-amd64 login:) - Type
ubuntuas loginname anreverseas password. - First of all, update the machine. This will take a moment. Get a coffee!
$ sudo apt-get update
$ sudo apt-get dist-upgrade -y- Edit the file
/root/.profile
$ sudo nano /root/.profile
# ~/.profile: executed by Bourne-compatible login shells.
if [ "$BASH" ]; then
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
fi
mesg n # replace this line by "tty -s && mesg n"Note: This avoids an annoying warning, when you vagrant up later.
- Change the hostname
$ sudo nano /etc/hostname
ubuntu-amd64 # replace this by "devops-template"- Let the machine resolve its own hostname
$ sudo nano /etc/hosts
127.0.0.1 localhost
127.0.1.1 ubuntu-amd64 # replace this by "127.0.1.1 devops-template"
# The following lines are desirable for IPv6 capable hosts
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters- Finalize language settings
$ sudo locale-gen en_US.UTF-8 # Or whatever language you want to use
$ sudo dpkg-reconfigure locales
$ sudo nano /etc/default/locale
LANG="en_US.UTF-8"
LANGUAGE="en_US"- Add the
vagrantuser
$ sudo adduser vagrant
# Set the password to "vargrant" too!
# Set the Full Name to "Vagrant", leave the rest blank- Allow Vagrant to login via insecure private key
# Add a ssh config folder and authorized_keys file
$ sudo mkdir /home/vagrant/.ssh
$ sudo touch /home/vagrant/.ssh/authorized_keys
# Set owner and permissions
$ sudo chown -R vagrant /home/vagrant/.ssh
$ sudo chmod 0700 /home/vagrant/.ssh
$ sudo chmod 0600 /home/vagrant/.ssh/authorized_keys
# Add the insecure public key, see https://github.com/mitchellh/vagrant/tree/master/keys
$ su vagrant
$ curl 'https://raw.githubusercontent.com/mitchellh/vagrant/master/keys/vagrant.pub' >> /home/vagrant/.ssh/authorized_keys
$ exit- Configure the sudo rights of user
vagrant
$ sudo nano /etc/sudoers.d/vagrant
vagrant ALL=(ALL) NOPASSWD: ALL
$ sudo chmod 0440 /etc/sudoers.d/vagrant- Disable DNS usage for sshd
$ sudo nano /etc/ssh/sshd_config
# Add the following line at the end of the file:
UseDNS no- Important: Install the VirtualBox Guest Additions with the proper version
Hint: Do not install the guest additions with apt-get install virtualbox-guest-additions-iso as this release is mostly outdated.
I said above that I'm using VirtualBox in Version 5.0.0, so the guest additions should be of the same version.
# prepare
$ sudo apt-get install -y linux-headers-generic build-essential dkms
# get the right ISO from http://download.virtualbox.org/virtualbox/
$ wget http://download.virtualbox.org/virtualbox/5.0.0/VBoxGuestAdditions_5.0.0.iso
# create a mount folder
$ sudo mkdir /media/VBoxGuestAdditions
# mount the ISO
$ sudo mount -o loop,ro VBoxGuestAdditions_5.0.0.iso /media/VBoxGuestAdditions
# install the guest additions
$ sudo sh /media/VBoxGuestAdditions/VBoxLinuxAdditions.run
# remove the ISO
$ rm VBoxGuestAdditions_5.0.0.iso
# unmount the ISO
$ sudo umount /media/VBoxGuestAdditions
# remove the mount folder
$ sudo rmdir /media/VBoxGuestAdditions- Last but not least: Change the welcome message and add the version number. We will change this later to see versioning work.
$ rm -rf /etc/motd
$ sudo nano /etc/motd
--
Welcome to devops-template version 0.1.0!
--- Reboot the vm to see your changes take effect:
$ sudo shutdown -r nowNow you should see a login terminal like this:
Ubuntu 14.04.2 LTS devops-template tty1
devops-template login: _Login and check the message of the day (motd) we set up:
Last login: ...
Welcome to Ubuntu ...
* Documentation: ...
[...]
--
Welcome to devops-template version 0.1.0!
--
ubuntu@devops-template:~$ _- Shutdown the vm
$ sudo shutdown -h nowGot it? Yeah, preparation is done!
Remember, we said in the message of the day, that this is version 0.1.0.
- Open a terminal on your host machine
- Create two new directories:
VagrantBoxesandVagrantTest
$ mkdir ~/VagrantBoxes
$ mkdir ~/VagrantTest- Change into the
VagrantBoxesdirectory. - Package the box
$ cd ~/VagrantBoxes
$ vagrant package --base 'devops-template' --output 'devops_0.1.0.box'Note: Because we will build multiple versions of the devops-template vm, we will put the version number in the name of the box file.
Packaging will take some time, you may get your next coffee!
When packaging is done, you should see an output like this:
==> devops-template: Exporting VM...
==> devops-template: Compressing package to: ~/VagrantBoxes/devops_0.1.0.box- Change into the
VagrantTestdirectory.
$ cd ~/VagrantTest- Add the box to vagrant
$ vagrant box add 'devops' file://~/VagrantBoxes/devops_0.1.0.boxIf successful, you should see output like this:
==> box: Adding box 'devops' (v0) for provider:
box: Downloading: file://~/VagrantBoxes/devops_0.1.0.box
==> box: Successfully added box 'devops' (v0) for 'virtualbox'!Note the v0. There is no version specified yet.
- Init a vagrant project
$ vagrant initNow there is a Vagrantfile with default settings in your current directory.
- Edit this
Vagrantfileusing a text editor
# Change the following line from
config.vm.box = "base"
# to
config.vm.box = "devops"
# save the fileNote: base is vagrant's default name for a box. But we told vagrant box add the name devops.
- Bring the machine up
$ vagrant upIf done, you should see output like this:
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Importing base box 'devops'...
==> default: Matching MAC address for NAT networking...
==> default: Setting the name of the VM: VagrantTest_default_1406634147824_25052
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
default: Adapter 1: nat
==> default: Forwarding ports...
default: 22 => 2222 (adapter 1)
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
default: SSH address: 127.0.0.1:2222
default: SSH username: vagrant
default: SSH auth method: private key
default: Warning: Connection timeout. Retrying...
==> default: Machine booted and ready!
==> default: Checking for guest additions in VM...
==> default: Mounting shared folders...
default: /vagrant => ~/VagrantTestNote: Vagrant's default behaviour is to boot the vm in headless mode (without a GUI in background). While booting the vm you can see the new vm in your VirtualBox GUI as "-> Running"
- SSH into the machine
$ vagrant sshNow you should see our previously added message of the day.
- Check if your
VagrantTestfolder is mounted
$ cd /vagrant/
$ ls -laAnd you should see something like this:
drwxr-xr-x 1 vagrant vagrant 136 Jul 29 13:38 .
drwxr-xr-x 23 root root 4096 Jul 29 13:42 ..
drwxr-xr-x 1 vagrant vagrant 102 Jul 29 13:38 .vagrant
-rw-r--r-- 1 vagrant vagrant 4813 Jul 29 13:39 VagrantfileOkay, your box works fine, well done!
- Exit the SSH session and destroy the machine
$ exit # On guest$ vagrant destroy # On host- Remove the box from vagrant (we will add it later with a version again!)
$ vagrant box remove 'devops'
Removing box 'devops' (v0) with provider 'virtualbox'...In order to serve multiple versions of a vagrant box and enable update notifications we need to set up a box catalog. This catalog is written in JSON code to a single file.
To keep things simple at this point we will carry on in the local filesystem of your host.
- Change into the
VagrantBoxesdirectory.
cd ~/VagrantBoxes- Create the file
devops.jsonwith the following content
{
"name": "devops",
"description": "This box contains Ubuntu 14.04.2 LTS 64-bit.",
"versions": [{
"version": "0.1.0",
"providers": [{
"name": "virtualbox",
"url": "file://~/VagrantBoxes/devops_0.1.0.box",
"checksum_type": "sha1",
"checksum": "d3597dccfdc6953d0a6eff4a9e1903f44f72ab94"
}]
}]
}What is going on here?
- We tell the catalog to be related to the box name
devops. All versions will be grouped under this name. - We created a clear statement of what is in the box.
- We defined the first version 0.1.0
- We tell that, version 0.1.0 is available for provider virtualbox under the URL file://~/VagrantBoxes/devops_0.1.0.box
- That's why you should put the version into the filename!
- We tell vagrant that there is a sha1-checksum to check when importing the box.
- To determine the checksum of your box, you can simple do sth. like this:
$ openssl sha1 ~/VagrantBoxes/devops_0.1.0.box
SHA1(~/VagrantBoxes/devops_0.1.0.box)= d3597dccfdc6953d0a6eff4a9e1903f44f72ab94Note: This is done on a linux based system. On Windows there will be another way.
Your catalog is finished!
- Change into the
VagrantTestdirectory
$ cd ~/VagrantTest- Edit the
Vagrantfilefile in a text editor
# Under ...
config.vm.box = "devops"
# ... add the line
config.vm.box_url = "file://~/VagrantBoxes/devops.json"
# save the file- Run
vagrant upwithout adding the box manually usingvagrant box add
$ vagrant upWhen done, you should see output like this:
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Box 'devops' could not be found. Attempting to find and install...
default: Box Provider: virtualbox
default: Box Version: >= 0
==> default: Loading metadata for box 'file://~/VagrantBoxes/devops.json'
default: URL: file://~/VagrantBoxes/devops.json
==> default: Adding box 'devops' (v0.1.0) for provider: virtualbox
default: Downloading: file://~/VagrantBoxes/devops_0.1.0.box
default: Calculating and comparing box checksum...
==> default: Successfully added box 'devops' (v0.1.0) for 'virtualbox'!Note the line Loading metadata for box 'file://~/VagrantBoxes/devops.json' that confirms the catalog is read.
And note the line Adding box 'devops' (v0.1.0) for provider: virtualbox that confirms that version 0.1.0 is added to VirtualBox.
The last two lines confirm that our checksum in the devops.json file was correct.
==> default: Importing base box 'devops'...
==> default: Matching MAC address for NAT networking...
==> default: Checking if box 'devops' is up to date...
==> default: Setting the name of the VM: VagrantTest_default_1406640770074_13210
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
default: Adapter 1: nat
==> default: Forwarding ports...
default: 22 => 2222 (adapter 1)
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
default: SSH address: 127.0.0.1:2222
default: SSH username: vagrant
default: SSH auth method: private key
default: Warning: Connection timeout. Retrying...
==> default: Machine booted and ready!
==> default: Checking for guest additions in VM...
==> default: Mounting shared folders...
default: /vagrant => ~/VagrantTestAgain, our machine is up and running.
If you wish you now can re-check by ssh into the machine, reading the message of the day and listing the content of /vagrant on the guest.
Okay, now we have built a vagrant box with an initial version. Let's add another version.
- Halt the vm (do not destroy it!)
$ vagrant halt
==> default: Attempting graceful shutdown of VM...- Open the VirtualBox GUI, select the vm named
devops-templateand clickStart - Log into the vm after it has booted
- Change the version number in
/etc/motdfrom0.1.0to0.1.1and save the file
$ sudo nano /etc/motd
--
Welcome to devops-template version 0.1.1!
--- Shutdown the vm
$ sudo shutdown -h nowTo be clear: Changing the version number in /etc/motd has nothing to do with the version itself. It just simulates
a minor but visible change to the vm template. Instead of changing the content of a file, you'll be installing software
or editing configs on a real-world vm.
- Change into
VagrantBoxesdirectory.
$ cd ~/VagrantBoxes- Package the template vm to a new vagrant box
$ vagrant package --base 'devops-template' --output 'devops_0.1.1.box'
==> devops-template: Exporting VM...
==> devops-template: Compressing package to: ~/VagrantBoxes/devops_0.1.1.boxNote the raised version number 0.1.1 in the output filename!
Your directory listing of ~/VagrantBoxes should look like this now:
$ ls -a1 ~/VagrantBoxes
.
..
devops.json
devops_0.1.0.box
devops_0.1.1.boxIf you wish you can test your new box like done under chapter 3.2.
- Edit the
devops.jsonfile in a text editor and extend the content to look like this:
{
"name": "devops",
"description": "This box contains Ubuntu 14.04.1 LTS 64-bit.",
"versions": [{
"version": "0.1.0",
"providers": [{
"name": "virtualbox",
"url": "file:///Users/hollodotme/VagrantBoxes/devops_0.1.0.box",
"checksum_type": "sha1",
"checksum": "d3597dccfdc6953d0a6eff4a9e1903f44f72ab94"
}]
},{
"version": "0.1.1",
"providers": [{
"name": "virtualbox",
"url": "file:///Users/hollodotme/VagrantBoxes/devops_0.1.1.box",
"checksum_type": "sha1",
"checksum": "0b530d05896cfa60a3da4243d03eccb924b572e2"
}]
}]
}Don't forget to determine the checksum of the newly created box devops_0.1.1.box!
- Change into
VagrantTestdirectory.
$ cd ~/VagrantTest- Ask if your vagrant box is outdated
$ vagrant box outdated
Checking if box 'devops' is up to date...
A newer version of the box 'devops' is available! You currently
have version '0.1.0'. The latest is version '0.1.1'. Run
`vagrant box update` to update.Suprise, suprise - a new version is available!
Note: Instead of manually asking for outdated boxes, vagrant will notify you automatically when you use the
Vagrant commands like vagrant up, vagrant reload, vagrant resume, etc.!
- Update the box
$ vagrant box update
==> default: Checking for updates to 'devops'
default: Latest installed version: 0.1.0
default: Version constraints:
default: Provider: virtualbox
==> default: Updating 'devops' with provider 'virtualbox' from version
==> default: '0.1.0' to '0.1.1'...
==> default: Loading metadata for box 'file://~/VagrantBoxes/devops.json'
==> default: Adding box 'devops' (v0.1.1) for provider: virtualbox
default: Downloading: file://~/VagrantBoxes/devops_0.1.1.box
default: Calculating and comparing box checksum...
==> default: Successfully added box 'devops' (v0.1.1) for 'virtualbox'!Note: The box with version 0.1.0 still exists. Vagrant will never prune your boxes automatically because of potential data loss.
- Remove the old box
$ vagrant box remove 'devops'
You requested to remove the box 'devops' with provider
'virtualbox'. This box has multiple versions. You must
explicitly specify which version you want to remove with
the `--box-version` flag. The available versions for this
box are:
* 0.1.0
* 0.1.1Okay, so...
$ vagrant box remove 'devops' --box-version '0.1.0'
~/VagrantTest/Vagrantfile:5: warning: already initialized constant VAGRANTFILE_API_VERSION
~/VagrantTest/Vagrantfile:5: warning: previous definition of VAGRANTFILE_API_VERSION was here
Box 'devops' (v0.1.0) with provider 'virtualbox' appears
to still be in use by at least one Vagrant environment. Removing
the box could corrupt the environment. We recommend destroying
these environments first:
default (ID: 3206d9d1a427459daac770f2e7e81f1b)
Are you sure you want to remove this box? [y/N]No! Let's destroy it first.
$ vagrant destroy
default: Are you sure you want to destroy the 'default' VM? [y/N] y
==> default: Destroying VM and associated drives...Now remove it, please!
$ vagrant box remove 'devops' --box-version '0.1.0'
Removing box 'devops' (v0.1.0) with provider 'virtualbox'...Hell yeah!
- Bring up the machine
$ vagrant up- SSH into the machine
$ vagrant sshNow you should see the previously changed version number 0.1.1 in the message of the day after login.
--
Welcome to devops-template version 0.1.1!
--So we are up-to-date!
What we did so far:
- We created a virtual machine template
- We built two versioned vagrant boxes out of the virtual machine template
- We established a box catalog to serve the versions to the client
- We updated an outdated box
What we will do now:
- Hosting the box catalog and the boxes on a webserver a.k.a. set up our own vagrant cloud.
So cleanup your desk: exit your SSH session, destroy the vm and remove it from vagrant.
$ exit # On guest$ vagrant destroy # On host
$ vagrant box remove 'devops'As I mentioned at the beginning, I assume that you have private/public webserver and access to its config and filesystem.
For explanation I'll use the domain www.example.com targeting to this webserver.
Furthermore www.example.com points to /var/www/ on the webserver's filesystem (document root).
To keep things easy I prefer to separate the catalog and the box files physically in the filesystem. Keep on reading and you'll understand why.
- /var/www # document root
`- vagrant
`- devops # box name folder
|- boxes # contains all available box files
| |- devops_0.1.0.box # version 0.1.0
| `- devops_0.1.1.box # version 0.1.1
`- devops.json # box catalogTranslated to URLs we have three targets to care about (we will use these later):
- The catalog: http://www.example.com/vagrant/devops/devops.json
- Box (v0.1.0): http://www.example.com/vagrant/devops/boxes/devops_0.1.0.box
- Box (v0.1.1): http://www.example.com/vagrant/devops/boxes/devops_0.1.1.box
I want to explain the basic webserver configuration with nginx on a linux server, because this is my favorite software. The configuration can be ported to apache and/or windows as well.
- SSH into your server.
$ ssh user@example.com- Install nginx
$ sudo apt-get install nginx-full- Create the target folders and set permissions
# Create folders
$ sudo mkdir -p /var/www/vagrant/devops/boxes
# Set owner to www-data
$ sudo chown -R www-data:www-data /var/www
# Set permissions
$ sudo chmod -R 0751 /var/www- Delete the
defaultsym-linked config for virtual hosts (vhost) - Just to make sure there is no colliding config!
$ sudo rm -rf /etc/nginx/sites-enabled/default- Create a new specific vhost config for
www.example.com
sudo nano /etc/nginx/sites-available/example.com... with the following content:
server {
listen 80 default_server;
listen [::]:80 ipv6only=on default_server;
server_name example.com www.example.com;
root /var/www;
# Match the box name in location and search for its catalog
# e.g. http://www.example.com/vagrant/devops/ resolves /var/www/vagrant/devops/devops.json
location ~ ^/vagrant/([^\/]+)/$ {
index $1.json;
try_files $uri $uri/ $1.json =404;
autoindex off;
}
# Enable auto indexing for the folder with box files
location ~ ^/vagrant/([^\/]+)/boxes/$ {
try_files $uri $uri/ =404;
autoindex on;
autoindex_exact_size on;
autoindex_localtime on;
}
# Serve json files with content type header application/json
location ~ \.json$ {
add_header Content-Type application/json;
}
# Serve box files with content type application/octet-stream
location ~ \.box$ {
add_header Content-Type application/octet-stream;
}
# Deny access to document root and the vagrant folder
location ~ ^/(vagrant/)?$ {
return 403;
}
}- Sym-link the vhost config to enable it
$ sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/000-example.com- Restart nginx and exit the webserver
$ service nginx restart
$ exitNow, that our boxes won't be stored any longer on the local filesystem, we have to change their locations in the box catalog.
- Open
~/VagrantBoxes/devops.jsonin your text editor and change the content to this:
{
"name": "devops",
"description": "This box contains Ubuntu 14.04.1 LTS 64-bit.",
"versions": [{
"version": "0.1.0",
"providers": [{
"name": "virtualbox",
"url": "http://www.example.com/vagrant/devops/boxes/devops_0.1.0.box",
"checksum_type": "sha1",
"checksum": "d3597dccfdc6953d0a6eff4a9e1903f44f72ab94"
}]
},{
"version": "0.1.1",
"providers": [{
"name": "virtualbox",
"url": "http://www.example.com/vagrant/devops/boxes/devops_0.1.1.box",
"checksum_type": "sha1",
"checksum": "0b530d05896cfa60a3da4243d03eccb924b572e2"
}]
}]
}- Upload this file to your webserver to directory
/var/www/vagrant/devops/.
If you open the URL http://www.example.com/vagrant/devops/ in your browser you should see your JSON box catalog.
- Upload both box files to your webserver to directory
/var/www/vagrant/devops/boxes/.
If you open the URL http://www.example.com/vagrant/devops/boxes/ in your browser you should see a directory listing with both box files listed.
- Change into the
~/VagrantTestdirectory on your host.
$ cd ~/VagrantTest- Open the
Vagrantfilefile in your text editor
# Change the line
config.vm.box_url = "file://~/VagrantBoxes/devops.json"
# to
config.vm.box_url = "http://www.example.com/vagrant/devops/"
# save the file- Bring up the machine
$ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Box 'devops' could not be found. Attempting to find and install...
default: Box Provider: virtualbox
default: Box Version: >= 0
==> default: Loading metadata for box 'http://www.example.com/vagrant/devops/'
default: URL: http://www.example.com/vagrant/devops/
==> default: Adding box 'devops' (v0.1.1) for provider: virtualbox
default: Downloading: http://www.example.com/vagrant/devops/boxes/devops_0.1.1.box
default: Calculating and comparing box checksum...
==> default: Successfully added box 'devops' (v0.1.1) for 'virtualbox'!
==> default: Importing base box 'devops'...
==> default: Matching MAC address for NAT networking...
==> default: Checking if box 'devops' is up to date...
==> default: Setting the name of the VM: VagrantTest_default_1406660957112_34972
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
default: Adapter 1: nat
==> default: Forwarding ports...
default: 22 => 2222 (adapter 1)
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
default: SSH address: 127.0.0.1:2222
default: SSH username: vagrant
default: SSH auth method: private key
default: Warning: Connection timeout. Retrying...
default: Warning: Remote connection disconnect. Retrying...
==> default: Machine booted and ready!
==> default: Checking for guest additions in VM...
==> default: Mounting shared folders...
default: /vagrant => ~/VagrantTestAnd here it is: Your own vagrant cloud!
- Please trigger fixes to this tutorial as an issue to this repo here on github
- For questions you can find me in the vagrant google group
- Thanks for reading, I hope this helps boosting your environment!