You can use the plethora of Vagrant Boxes available online, but there are times that you want/need to create your own Vagrant Box, based on specific requirements, with specific packages and most importantly with a specific ssh key pair.

In this guide I will walk through the process of creating a Vagrant BOX from scratch. I will be using a Mac with VMware Fusion and my Vagrant Box will be based on RHEL/CentOS.

1)Create a kickstart configuration file that you will use to automate the installation.
You can do it manually but I prefer/recommend using a kickstart file because you are software-defining the resulting machine and you can source control it. I placed the kickstart on a web server, in this case in my own Mac system so that it is reachable by the VM during installation.

Pre-requisites:
root password:
You can use the password ‘vagrant‘ as is on the kickstart, or you can provide the SHA512 hash of the root password you want. You can do this in several ways from a Linux terminal

mkpasswd -m sha-512
OR
python -c 'import crypt; print crypt.crypt("password", "$6$somesalt$")'

//You then place this hash in the kickstart below, for example:
// rootpw  --iscrypted $6$AcXXXXXX$ZfE9iCSvnezqs3/t47dcPRxozcWACkdITx38T.oTMESLzVv8yjSm1pVE4JC5FmdGojpg8StRhfi.peduXXXXX

SSH key pair:
You need to create a key pair that you will use for Vagrant. The way it works is that the generated public key will be added to the authorized keys allowed to ssh as the user ‘vagrant’ in the custom Vagrant BOX while the vagrant software on the host(Mac) will use the private key to connect from the host(Mac) to the Vagrant BOX(vm)
You can create the ssh key pair as follows:

ssh-keygen -t rsa -C "Vagrant" -f 'vagrant_rsa'

// You then place the contents of vagrant_rsa.pub on the kickstart below, replacing the XXXX.....'s

Once you have the password and SSH keys, you can use the below kickstart (replacing the password and SSH public key accordingly)

# ks.cfg

install
cdrom
text
lang en_US.UTF-8
keyboard us
network --onboot yes --device eth0 --bootproto dhcp --noipv6
rootpw  vagrant
firewall --disabled
authconfig --enableshadow --passalgo=sha512
selinux --disabled
timezone --utc America/New_York
bootloader --location=mbr --driveorder=sda --append="crashkernel=auto"
zerombr
clearpart --initlabel --drives=sda --all
part /boot --fstype=ext4 --size=500
part pv.100 --grow --size=1
volgroup vg0 --pesize=4096 pv.100
logvol swap --name=lv_swap --vgname=vg0 --size=2048
logvol / --fstype=ext4 --name=lv_root --vgname=vg0 --grow --size=1024
poweroff

## Install needed software (this is for ESX5/Fusion5 compatibility)
repo  --name=vmware-tools-collection   --baseurl=http://packages.vmware.com/tools/esx/5.0u3/rhel6/x86_64

%packages --nobase
@core
vmware-tools-hgfs
vmware-tools-esx-nox
openssh-clients
%end

%post
############################### BEGIN post-kickstart actions

# See: https://www.kernel.org/pub/linux/utils/kernel/hotplug/udev/udev.html
/bin/rm -f /etc/udev/rules.d/70-persistent-net.rules
/bin/ln -s /dev/null /etc/udev/rules.d/70-persistent-net.rules
/bin/rm -rf /dev/.udev/
/bin/rm /lib/udev/rules.d/75-persistent-net-generator.rules

# Clean hardcoded MAC address
/bin/sed -i -e 's/^HWADDR=.*$//' -e 's/^UUID=.*$//' /etc/sysconfig/network-scripts/ifcfg-eth0

# Make boot verbose
/bin/sed -i -e 's/^splash/#splash/' -e 's/^hidden/#hidden/' -e 's/rhgb//' -e 's/quiet//' /boot/grub/grub.conf

# Remove screensaver/blank screen 
/bin/sed -i -r s/"(^[\t]*kernel.*)"/"\1 consoleblank=0"/ /boot/grub/grub.conf 

### BEGIN: Vagrant specific pre-requisites ###
# Enable vmhgfs
/bin/echo "modprobe vmhgfs" > /etc/sysconfig/modules/vmhgfs.modules
/bin/chmod +x /etc/sysconfig/modules/vmhgfs.modules

# Create vagrant user
/usr/sbin/useradd vagrant
/bin/mkdir /home/vagrant/.ssh
/bin/chmod 700 /home/vagrant/.ssh
cat >           /home/vagrant/.ssh/authorized_keys <<'VAGRANT_RSA'
ssh-rsa XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX vagrant
VAGRANT_RSA

/bin/chmod 600 /home/vagrant/.ssh/authorized_keys
/bin/chown -R vagrant /home/vagrant/.ssh

## Allow vagrant user to sudo
/bin/sed -i -e 's/Defaults[[:space:]]*requiretty/###Allow vagrant user to sudo\nvagrant ALL=(ALL:ALL) NOPASSWD:ALL\nDefaults requiretty\nDefaults:vagrant !requiretty/' /etc/sudoers 
### END: Vagrant specific pre-requisites ###

# Clean yum stuff to make resulting machine leaner
yum clean all

############################### END post-kickstart actions

%end

2) Creating the custom VM

Add new VM
vm_create_new

Continue without Disc

vm_continuewithout_cd

Create a custom virtual machine
vm_create_custom

Choose RHEL6_64
vm_os_choice

Click on Customize settings
vm_customize_settings

 

Select 1CPU and 1GB of RAM (The VM should be as minimal as possible, you can increase CPU and RAM from Vagrant)
cpu_ram

 

Disable unnecessary stuff (print sharing, bluetooth, sound card)
disable_bluetooth

disable_printsharing

disable_sound

 

3) Start installation

Boot VM and add the RHEL/CentOS ISO disk (Choose Disc or Disc Image...)
connect_cd

Point to the kickstart file served by the web server
rhel_bootscreen2box

Installation will proceed and the VM will be powered off (based on the kickstart 'poweroff' option)

4) Once VM is off Disable CD drive
disable_cd

5) Quit VMware Fusion (this is to clear the lock files so that you have a pristine VM)

 

6) Difragment and Shrink the VMDK

john@mac:~$ /Applications/VMware\ Fusion.app/Contents/Library/vmware-vdiskmanager -d ~/Documents/Virtual\ Machines.localized/vagrant_rhel6_64.vmwarevm/Virtual\ Disk.vmdk
Defragment: 100% done.

john@mac:~$ /Applications/VMware\ Fusion.app/Contents/Library/vmware-vdiskmanager -k ~/Documents/Virtual\ Machines.localized/vagrant_rhel6_64.vmwarevm/Virtual\ Disk.vmdk
Shrink: 100% done.
Shrink completed successfully.

 

7) On the folder where the virtual machine was created, create the following metadata.json file:

john@mac:~/Documents/Virtual Machines.localized/vagrant_rhel6_64.vmwarevm $ printf "{\n\t\"provider\":\"vmware_desktop\"\n}\n" > metadata.json
john@mac:~/Documents/Virtual Machines.localized/vagrant_rhel6_64.vmwarevm $ cat metadata.json
{
"provider":"vmware_desktop"
}

8) Create the Vagrant box container

john@mac:~/Documents/Virtual Machines.localized/vagrant_rhel6_64.vmwarevm $ tar cvzf vagrant-rhel6.box ./*
a ./Virtual Disk-s001.vmdk
a ./Virtual Disk-s002.vmdk
a ./Virtual Disk-s003.vmdk
a ./Virtual Disk-s004.vmdk
a ./Virtual Disk-s005.vmdk
a ./Virtual Disk-s006.vmdk
a ./Virtual Disk-s007.vmdk
a ./Virtual Disk-s008.vmdk
a ./Virtual Disk-s009.vmdk
a ./Virtual Disk-s010.vmdk
a ./Virtual Disk-s011.vmdk
a ./Virtual Disk.vmdk
a ./metadata.json
a ./vagrant_rhel6_64.nvram
a ./vagrant_rhel6_64.plist
a ./vagrant_rhel6_64.vmsd
a ./vagrant_rhel6_64.vmx
a ./vagrant_rhel6_64.vmxf
a ./vmware.log

9) Add the Box to Vagrant

john@mac:~$ vagrant box add -name vagrant-rhel6 ~/Documents/workspace/vagrant/boxes/vagrant-rhel6.box
==> box: Adding box 'vagrant-rhel6' (v0) for provider:
box: Downloading: file:///Users/john/Documents/workspace/vagrant/boxes/vagrant-rhel6.box
==> box: Successfully added box 'vagrant-rhel6' (v0) for 'vmware_desktop'!

Note: You can also add this Vagrant Box to a webserver so that it can be shared with others, in my case I uploaded the Box to a web server:

john@mac:~$ scp ~/Documents/workspace/vagrant/boxes/vagrant-rhel6.box john@webserver:/var/www/html/vagrant/

Update: You can create a Vagrant Box Catalog that will allow versioning of the Boxes and allows the end-users/developers to get automatic update notifications when you have an updated Vagrant box: Versioning and Update Notifications for your Vagrant boxes