Virtual Dev Environment with Vagrant + VBox on Linux
Tags: linux, tutorial
Published: 2020-08-09 03:48:35

On my computer I have an Arch-based distribution installed. These days I'm using EndeavourOS but I've used Arch Linux and Manjaro as well.

I have some virtual machines configured for when I have to test any software or configuration on another distro, especially when writing a blog post or preparing a talk/workshop.

The virtual machines that are up and running on my laptop includes the following:

* Arch Linux
* Debian
* Ubuntu
* Fedora
* CentOS

You can use Vagrant and VirtualBox to have your own virtual dev environments configured on your computer. Through this blog post you will learn how to install and configure both tools.

## VirtualBox
[VirtualBox](https://virtualbox.org) is one of the most popular virtualization software, developed by **Oracle**. It supports the following operating systems as host, according to the [documentation](https://www.virtualbox.org/manual/UserManual.html#hostossupport):

* Ubuntu 18.04 LTS, 19.03 and 19.10
* Debian GNU/Linux 9 ("Stretch") and 10 ("Buster")
* Oracle Linux 6, 7 and 8
* Red Hat Enterprise Linux 6, 7 and 8
* Fedora 30 and 31
* Gentoo Linux
* SUSE Linux Enterprise server 12 and 15
* openSUSE Leap 15.1

As well as any other distro based on Linux kernel 2.6, 3.x, 4.x or 5.x.

### Installation
For installing VirtualBox on your Linux distribution, go to the [download page](https://www.virtualbox.org/wiki/Linux_Downloads) and get the right package. There you will find packages for Oracle Linux, RHEL, CentOS, Ubuntu, Debian, openSUSE y Fedora.

If you want automatic updates, you can configure the package manager of your system with the Oracle repository.

#### Debian-based
Add the repository to `/etc/apt/sources.list`:

```bash
$ echo deb [arch=amd64] https://download.virtualbox.org/virtualbox/debian <mydist> contrib | sudo tee /etc/apt/sources.list.d/virtualbox.list
```

Where you must replace `<mydist>` with 'eoan', 'bionic', 'xenial', 'buster', 'stretch', or 'jessie'.

---

If you're using Debian 8 ("jessie") / Ubuntu 16.04 ("Xenial") and later, add the Oracle public key running:

```bash
$ wget -q https://www.virtualbox.org/download/oracle_vbox_2016.asc -O- | sudo apt-key add -
```

For older versions run the following command:

```bash
wget -q https://www.virtualbox.org/download/oracle_vbox.asc -O- | sudo apt-key add -
```

Note: It will probably give you the following error when trying to add the key:

```bash
E: gnupg, gnupg2 and gnupg1 do not seem to be installed, but one of them is required for this operation
```

If that's the case, install GnuPG:

```bash
$ sudo apt install gnupg2
```

---

For installing VirtualBox first update the list of packages in the repositories:

```bash
$ sudo apt update
```

Then install the latest version of VirtualBox which as of today is `6.1.12`:

```bash
$ sudo apt install virtualbox-6.1
```

#### RPM-based
On Fedora, add the repository by running the following command:

```bash
$ sudo dnf config-manager --add-repo https://download.virtualbox.org/virtualbox/rpm/fedora/virtualbox.repo
```

On CentOS:

```bash
$ sudo dnf config-manager --add-repo https://download.virtualbox.org/virtualbox/rpm/el/virtualbox.repo
```

---

After running one of the commands above update the list of packages in the repositories:

```bash
$ sudo dnf update
```

It will ask you if you want to import the Oracle public key, answer `y`:

```bash
Importing GPG key 0x98AB5139:
 Userid     : "Oracle Corporation (VirtualBox archive signing key) <info@virtualbox.org>"
 Fingerprint: 7B0F AB3A 13B9 0743 5925 D9C9 5442 2A4B 98AB 5139
 From       : https://www.virtualbox.org/download/oracle_vbox.asc
Is this ok [y/N]: y
```

---

Before installing VirtualBox make sure the dependencies are installed:

```bash
$ sudo dnf install gc make perl elfutils-libelf-devel kernel-devel
```

Then install VirtualBox:

```bash
$ sudo dnf install VirtualBox-6.1
```

#### Arch-based
On Arch-based distros you can install VirtualBox using `pacman` as it is available from the official repositories:

```bash
$ sudo pacman -S virtualbox
```

It will ask you to choose between one of two providers for `VIRTUALBOX-HOST-MODULES`, for the Linux kernel choose `virtualbox-host-modules-arch`

```bash
:: There are 2 providers available for VIRTUALBOX-HOST-MODULES:
:: Repository community
   1) virtualbox-host-dkms  2) virtualbox-host-modules-arch

Enter a number (default=1): 2
```

## Vagrant
[Vagrant](https://vagrantup.com) is a tool for building and managing virtual environments that works on top of VirtualBox, VMware, AWS and [other providers](https://www.vagrantup.com/docs/providers). You can install software on the virtual machines using [provisioning tools](https://www.vagrantup.com/docs/provisioning/) such as shell scripts, Chef, or Puppet.

Vagrant configures a virtual environment from base images known as "boxes" that you can start using as soon as the virtual machine is up and running.

Some Linux distributions that you can configure using Vagrant are:

* [Ubuntu](https://app.vagrantup.com/ubuntu)
* [Debian](https://app.vagrantup.com/debian)
* [Fedora](https://app.vagrantup.com/fedora)
* [CentOS](https://app.vagrantup.com/centos)
* [Arch Linux](https://app.vagrantup.com/archlinux)

You can find more boxes and the instructions for configuring them at:

* [app.vagrantup.com/boxes/search](https://app.vagrantup.com/boxes/search)
* [www.vagrantbox.es](https://www.vagrantbox.es/)

### Installation
For installing Vagrant go to the [download page](https://www.vagrantup.com/downloads) and get the right package for your distribution. You can also install it from the repositories of some Linux distributions.

#### Debian-based:

```bash
$ sudo apt install vagrant
```

#### Fedora:
 
```bash
$ sudo dnf install vagrant
```

#### CentOS

```bash
$ sudo dnf install -y https://releases.hashicorp.com/vagrant/2.2.9/vagrant_2.2.9_x86_64.rpm
```

#### Arch Linux:

```bash
$ sudo pacman -S vagrant
```

### Getting started
First create a directory where you can store the configuration for every virtual environment that you need to configure.

```bash
$ mkdir vagrant
```

#### Initial configuration
Once Vagrant is installed run `vagrant init` for creating a `Vagrantfile` that contains the initial configuration of the virtual environment.

The `Vagrantfile` will contain comments with additional information. If you want a file with just the lines needed to create and run your environment, run:

```bash
$ vagrant init --minimal
```

The `Vagrantfile` will have the following content and it will be easy to read and modify:

```ruby
Vagrant.configure("2") do |config|
  config.vm.box = "base"
end
```

Here's some `vagrant init` examples that you could try, don't forget to add the `--minimal` flag for a shorter `Vagrantfile`:

```bash
$ mkdir debian && cd debian
$ vagrant init debian/buster64
```

```bash
$ mkdir fedora && cd fedora
$ vagrant init fedora/32-cloud-base
```

```bash
$ mkdir centos && cd centos
$ vagrant init centos/8
```

```bash
$ mkdir archlinux && cd archlinux
$ vagrant init archlinux/archlinux
```

The commands above will configure Vagrant to download and run official boxes of Debian, Fedora, CentOS or Arch Linux.

#### Up and running
Once the `Vagrantfile` is created, run `vagrant up` for the virtual machine to be started.

Your virtual environment is up and running, now you can access through an SSH connection by running `vagrant ssh`. After that the prompt will look similar to:

```bash
Last login: Sun Aug  9 01:54:17 2020 from 10.0.2.2
[vagrant@localhost ~]$
```

#### Installing software
Once you logged in you can install the tools you need using the package manager or running the instructions needed.

You can also use provisioning tools like shell scripts, [Ansible](https://www.ansible.com/), [Chef](https://www.chef.io/) or [Puppet](https://github.com/puppetlabs/puppet).

Here's an example using a shell script:

If you want to configure a dev environment for Python and manage your project using pyenv and Poetry, create the script `install.sh` in the folder where the Vagrantfile was created and add the following content:

```bash
#!/usr/bin/env bash

sudo apt-get update
sudo apt-get install -y make build-essential libssl-dev zlib1g-dev libbz2-dev \
libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev \
xz-utils tk-dev libffi-dev liblzma-dev python-openssl git

curl https://pyenv.run | bash

echo 'export PATH="$HOME/.pyenv/bin:$PATH"' >> ~/.bashrc && \
echo 'eval "$(pyenv init -)"' >> ~/.bashrc && \
echo 'eval "$(pyenv virtualenv-init -)"' >> ~/.bashrc

curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python
```

Then edit the `Vagrantfile`:

```ruby
Vagrant.configure("2") do |config|
  config.vm.box = "debian/buster64"
  config.vm.provision :shell, path: "install.sh", privileged: false
end
```

After you run `vagrant up` Vagrant will start configuring your virtual environment and will run the instructions that you specified in the shell script.

#### Additional commands
To stop a virtual environment run:

```bash
$ vagrant halt
```

Every time you initialize your virtual environment with `vagrant up` it will check if there's a new version of the box available. If you update the box you will need to destroy the virtual environment configured with the previous version. Bear in mind that the configuration will not be moved to the new virtual machine.

If you still want to update, run:

```bash
$ vagrant box update
```

If you don't want Vagrant to check for updates, modify the `Vagrantfile` adding the following line after `config.vm.box`:

```ruby
config.vm.box_check_update = false
```

Run the following command if you have to destroy the environment and build it again:

```bash
vagrant destroy
```

If you want to delete the `.box` file downloaded the first time you ran `vagrant up`, run:

```bash
vagrant box remove debian/buster64
```

Replace `debian/buster64` with the name of the box that you're using.

## Notes
* You don't have to open VirtualBox as the virtual machine will be running in the background and will be accessed through an SSH connection.
* Whenever I try to update the system or install any package on Fedora, the command is stopped by the system. The solution I found was to assign 1 GB of RAM instead of 512 MB (assigned by Vagrant) To change the configuration modify the `Vagrantfile` as follows:

```bash
Vagrant.configure("2") do |config|
  config.vm.box = "fedora/32-cloud-base"
  config.vm.provider "virtualbox" do |vb|
    vb.memory = "1024" 
  end
end
```