About

This is a guide on Vagrant which covers most of what there is to known about it. If you’ve found other resources to be confusing, not going through all the steps, or not able to demystify how things work; then you may find this tutorial helpful.
In any case, if you just need a cheat sheet then jump into the Basics section.

What is Vagrant

Vagrant is a tool for deploying software environments in a configurable and reproducible form, from a single source configuration file. Whereas a software environment consists of one or more virtual machine or container instances; and most likely with network port forwarding and folder shares configured as well.
Its typical use case is the deployment of development and test environments. Because the VM deployment is reproducible it makes possible to have the same exact environment across multiple machines, thus eliminating the problems caused by differences in system configuration both across teams and infrastructure.
With a single command, vagrant up, it becomes possible to deploy a whole environment in just a few minutes.
Supported providers (ie: virtualization and containerization platforms) include: VirtualBox, VMWare, HyperV, Docker, KVM, AWS and others.
The provisioning (ie: installation and configuration of software into the instantiated guest system) can be done using one or more of the supported configuration management tools: shell scripts, Ansible, CFEngine, Chef, Docker, Puppet, Salt.
The Vagrant VM images are commonly referred as Vagrant boxes and they are provider specific. While an instantiated VM is referred as development environment.

Vagrant recipes used in this tutorial:
https://github.com/alexconst/vagrant_recipes

Understanding the magic

Vagrant acts as a wrapper around different providers (eg: VirtualBox) and provisioning tools (eg: Ansible), making the whole process:

  • easy: with just a couple of commands you can ssh into a new development environment;
  • simple: no need to configure any settings from each virtualization software;
  • uniform: it works the same way across multiple cloud providers and virtualization platforms (assuming Vagrant boxes are available for those providers); and
  • reproducible: you always get the same development environment when you start a new development environment.

The Vagrant boxes are created using Packer. And these consist on a tar file which include the virtualization software VM files (eg: .ovf, .vmdk) and a couple of Vagrant specific files.
The configuration of a development environment is done via a Vagrantfile. It includes settings for box selection, network port forwarding, shared folders, credentials, provisioning scripts, and other settings; for one or more machine instances.
When a new environment is created using vagrant up Vagrant loads a series of Vagrant files and merges and overrides the settings as it goes. The order being: the Vagrantfile packaged in the box, the Vagrantfile at ~/.vagrant.d/, the Vagrantfile for the current environment (this is the one that we’ll change most of the time), multi-machine overrides, and provider specific overrides.
Vagrant boxes are installed to ~/.vagrant.d/boxes/ while environments are created at each provider’s own default folder.
Vagrant then acts as a wrapper to the different virtualization software simplifying the whole process. For example, when vagrant up is executed it (if required) downloads a VM image, unpacks it, starts the VM, installs and configures software packages, and sets up the network and shared folders.
This means that with a Vagrantfile and the corresponding provisioning scripts it becomes possible to define a whole development environment consisting of one or more machines. With the advantage that the whole configuration can be easily shared and put under version control.

Security concerns
Vagrant development environments are insecure by default and by design. Since the typical use case is the local computer, Vagrant development environments exchange security for streamlined and easy access instead. If the Vagrant development environment is exposed to the outside world then:

  • create your own box,
  • with private credentials,
  • use secure SSH keypairs, and
  • disable password login for all users.

Installation and plugins

Download and install Vagrant from https://www.vagrantup.com/downloads.html.
Source code can be found at https://github.com/mitchellh/vagrant.

Vagrant ships with provider support for VirtualBox, Docker and HyperV.
Support for other providers can be done via plugins:

Other interesting plugins:

List of plugins: http://vagrant-lists.github.io/

Installing plugins:

1
2
3
4
5
vagrant plugin install vagrant-libvirt
vagrant plugin install vagrant-vmware-free
vagrant plugin install vagrant-aws
vagrant plugin list
vagrant plugin update

Plugins are downloaded from the ruby gems repository and are installed to $HOME/.vagrant.d/gems/gems/.

Using Vagrant

Basics

This section is a bit of a cheat sheet and characterizes a typical Vagrant workflow.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# check version
vagrant version

# select a box from Hashicorp's Atlas, eg: ubuntu/wily64
# FYI ubuntu/wily64 comes with VirtualBox guest tools installed,
# while debian/jessie64 instead uses rsync (which doesn't work so well)
boxname="ubuntu/wily64"

# if the box is not present in your box pool, then add it
vagrant box add $boxname
# check that it has been added
vagrant box list

# generate a Vagrantfile set to use given box
vagrant init $boxname

# deploy the vagrant box (ie: download if needed, unpack, and instantiate the box)
vagrant up
# if you have multiple providers for the same box then you'll need to specify which
# with $provider being one of 'virtualbox', 'vmware', 'aws', 'qemu', etc
vagrant up --provider $provider

# package the running VirtualBox environment into a re-usable box
# (tip: can be useful when looking to save provisioning time)
vagrant package --output "${newbox}.box"

# connect to the development environment
vagrant ssh

# get the status of existing environments for the local Vagrantfile
vagrant status

# get the status for all environments for all Vagrantfiles
# to make sure results are accurate add the --prune flag
# however it will take a lot! longer to show results
vagrant global-status

# show existing network port mappings
vagrant port

# suspend the development environment
vagrant suspend

# resume a previously suspended environment
vagrant resume

# delete the running development environment (use -f for no confirmation)
vagrant destroy

# remove a box
vagrant box remove $boxname

# get a list of available boxes
vagrant box list

Snapshots

Taking snapshots is simple, but there are a few caveats.
If you use push and pop it is not recommended to mix them with save and restore and delete.
Also some providers (VirtualBox included) require that when delete is used that all subsequent snapshots are deleted in the reverse order that they were taken.
So when using snapshots choose one and only one of the options:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# list existing snapshots
vagrant snapshot list

# option 1:
# take snapshot and push it onto the snapshot stack
vagrant snapshot push
# restore a snapshot and remove it from the snapshot stack
vagrant snapshot pop

# option 2:
# take a snapshot
vagrant snapshot save $snap_name
# restore a snapshot
vagrant snapshot restore $snap_name
# delete a snapshot
vagrant snapshot delete $snap_name

Your own environment

This section details how to add a local Vagrant box (that was created with Packer) and how to set up a development environment using a Vagrantfile. It goes through the most commonly used Vagrantfile settings.

Add a local Vagrant box to the pool of available boxes:

1
2
3
4
5
6
7
# select the box
boxfile="debian-802-jessie-amd64_jessie-vboxiso.box"
boxname="alexconst/debian/jessie64/20160115.0.3"
# add the box
vagrant box add  "${boxfile}"  --name "${boxname}"
# check that it has been added
vagrant box list

Note that there is a --box-version option to the box add command but that is only for remote clouds (eg: Hashicorp Atlas), so we workaround that limitation by adding the version tag to the box name. This “workaround” does give us visual identification, but doesn’t really provide the version constraint features of that command option.

Create a blank Vagrantfile:

1
vagrant init

Then to configure a new environment, that uses the new box, edit the Vagrantfile as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# select our box
config.vm.box = "alexconst/debian/jessie64/20160115.0.3"

# set credentials (only required if Vagrant's insecure keypair wasn't added during box creation)
config.ssh.username = "vagrant"
config.ssh.password = "vagrant"

# set hostname
config.vm.hostname = "vagrant-devbox"

# set text to be shown after 'vagrant up'
# this text can be useful for detailing instructions how to access the development environment
config.vm.post_up_message = "A Vagrant tutorial can be found at http://alexconst.github.io/"

# configure an additional shared folder
# by default the project dir is already shared at /vagrant/
host_folder = ENV['HOME'] + "/shared_vagrant"
guest_folder = "/shared/"
config.vm.synced_folder host_folder, guest_folder

# configure a private network using DHCP
# this will allows the VM to be accessible by the host and other guests within the same network
config.vm.network "private_network", type: "dhcp"

# alternatively it can also be configured to use a static IP, for example:
#config.vm.network "private_network", ip: "192.168.22.50"
# but make sure the 192.168.22.x network is not being already used (if so choose
# another network) and also make sure you don't set at IP ending in ".1" since
# that can cause problems

# configure the network: set up port forwarding for TCP
# accessing port 8080 on the host will be forwarded to port 80 on the guest
config.vm.network "forwarded_port", host: 8080, guest: 80

# configure the network: set up port forwarding for both UDP and TCP
config.vm.network "forwarded_port", host: 12003, guest: 2003, protocol: "tcp"
config.vm.network "forwarded_port", host: 12003, guest: 2003, protocol: "udp"

# provision by copying a file or directory to the guest machine
config.vm.provision "file", source: "files/mydata.tar.gz", destination: "/tmp/mydata.tar.gz"
# provision by executing a command on the guest
config.vm.provision "shell", inline: "tar -xzf /tmp/mydata.tar.gz"
# provision by uploading a script and executing it (path can be an URL)
config.vm.provision "shell", path: "scripts/packages.sh"

Our use case matches the default scenario where the guest is Linux and communication is done via ssh. But Vagrant also supports Windows guest where communication is done via winrm.
Vagrant also supports synced folders via different implementations: NFS (Linux only), Samba (Windows only), rsync, and the provider’s own mechanism (eg: VirtualBox shared folders). However these are not perfect; do check the Known issues section for more information.
Regarding rsync, it does a one-time one-way (from host to guest) folder synchronization on vagrant up, vagrant reload and vagrant rsync. There is also vagrant rsync-auto which runs in the foreground listening to events on the local filesystem before it does a folder sync; however this command has a few caveats.

To instantiate a new environment using our box and connect to it:

1
2
vagrant up
vagrant ssh

DevEnv 1: Blog in a box

Here we’ll see how to set up a development environment ready for blogging by installing the GitHub Pages gem (which uses a specific version of Jekyll).
This way we’ll have an environment that matches the GitHub Pages website blogging backend and so we’ll be able to preview our posts just as they’ll be shown on the GitHub website.

The Vagrantfile:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure(2) do |config|

  # Choose a box with VBox guest tools already installed and a Ruby version
  # compatible with GitHub Pages and Jekyll.
  config.vm.box = "ubuntu/wily64"

  # Set up hostname
  config.vm.hostname = "jekyll"

  # Message shown on vagrant up
  config.vm.post_up_message = "
Blog in a box! GitHub Pages (Jekyll powered) compatible environment.
Simply cd to the blog directory and type:
    pkill jekyll ; jekyll build  && jekyll serve

A Vagrant tutorial can be found at http://alexconst.github.io/"


  # Create a forwarded port mapping for Jekyll
  config.vm.network "forwarded_port", guest: 4000, host: 4000

  # Share an additional folder with the guest VM.
  # This folder should have our blog files.
  host_folder = ENV['HOME'] + "/home/downloads/share_vagrant"
  guest_folder = "/shared/"
  config.vm.synced_folder host_folder, guest_folder

  # Fine tune the virtualbox VM
  # We could get away with 256MB if Chef and Puppet agents weren't installed,
  # which eat a total of 100 MiB of RAM (~ 50 MiB each). Update: no we wouldn't
  # because 384 MB may not be enough for building the GitHub pages gem. It may
  # complain with "ERROR: Failed to build gem native extension. ... Cannot allocate memory"
  # Set 2 virtual CPUs, each can use up to 50% of a single host CPU.
  config.vm.provider "virtualbox" do |vb|
    vb.customize [
      "modifyvm", :id,
      "--cpus", "2",
      "--cpuexecutioncap", "50",
      "--memory", "512",
    ]
  end

  # fix annoyance, http://foo-o-rama.com/vagrant--stdin-is-not-a-tty--fix.html
  config.vm.provision "fix-no-tty", type: "shell" do |s|
    s.privileged = false
    s.inline = "sudo sed -i '/tty/!s/mesg n/tty -s \\&\\& mesg n/' /root/.profile"
  end
  # fix annoyance, http://serverfault.com/questions/500764/dpkg-reconfigure-unable-to-re-open-stdin-no-file-or-directory
  config.vm.provision "shell", inline: "echo 'export DEBIAN_FRONTEND=noninteractive' >> /root/.profile"
  config.vm.provision "shell", inline: "for user in /home/*; do echo 'export DEBIAN_FRONTEND=noninteractive' >> $user/.profile; done"


  # provisioning using shell scripts
  config.vm.provision "shell", path: "scripts/jekyll.sh"

end

And the provisioning script:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/bin/bash

apt-get update
# install htop because we can
apt-get install -y htop
# dependencies for github-pages
apt-get install -y ruby-dev bundler zlib1g-dev ruby-execjs --no-install-recommends
# dependencies for the pygments syntax highlighter
apt-get install -y python-pygments
# There is a bug which forces us to explicitly install activesupport, which
# would otherwise be done by the github-pages gem.
# https://github.com/github/pages-gem/issues/181
gem install activesupport
gem install github-pages
apt-get clean

To get jekyll running:

1
2
3
4
5
6
7
8
9
10
11
12
# deploy and connect to the environment
vagrant up
vagrant ssh

# if you don't have a site yet:
cd /shared/
jekyll new myblog
# if you already have one then:
cd $to_directory_with_your_blog

# start jekyll webserver
pkill jekyll ; jekyll build  && jekyll serve

DevEnv 1.1: Using Ansible

Here we create the same GitHub Pages & Jekyll environment. But instead of using shell scripts for provisioning we’ll use Ansible (for more information about it check my tutorial).

Install Ansible on your host machine:

http://docs.ansible.com/ansible/intro_installation.html#installing-the-control-machine

NOTE: we are not setting an inventory file (which is basically a list of hosts) here since Vagrant will take care of it for us dynamically.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# install Ansible from source
cd /usr/local/src
git clone git://github.com/ansible/ansible.git --recursive

# install dependencies
sudo pip install paramiko PyYAML Jinja2 httplib2 six

alias setupansible='source /usr/local/src/ansible/hacking/env-setup'

# to use ansible
setupansible

# to update Ansible
cd /usr/local/src/ansible
git pull --rebase
git submodule update --init --recursive

Edit the Vagrantfile to have the provisioning done using Ansible:

1
2
3
config.vm.provision "ansible" do |ansible|
  ansible.playbook = "ansible/playbook.yml"
end

Create the ansible/playbook.yml playbook:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
---
# This playbook only has one play
# And it applies to all hosts in the inventory file (which is dynamically
# created by Vagrant)
- hosts: all
  # we need priviledge escalation to install software, so we become root
  become: yes
  # and we become root using sudo
  become_method: sudo
  # to perform the following tasks:
  # (and tasks should always have a name)
  tasks:
    - name: Update package listing cache
      # use the Ansible apt module to:
      # update package list, but don't upgrade the system
      apt: update_cache=yes upgrade=no cache_valid_time=1800

    - name: Install packages required by GitHub Pages
      # use the Ansible apt module to:
      # install the listed packages to the latest available version
      apt: pkg={{item}} state=latest install_recommends=no
      with_items:
        - htop
        - ruby-dev
        - bundler
        - zlib1g-dev
        - ruby-execjs
        - python-pygments

    - name: Install the GitHub Pages Ruby gem
      # use the Ansible gem module to:
      # install the listed Ruby gems to the latest available version for all users
      gem: name={{item}} state=latest user_install=no
      with_items:
        - activesupport
        - github-pages

Deploy the environment:

1
2
setupansible
vagrant up

DevEnv 2: AWS environment

The AWS provider is supported via the vagrant-aws plugin, which supports several AWS settings, so you may want to take a look at the README for any specific settings that you may need. However there are two caveats to it:
1) synced folders are supported via rsync (subject to rsync own limitations).
2) AWS credentials files are not supported. I have submitted a PR for the vagrant-aws plugin that adds support for AWS config and credential files, but until it gets (or if it gets) approved we’re stuck either using environment variables or leaking credentials to the Vagrantfile.2
This section shows a simple use case of the plugin.

AWS needs a dummy box so let us start by adding it:

1
2
3
4
# install the dummy AWS box
vagrant box add dummy https://github.com/mitchellh/vagrant-aws/raw/master/dummy.box
# create Vagrantfile
vagrant init dummy

Then adapt the following Vagrantfile with your credentials:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure(2) do |config|
  # AWS dummy box
  config.vm.box = "dummy"

  config.vm.provider :aws do |aws, override|
    # configure your credentials and select your region
    aws.access_key_id = "YOUR KEY"
    aws.secret_access_key = "YOUR SECRET KEY"
    # the token is only needed if you're using one
    #aws.session_token = "YOUR SESSION TOKEN"
    aws.region = "YOUR REGION"

    aws.ami = "ami-e31a6594"
    # this username must exist in the specified aws.ami
    override.ssh.username = "admin"
    aws.instance_type = "t2.micro"
    # if your default SG does not allow for SSH then you need to specify it here
    #aws.security_groups = ['YOUR SG ALLOWING SSH']

    # set the keypair name that will be used (name as shown in AWS)
    aws.keypair_name = "KEYPAIR NAME"
    # the credential file should be the one for the aws.keypair_name
    override.ssh.private_key_path = ENV['HOME'] + "/.ssh/" + "YOUR PRIVATE KEYFILE"
  end

end

Then to start the development environment and connect to it:

1
2
vagrant up --provider=aws
vagrant ssh

DevEnv 3: Multi-Machine environment

This is a mock example of a multi-machine environment. For a more realistic example, with complete provisioning, check this Ansible tutorial.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure(2) do |config|

  # Choose a box
  config.vm.box = "ubuntu/wily64"

  # Fine tune the virtualbox VM
  config.vm.provider "virtualbox" do |vb|
    vb.customize [
      "modifyvm", :id,
      "--cpus", "2",
      "--cpuexecutioncap", "50",
      "--memory", "384",
    ]
  end

  # Common provisioning
  config.vm.provision :shell, inline: 'echo "Hello World"'

  # web servers
  (1..2).each do |i|
    config.vm.define "web#{i}" do |node|
      node.vm.hostname = "web#{i}"
      node.vm.network :private_network, ip: "192.168.33.5#{i}"
      node.vm.network "forwarded_port", guest: 80, host: "808#{i}"
      # web server specific provisioning
      node.vm.provision :shell, inline: 'echo "Web server reporting for duty."'
    end
  end

  # db server
  config.vm.define "db" do |db|
    db.vm.hostname = "db"
    db.vm.network :private_network, ip: "192.168.33.40"
    db.vm.network "forwarded_port", guest: 5432, host: "54322"
    # db server specific provisioning
    db.vm.provision :shell, inline: 'echo "DB server ready to store and serve."'
  end

end

Because the Vagrantfile is a valid Ruby file it’s possible to define a group of machines using the language constructs. Here the web servers are iterated and configured using the node object.
The settings applied to the config object (eg: config.vm.box) affect all the machines described in the Vagrantfile. While the settings applied to the node and db objects only affect the corresponding machines. This will become apparent when doing vagrant up due to the specified shell provisioning echo commands.

To use the environment:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# check status for all machines in the environment
vagrant status

# deploy the environment
vagrant up
# or just a single machine
vagrant up web1

# to connect to web1
vagrant ssh web1
# and since the machines are in a private network, you can connect from web1 to web2
ssh 192.168.33.52

# to destroy all machines in the environment without prompting the user
vagrant destroy -f

Finally, one important thing to be aware of when using these inner config objects, is how they are evaluated/executed. Vagrant enforces an outside-in ordering, which means that “nesting level” has priority over “line location”. Taking this example from the manual3:

1
2
3
4
5
6
7
Vagrant.configure("2") do |config|
    config.vm.provision :shell, inline: "echo A"
    config.vm.define :testing do |test|
        test.vm.provision :shell, inline: "echo B"
    end
    config.vm.provision :shell, inline: "echo C"
end

The outside-in ordering means the provisioners will first output “A”, then “C”, and finally “B”. Which is counter-intuitive to what someone would expect.

Other features

This tutorial covers most of what there is to know about Vagrant and its workflow. However, there are some other features which were not discussed but are worthwhile to be aware of. These are:

  • Box catalogs
    Hashicorp provides a public repository for their own boxes4, as well as third party boxes. For private boxes you can either subscribe to Hashicorp’s Atlas service, or roll up your sleeves and set up your own box repository5.

  • Certificates
    To make the box download process secure use the appropriate Vagrantfile config.vm settings to specify which certificates to use and which checksums to perform.

  • Share and connect
    Vagrant, by means of the Hashicorp Atlas website, makes possible to share a development environment to anyone on the internet.

  • Public networks
    With the config.vm.network it is possible to define private and as mentioned in the manual less private networks (which will likely be replaced by bridged networks in the future). While private networks were covered, public networks were not.

  • Provider specific settings
    Vagrant allows configuring additional provider specific settings as well as overriding existing settings using the config.vm.provider option6. These vary according to the provider but can include options for: choosing between headless/GUI mode, using linked clones, customizing the virtual hardware devices, set limits on processing power used, networking, etc. Some of VirtualBox specific settings7 were used in the Vagrantfile for the GitHub Pages environment, but there are many more.

  • SSH settings
    On the scenario described in this tutorial only the SSH credentials needed to be provided. But Vagrant allows configuring several other SSH related settings, such as: guest domain/IP, guest port, private key, agent forward8, X11 forward, environment forward, pty, shell and sudo settings9.

Known issues

Related to synced folders:

  • VirtualBox shared folders has a bug related to the sendfile syscall that webservers typically use to serve static files. There is workaround for web servers10 but the bug is still present (5 years and counting)11 and therefore may manifest itself with other software. A safer approach may be switching to NFS.
  • Performance issues may also arise with VirtualBox shared folders: “In some cases the default shared folder implementations (such as VirtualBox shared folders) have high performance penalties. If you’re seeing less than ideal performance with synced folders, NFS can offer a solution.”12
  • Vagrant supports different synced folders implementations. However support for symbolic links is inconsistent, so it is better throughly test them beforehand or to avoid them altogether.

Debugging and tips

  • Whenever the Vagrantfile is updated changes will only be applied after a vagrant reload or vagrant up.

  • When implementing the provisioning modules for an environment there a few commands that can help speeding up the process and troubleshooting problems:
    • both vagrant provision and vagrant reload --provision will execute the provisioning steps on a running environment.
    • vagrant snapshot push and vagrant snapshot pop for reverting undesired changes.
    • vagrant ssh -c $your_cmd_here will execute the provided command.
  • If no SSH keypair was added during the creation process of a Vagrant box, or there isn’t a vagrant user, then it’s necessary to configure the config.ssh.username and config.ssh.password settings with valid credentials.

  • To connect to a development environment directly without going through Vagrant: ssh -p $(vagrant port --guest 22) -l $box_username localhost.

  • To enable logging:

    1
    2
    # supported levels are: debug, info, warn, error
    export VAGRANT_LOG="debug"
    
  • To run the latest version of Vagrant or any of its plugins from GitHub’s master branch (which BTW is not recommended), then clone the repo and then use bundle to run vagrant. Check the vagrant_dev-wily64-atlas recipe for more details, but it would go something like this:

    1
    2
    3
    4
    git clone git@github.com:alexconst/vagrant-aws.git
    cd vagrant-aws
    bundle exec vagrant version
    bundle exec vagrant $your_commands
    

Troubleshooting

  • failure when installing the vagrant-libvirt plugin
    TRIGGER: vagrant plugin install vagrant-libvirt
    ERROR: Make sure that gem install ruby-libvirt -v '0.6.0' succeeds before bundling.
    PROBLEM: you’re probably missing both libvirt-dev and the ruby-libvirt gem
    SOLUTION: apt-get install libvirt-dev and then gem install ruby-libvirt -v '0.6.0'

  • failure when adding a new box
    ERROR:

    1
    /opt/vagrant/embedded/lib/ruby/2.2.0/fileutils.rb:252:in 'mkdir': File name too long @ dir_s_mkdir - /home/$USER/.vagrant.d/boxes/file:-VAGRANTSLASH--VAGRANTSLASH--VAGRANTSLASH-...-VAGRANTSLASH-debian-802-jessie-amd64_jessie-vboxiso.box (Errno::ENAMETOOLONG)
    

    SOLUTION: cd into the directory with the box file and run the vagrant box add command from there refering directly to the filename (ie: no path)

  • non-fatal error message about stdin and tty
    ERROR: stdin: is not a tty
    REFERENCES:
    http://foo-o-rama.com/vagrant–stdin-is-not-a-tty–fix.html
    https://github.com/Varying-Vagrant-Vagrants/VVV/issues/517
    https://github.com/mitchellh/vagrant/issues/1673
    SOLUTION: add the following as the first provisioner:

    1
    2
    3
    4
    config.vm.provision "fix-no-tty", type: "shell" do |s|
    s.privileged = false
    s.inline = "sudo sed -i '/tty/!s/mesg n/tty -s \\&\\& mesg n/' /root/.profile"
    end
    
  • non-fatal error message about stdin when using apt
    ERROR: dpkg-preconfigure: unable to re-open stdin: No such file or directory
    REFERENCES:
    http://serverfault.com/questions/500764/dpkg-reconfigure-unable-to-re-open-stdin-no-file-or-directory
    SOLUTION 1: prepend the following line to any script with apt-get calls:

    1
    export DEBIAN_FRONTEND=noninteractive
    

    SOLUTION 2: add the following lines before running other provisioners that use apt

    1
    2
    config.vm.provision "shell", inline: "echo 'export DEBIAN_FRONTEND=noninteractive' >> /root/.profile"
    config.vm.provision "shell", inline: "for user in /home/*; do echo 'export DEBIAN_FRONTEND=noninteractive' >> $user/.profile; done"
    
  • unable to access the guest directly via SSH when using a private network
    NOTE: failure to connect to the guest via SSH may be due to sshd configuration issues. If you can ping the machine and telnet to the SSH port, then the private network is working. If still not convinced yet, then install lighttpd and access port 80 from the host. Make sure you’re using the correct IP and port. Example:

    1
    2
    3
    ssh vagrant@$private_network_ip
    # example:
    ssh vagrant@192.168.22.50
    

    If /etc/ssh/sshd_config has PasswordAuthentication no then you’ll have to use a command similar to this one:

    1
    ssh -i ./.vagrant/machines/default/virtualbox/private_key vagrant@192.168.22.50
    

Footnotes