Automate your virtual lab environment with Ansible and Vagrant

If you’re studying for your IT certifications, do technical research, or develop software you often need to set up a virtual lab environment. Therefore, I lately created an article about how to automate the creation and provisioning process of virtual machines with Vagrant. And I also created an article on how to automate all your Linux servers with Ansible. In this article, we’re combining those two amazing technologies. And I show you how you can easily automate a full lab environment containing multiple virtual machines.

How to use Vagrant with Ansible on Windows 10

If you’re running Vagrant on Linux, you can skip this part. But if you’re running Vagrant on Windows with VirtualBox or Hyper-V, you have a problem. Because Ansible is not running on Windows, you will need to run Vagrant with Ansible scripts on a Linux machine. Luckily, you can do this pretty easily with the Windows Subsystem for Linux (WSL2). Because the trick is to install Vagrant on your WSL machine and on your Windows 10, too. Note, that it needs to be installed exactly in the same version and it’s still considered a beta version at this time.

To install Vagrant on WSL just simply download the latest version at


sudo apt install ./vagrant_2.2.10_x86_64.deb

Next, you need to add a few environment variables according to If you’re running bash, simply add them to your .bashrc file. On zsh you need to place them in your .zshrc file.


On Windows 10 with Hyper-V, set the default provider with the following environment variable.


Check if Vagrant is running on your WSL2 and can communicate to the Hypervisor on your Windows 10 by executing the vagrant command. If and error shows up, you probably haven’t loaded the environment variables correctly.

Install Ansible:

sudo apt-add-repository ppa:ansible/ansible

sudo apt update

sudo apt install ansible

Prepare the Vagrantfile to automate the virtual machine creation

Now let’s start with the creation of our Vagrantfile. If you’re not familiar with Vagrant yet, you should check out my tutorial about Vagrant, to learn the fundamentals. When you’re running Vagrant with VirtualBox, the configuration will look slightly different, because I’m using Hyper-V as my default provider. Any Virtualbox fans can just comment out the HyperV subconfiguration part.


# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.configure("2") do |config|
  config.vm.define "master" do |subconfig| = "generic/ubuntu2004"
    subconfig.vm.hostname = "master"
    subconfig.vm.provider "hyperv" "public_network", bridge: "BRIDGE"

    subconfig.vm.provider "hyperv" do |h|
      h.enable_virtualization_extensions = false
      h.linked_clone = false
      h.vmname = "ubuntu_cluster_master"

    subconfig.vm.provision "ansible" do |a|
      a.verbose = "v"
      a.playbook = "master_playbook.yaml"

If you later want to add more than one virtual machine, it’s useful to create a sub config for every single machine.

config.vm.define "master" do |subconfig|

We can automatically attach our virtual machine(s) to a virtual switch in Hyper-V with the following statement. Because the “BRIDGE” Interface is the name of my virtual switch that connects the virtual machine to my physical network adapter. "public_network", bridge: "BRIDGE"

This h configuration is part of the provider-specific configuration of the Hyper-V on Windows 10. For more information check out this blogpost.

    subconfig.vm.provider "hyperv" do |h|
      h.enable_virtualization_extensions = false
      h.linked_clone = false
      h.vmname = "ubuntu_cluster_master"

Now we will create another subconfiguration to provision the machine with an ansible-playbook. This will contain all ansible instructions to provision our virtual machine. Vagrant automatically executes the ansible-playbook once the virtual machine is created the first time.

    subconfig.vm.provision "ansible" do |a|
      a.verbose = "v"
      a.playbook = "master_playbook.yaml"

Create Ansible playbooks to provision the virtual machines

Now, we need to create your ansible-playbook that is used to provision our virtual machine. I’ve created an example of a playbook that will automatically install Docker. Of course, you can simply change the playbook to whatever your need is. By the way, you find useful examples on my GitHub repository ansible-boilerplates. Of course, you can simply use and modify them in a variety of different setups.

Because Vagrant completely handles the provisioning and authentication part, you don’t need to enter any passwords or public SSH keys.

- hosts: all
    become: yes
    - name: install prerequisites
        - apt-transport-https
        - ca-certificates 
        - curl 
        - gnupg-agent
        - software-properties-common
    - name: add apt-key
    - name: add docker repo
        repo: deb focal stable
    - name: install docker 
        - docker-ce
        - docker-ce-cli
        update_cache: yes
    - name: add userpermissions
    shell: "usermod -aG docker vagrant"

Start the virtual lab environment

Now, start the virtual lab environment. Just execute “vagrant up”, and Vagrant will create the virtual machine, install the box image, and provision it with the ansible-playbook. After that, you should see that all tasks are applied.

Let’s check if we’re able to log in to our virtual machine. To log in to a remote shell simply type in “vagrant ssh”. Then execute the command “docker –version”, to check if you’re able to execute any docker commands. Because if everything was successful, you will get the version number of docker.

5 thoughts on “Automate your virtual lab environment with Ansible and Vagrant”

  1. Thanks for great write up, I am trying to reproduce the same setup with Vagrant 2.2.14, however I have ran into an issue where running the Vagrant from Linux Volume e.g ~/vagrant ends up with error:
    Get-ACL : Method failed with unexpected error code 1.
    At \\wsl$\Ubuntu-20.04\opt\vagrant\embedded\gems\2.2.14\gems\vagrant-2.2.14\plugins\providers\hyperv\scripts\utils\VagrantVM\
    m1:731 char:12
    + $acl = Get-ACL -Path $Path

    When I move the files to Windows volume e.g. /mnt/c/… I can get it started but Ansible Gathering Facts tasks will complain about Private Key permissions (0777) since it is now located in Windows side. and the play with end up with unreachable error.

    Have you found a workaround for that?

      • Had the same on my Windows 10 21H2 machine today.
        I have changed 2 things to fix this:

        1) remount C: with metadata option by first unmounting:
        > umount /mnt/c
        > sudo mount -t drvfs C: /mnt/c -o metadata

        After this from within WSL it is possible to chmod to /mnt/c files

        However, after doing this, i stumped upon a problem that Vagrant almost immediately stops after vagrant up command with some vague message that permissions on key can not be set.
        I found on the following github page a solution to this:

        I have edited /opt/vagrant/embedded/gems/2.2.19/gems/vagrant-2.2.19/lib/vagrant/environment.rb which checks if permission on private key is not equal to 600 and then it will set it to 0600 (which fails). I have changed the line:

        if Util::FileMode.from_octal(@default_private_key_path.stat.mode) != “600”
        if Util::FileMode.from_octal(@default_private_key_path.stat.mode) = “600”

        then the check will skip this and the ansible playbook will finish.

        Guess it may even be better to completely comment out this if statement up until the end from this if to just skip the check in any case.

        Later I read in the same github page that it may have also been fixed by running Restart-Service LxssManager in Powershell with admin privilege, however I haven’t tried this anymore. This would be the better option.

  2. It is more effective if you add the variables as follows:

    export PATH=$PATH:/mnt/c/Windows/System32
    export PATH=”$PATH:/mnt/c/ProgramData/Microsoft/Windows/Hyper-V”

  3. Great Tutorial, using everything from a Linux-System as my primary host OS which makes stuff even easier 🙂

    Now will try your guide and adapt it to VMware for a remote ESXi-Host.

    Thanks for the guide!


Leave a Comment

I accept the Privacy Policy