DEV Community

Mario García
Mario García

Posted on

A custom Vagrant box with Packer

Packer is an open source tool developed by Hashicorp for automating the creation of any type of machine image. You can use it for creating a custom Vagrant box for your development environment. That's what I will cover on this article.


You can get the installer for your operating system by going to If you're on Linux you can get it from the repositories of some distributions.

Check the Install Packer section for installation instructions of some Linux distros including Ubuntu/Debian, Centos/RHEL, Fedora and Amazon Linux.

Note: If you get the following error on Debian when trying to add the Hashicorp repository, just install the package software-properties-common.

sudo: apt-add-repository: command not found
Enter fullscreen mode Exit fullscreen mode
$ sudo apt-get install -y software-properties-common
Enter fullscreen mode Exit fullscreen mode

For Arch-based distributions, you can install Packer from the official repositories. Not to be confused with the packer package available from AUR, this is an old package manager for Arch.

Vagrant boxes

Packer uses JSON and HCL templates for knowing the instructions to execute for building images. HCL is the format recommended for Packer 1.7 or later but still has support for JSON templates.

You must create an HCL or JSON file following the naming convention recommended by Packer, file_name.pkr.json or file_name.pkr.hcl.

Don't forget to create a directory for storing the configuration files for Packer and Vagrant.

$ mkdir virtual-environment
$ cd virtual-environment
Enter fullscreen mode Exit fullscreen mode


Create a JSON file with the following content:

  "provisioners": [
      "type": "shell",
      "execute_command": "echo 'vagrant' | {{.Vars}} sudo -S -E bash '{{.Path}}'",
      "script": "scripts/"
  "builders": [
      "communicator": "ssh",
      "source_path": "ubuntu/focal64",
      "provider": "virtualbox",
      "add_force": true,
      "type": "vagrant"
Enter fullscreen mode Exit fullscreen mode

In the builders section:

  • communicator is set to ssh as Vagrant will access the virtual environment through an SSH connection.

  • ubuntu/focal64, assigned to source_path, is the base image that Packer will use during the building process.

  • The provider that Vagrant will use is VirtualBox.

  • add_force set to true is the same as using the --force flag when running any vagrant box instruction.

  • The builder type is set to vagrant for building a custom Vagrant box.

In the provisioners section:
Vagrant has support for shell scripts, Ansible, Chef or Puppet as provisioners.

If you're using a shell script for provisioning your environment you have to define the following variables in this section.

  • type set to shell for using shell scripts.

  • execute_command is the instruction that Packer will run for provisioning the environment.

  • The path of the script is set in the script variable.


If you're still using JSON templates, you can use the hcl2_upgrade command for converting from JSON to HCL.

If you want to convert the file from the previous example, just run:

packer hcl2_upgrade -output-file=file_name.pkr.hcl file_name.pkr.json
Enter fullscreen mode Exit fullscreen mode

The HCL template generated after running the above command will have the following content:

variable "version" {
  type    = string
  default = ""

locals { timestamp = regex_replace(timestamp(), "[- TZ:]", "") }

source "vagrant" "autogenerated_1" {
  add_force    = true
  communicator = "ssh"
  provider     = "virtualbox"
  source_path  = "ubuntu/focal64"

build {
  sources = ["source.vagrant.autogenerated_1"]

  provisioner "shell" {
    execute_command = "echo 'vagrant' | {{.Vars}} sudo -S -E bash '{{.Path}}'"
    script = "scripts/"
Enter fullscreen mode Exit fullscreen mode


Create a directory named scripts.

$ mkdir scripts
Enter fullscreen mode Exit fullscreen mode

Inside the scripts directory, create a shell script named that contains the instructions required for configuring the tools you need for your virtual environment.

You can use other provisioning tools like Ansible, Chef or Puppet but this time you will use a bash script.

For example, if you want to configure an environment for Python, your script will have the following content:

apt-get update
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

su - vagrant -c "curl | bash

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

curl -sSL | python3"
Enter fullscreen mode Exit fullscreen mode

Instructions in your shell script will be executed by the root user, that's why you don't need to run apt-get update or apt-get install with sudo.

For configuring tools like Poetry and pyenv you need to run installation and configuration instructions with the vagrant user, as this is the user you will log in with. In that case, run those instructions with su - vagrant -c.


Run packer build after creating the template for Packer:

$ packer build file_name.pkr.json
Enter fullscreen mode Exit fullscreen mode
$ packer build file_name.pkr.hcl
Enter fullscreen mode Exit fullscreen mode

The above command will create a directory named output-vagrant where you can find a file and a Vagrantfile.

You need the file for configuring your virtual environment with Vagrant.

Configuring Vagrant

After creating the custom Vagrant box, you have to configure the virtual environment with Vagrant.

Create a Vagrantfile:

$ vagrant init dev-env
Enter fullscreen mode Exit fullscreen mode

Where dev-env is the value assigned to the variable in the Vagrantfile. You can replace it according to your needs.

Add the file to Vagrant:

$ vagrant box add dev-env output-vagrant/
Enter fullscreen mode Exit fullscreen mode

Now your virtual environment is ready. You can initialize it and log in through SSH.

$ vagrant up
$ vagrant ssh
Enter fullscreen mode Exit fullscreen mode

You're ready to go!

Top comments (0)