Andrew Welch
Published , updated · 5 min read · RSS Feed
Please consider 🎗 sponsoring me 🎗 to keep writing articles like this.
Local Development with Vagrant / Homestead
A local development environment with Vagrant/Homestead allows you to work on projects more safely and effectively
Homestead is a provisioning tool which sets up a local development environment that allows you to work on webdev projects without fear. You get a modern stack with everything you need for development, including an array of fantastic debugging tools.
We’re going to talk about why I use Homestead for local development, but before we get into the nuts and bolts, let’s talk about why we use a local development environment to begin with.
N.B.: Although Craft CMS is referenced in this article, Homestead works well for any kind of web development with any kind of CMS or dev stack (Laravel, NodeJS, whatevs).
You don’t work on a car’s engine while it’s running, barreling down the highway at 100km/h
In the bad old days, web development was done commando, editing .html files directly on the server. Then people started realizing this was a bad idea, and files were edited locally, and then copied down to the server using an FTP app after some rudimentary testing.
The problem is that modern web development isn’t just editing markup anymore. Modern web development is on a collision course with software engineering & information architecture. Some would argue — I think quite rightly — that we’re already there.
That means we have to be serious about our tooling. We need to have a way to design, develop, and debug our projects using modern tools, in a way that doesn’t interfere with the public-facing website.
The Multi-Environment Config for Craft CMS article talks more in-depth about how to set up Craft CMS for this type of setup where you have local development, staging, and live production environments.
If you’re not using some kind of local development environment, you will find it increasingly difficult to stay up to speed. So let’s do it.
Link Why Vagrant/Homestead?
There are as many ways to set up a local development environment as there are to skin a cat. The reason I’m partial to using Homestead to set up my local development environment is that it creates an entirely separate virtual machine (VM) inside of your computer.
This has several advantages:
- You can install whatever you want in your Homestead VM without affecting your actual computer
- You can easily create and destroy as many VMs as you want, so an “oops” moment means minutes, not hours
- You get a real™ Linux box that mirrors your production server as closely as possible
- You get all of the tools you need pre-installed, without having to add them in piecemeal
Having something that closely mirrors a production environment means fewer unexpected surprises when you deploy to production, and it means you spend less time on the “meta-work” of getting your development environment working.
The fact that you can create a pre-provisioned VM quickly and easily means that you can develop without fear. If you royally screw up your development environment, no big deal, you just spin up another one.
Here’s what it looks like:
Homestead is a Vagrant box (along with some setup & provisioning scripts). Vagrant is provisioning software that uses a preconfigured “box” to set up a Virtual Machine from a provider. The “provider” is what actually runs the VM, and can be either VirtualBox (which is free), VMware (which is not free), or Parallels (which is also not free).
I’m going to assume that you’re cheap like me, and you’re going to use VirtualBox, because it’s free. But any of the three will do, and in fact, VMware offers significantly better performance than the free VirtualBox, so you might consider giving it a go.
So Homestead is the recipe, Vagrant is the chef, and VirtualBox is the waiter that serves you up the scrumptious dish.
All of this runs as a virtual machine (VM) inside of your computer. Nothing that is in this VM can hurt your actual computer, it’s completely separate and insulated.
You have your own little server inside your computer, and combined with a setup as described in the Database & Asset Syncing Between Environments in Craft CMS article, you have a mobile environment that you can use anywhere. Even without Internet access.
What’s more, if you work with other people, the deterministic way in which Homestead provisions your VM means you can ensure that they also have the exact same local development environment that you do.
Consistency in tooling amongst your team means less friction, and fewer problems.
Link Becoming a Homesteader
So enough talk! Let’s get a Homestead environment. If you prefer video instructions, check out the Setup Craft CMS on Vagrant Homestead YouTube video.
First, you’ll need to download and install:
Both of them come with native installers for Mac, Windows, and Linux. You don’t need to do any kind of setup for either of them, just install them. Then we need to add the laravel/homestead box to Vagrant via the following:
vagrant box add laravel/homestead
Next up we’ll need to install Homestead by cloning the repo:
git clone https://github.com/laravel/homestead.git Homestead
…and checking out the desired version (v5.1.0 is the latest as of this writing):
cd Homestead
git checkout v5.1.0
Tangent: A word about versions. As we mentioned earlier, Homestead comes in two parts, the Homestead Vagrant box, and then the scripts that compose Homestead itself. There’s a separate version number for each. As of this writing, the latest version of the Homestead Vagrant box is 2.0.0, and the latest version of Homestead itself is 5.1.0. Just something to keep in mind when updating Homestead.
Finally, the first time we install Homestead, we also need to initialize it from the Homestead directory. On Mac/Linux, we do:
bash init.sh
…and on Windows, we do:
init.bat
This creates a Homestead.yaml file in the Homestead/ directory. This is the file we’ll be using to configure our Homestead setup. Here’s a simple example (edit your Homestead.yaml file to suit your own needs, using this as a guide):
---
ip: "192.168.10.10"
memory: 2048
cpus: 1
provider: virtualbox
mariadb: true
authorize: ~/.ssh/id_rsa.pub
keys:
- ~/.ssh/id_rsa
folders:
- map: /Users/andrew/webdev/sites
to: /home/vagrant/sites
type: nfs
sites:
- map: nystudio107.dev
to: /home/vagrant/sites/nystudio107/public
- map: craft3.dev
to: /home/vagrant/sites/craft3/public
databases:
- nystudio
- craft3
variables:
- key: APP_ENV
value: local
# blackfire:
# - id: foo
# token: bar
# client-id: foo
# client-token: bar
# ports:
# - send: 93000
# to: 9300
# - send: 7777
# to: 777
# protocol: udp
What this will do is provision our VM to have 2048mb of memory, and use 1 virtual CPU. A decent rule of thumb is to use 1/8th of your computer’s RAM to dedicate to the VM.
We’re using mariadb instead of mysql because it doesn’t have the annoying issue with Craft CMS 2.x that MySQL 5.7 does. MariaDB doesn’t whine about Warning: Using a password on the command line interface can be insecure, and it’s a more active codebase.
Don’t worry, MariaDB a 100% drop-in replacement for MySQL, and it’s 100% compatible (it’s a fork of the same codebase, by the original author of MySQL). If for some reason you really don’t want to use MariaDB, just omit this line, and it’ll use MySQL by default.
folders allows you to map directories from your computer to your VM. This lets you use native editors like Sublime or PhpStorm to edit your code, while also allowing the VM to access the files as well.
Remember, the VM is effectively a separate computer, so this directory mapping is a bridge between the two. So you can edit the same files either on your computer, or in the VM. A key setting is to use nfs as the type because its a more performant way to do this file sharing/syncing.
sites lets you set up mappings from a domain name to a directory on the VM where the website lives. You can add as many as you want in the same VM.
databases lets you tell Homestead to create the mysql databases for you. Again, you can have as many databases as you like in the same VM.
Then we need to tell our computer where to find these sites by them to our hosts file, which is at /etc/hosts on Mac/Linux, and at C:\Windows\System32\drivers\etc\hosts on Windows:
192.168.10.10 nystudio107.dev
192.168.10.10 craft3.dev
The easiest way to edit the hosts file on a Mac is just doing: sudo nano /etc/hosts which will bring up a very simple editor. Since this is a system file, you’ll need to enter your admin password to edit it.
On Windows, you similarly need to edit the hosts file with admin rights. For example, run Notepad with right click > run as admin and then edit the hosts file.
If you get tired of editing your hosts file manually, you can always use the hostsupdater Vagrant plugin to do it for you.
Finally, let’s do a little bit of setup that isn’t strictly necessary, but it’ll make your daily life with Homestead a lot nicer.
Homestead is a specific type of Vagrant box; so we could use the standard Vagrant commands when working with our Homestead box. But it’s much more convenient to set up a command that works specifically with our Homestead environment.
On the Mac do this to edit your Bash profile: nano ~/.bash_profile and add this to the end of it:
function homestead() {
( cd ~/Homestead && vagrant $* )
}
Make sure to tweak the ~/Homestead path in the function to the location of your actual Homestead installation.
While you’re in there, if you want the command line prompt to tell you what git repo & branch you’re currently in, add this to the end of your ~/.bash_profile too:
parse_git_branch() {
git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/ (\1)/'
}
export PS1="\u@\h \[\033[32m\]\w\[\033[33m\]\$(parse_git_branch)\[\033[00m\] $ "
You’ll have to close your Terminal window and re-open it for the changes to your ~/.bash_profile to take effect, so do that now.
On Windows, create a homestead.bat batch file anywhere on your machine with the following contents:
@echo off
set cwd=%cd%
set homesteadVagrant=C:\Homestead
cd /d %homesteadVagrant% && vagrant %*
cd /d %cwd%
set cwd=
set homesteadVagrant=
Make sure to tweak the example C:\Homestead path in the script to the actual location of your Homestead installation. After creating the file, add the file location to your PATH
There’s plenty more you can do with Homestead, including installing it via Composer on a per-project basis, and more. Check out the Homestead Documentation for further details.
Link Ladies & Gentlemen, start your engines
Phew! That was a lot of setup work, but thankfully we only have to do it once. Let’s fire up our VM! Type:
homestead up
What actually happens is the homestead command changes the current working to where we installed Homestead, and then maps the rest of the arguments to vagrant because of the command we set up earlier.
The way Vagrant works is that if there is a Vagrantfile in the current working directory when you execute the vagrant command, it assumes you want to work with that VM, and it uses it.
So setting up that homestead command saved us from having to switch to the Homestead/ directory (or know the Vagrant machine ID) each time we want to do something with it. That’s all.
The first time you do homestead up it’ll take a bit of time, and you will have to enter your admin password to allow the nfs directory mapping to work.
After that, though, it’s smooth sailing. I generally just leave my VM running all the time, since I use it every day, and it has very little CPU/battery impact when it’s just idling in the background.
I set it up so that every project I work on lives in the same VM. Spinning up a new project just involves adding the appropriate lines to the sites and databases in the Homestead.yaml file, adding the domain name to the hosts file, and then provisioning the VM by doing:
homestead reload --provision
Don’t worry, neither homestead reload nor homestead reload --provision will affect your files or databases stored on your VM.
All of the databases that Homestead creates for you have the following credentials:
- User: homestead
- Password: secret
So you’ll want to enter that into your multi-environment config so that you can access your database. By far the easiest way to pull your production database down is to do so via Craft-Scripts, as discussed in the Database & Asset Syncing Between Environments in Craft CMS article.
If you want to access your website that’s running from your VM, just put the domain name in your web browser, and away you go, e.g.: nystudio107.dev
The websites that you specified via sites in the Homestead.yaml file result in the corresponding Nginx .conf files for the virtual hosts in /etc/nginx/sites-available (and a symlink in /etc/nginx/sites-enabled). You can edit them as you see fit, but they will be reset if you do a homestead up --provision or homestead reload --provision.
If you want to ssh into your VM, just type:
homestead ssh
…and you’re in! No passwords or anything. It’s a real Linux box, running Ubuntu 16.04 (at the time of this writing), so you can install whatever you like.
One thing you’re going to need to install if you’re running Craft 2.x is the mycrypt package for PHP. mycrypt is deprecated as of PHP 7.1 (though it still works), and Craft 3.x doesn’t use it, but we need this legacy package for Craft 2.x. So let’s install it.
While we’re at it, let’s install Imagemagick as well, for doing our image transforms and such. Homestead comes with GD installed by default, but we can easily add Imagemagick too. From inside of your VM, simply do:
sudo apt-get install php7.1-mcrypt php-imagick
Important: If, when installing things, it ever asks you whether you want to replace an existing .conf file, always say No (or just hit the Return key, which defaults to the safest option).
You can install other stuff, too!
Let’s say you want to play around with using .webp images as per the Creating Optimized Images in Craft CMS article; just install cwebp on your VM via:
sudo apt-get install webp
…and away you go. If you want to edit your files to, you know, actually do some development work, just do that however you normally would.
The files are automatically synced between your computer and your VM. Edit them in Sublime or PhpStorm on your computer. Edit them in nano or vim on your VM. Homestead doesn’t care.
If you do plan to use PhpStorm for local development, check out the Using PhpStorm with Vagrant / Homestead article for how to set that up.
Link Homestead Like a Pro
Now that we have Homestead up and running, here are a few tips I’ve found that can make it really sing. You don’t have to do any of these things, they are completely optional, but some will make your life on the trail much easier.
We’re already using nfs for our directory mapping, which is great, because otherwise VirtualBox can be pretty slow at syncing files. There is, however, one annoying side-effect, which is that all of your shared files will look like this:
vagrant@homestead /htdocs/nystudio107 (develop) $ ls -al gulpfile.js
-rw-r--r-- 1 501 dialout 11269 Feb 15 04:51 gulpfile.js
What’s going on here is that it’s using the UID and GID from your computer in the VM; and it has different users and groups than your computer does. If you’re unfamiliar with Unix users, groups, and permissions, check out the Hardening Craft CMS Permissions article for a primer.
So in this case, there’s no user with the UID of 501 in the VM, and the staff GID on my computer happens to be the GID of the dialout user on my VM.
While this is mildly annoying to look at, it can become a real problem with permissions sometimes. So let’s fix it. To do so, we’ll use the vagrant-bindfs Vagrant plugin; just install it on your computer via:
vagrant plugin install vagrant-bindfs
Homestead will automatically use this Vagrant plugin if it is present, so there’s no need to alter your Vagrantfile. Then reload your VM config with:
homestead reload
…and all will be well with the universe:
vagrant@homestead /htdocs/nystudio107 (develop) $ ls -al gulpfile.js
-rw-r--r-- 1 vagrant vagrant 11269 Feb 15 04:51 gulpfile.js
Next up, there’s a handy shell script in the Homestead/ folder called after.sh. This script is executed after Homestead has finished provisioning the VM, so you can add whatever you want to it, and it’ll be executed after a homestead up --provision or homestead reload --provision.
As a for-instance, I use customized versions of the Nginx .conf files for my websites, set up via Nginx-Craft. These normally would get reset to their defaults after a homestead up --provision or homestead reload --provision. so we can stash the customized versions in the setup/sites directory inside the Homestead/ folder, and restore them via after.sh:
# -- Copy over customized nginx configs
# As per: https://laracasts.com/discuss/channels/requests/homestead-provision-deletes-custom-nginx-settings
# define your sites config directory located on your host machine
SITES=/home/vagrant/setup/sites/*
# copy every site file from /home/vagrant/setup/sites/ to your Nginx sites-available folder
yes | sudo cp -rf $SITES /etc/nginx/sites-available
# enable each site by creating a symbolic link to each file
for p in $SITES
do
FILE=$(basename $p)
sudo ln -s /etc/nginx/sites-available/$FILE /etc/nginx/sites-enabled/
done
# restart the nginx service
sudo service nginx restart
We’ll also need to add an additional directory to our folders in Homestead.yaml mapping too:
- map: /Users/andrew/Homestead/setup
to: /home/vagrant/setup
type: nfs
Make sure you change the first path to point to your Homestead/setup directory.
Next, let’s make some tweaks to our nfs mounts to speed them up when dealing with lots of files (such as git repos, node_modules folders, etc.). Add this to the bottom of your Vagrant file:
# Speed up NFS as per: https://www.jverdeyen.be/vagrant/speedup-vagrant-nfs/
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
# …
config.vm.synced_folder "/Users/andrew/webdev/sites", "/home/vagrant/sites", type: "nfs", mount_options: ['rw', 'vers=3', 'tcp', 'fsc' ,'actimeo=2']
end
Change the paths to be whatever you set your folders to be in your Homestead.yaml file. Note that the first directory is the directory on your computer, the second directory is the directory in your VM. Then reload your VM with:
homestead reload
One final tip related to performance, here are some tweaks you can make by adding this to the bottom of your Vagrantfile:
# As per https://www.mkwd.net/improve-vagrant-performance/
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
# …
config.vm.provider "virtualbox" do |v|
# change the network card hardware for better performance
v.customize ["modifyvm", :id, "--nictype1", "virtio" ]
v.customize ["modifyvm", :id, "--nictype2", "virtio" ]
# enable IO APIC so that the virtual machine can make use of the additional cores
v.customize ["modifyvm", :id, "--ioapic", "on"]
end
end
# Speed up VirtualBox i/o as per: https://joeshaw.org/terrible-vagrant-virtualbox-performance-on-mac-os-x/
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
# …
config.vm.provider "virtualbox" do |v|
v.customize [
"storagectl", :id,
"--name", "SATA Controller",
"--hostiocache", "on"
]
end
end
Then restart your VM with:
homestead reload
Link So What’s the Bad News?
So what are the downsides to using a Homestead VM? If you’ve read this far, you’re aware that there’s some setup work involved. But given that this is a one-time thing, and it installs modern versions of everything you’ll need in one shot, I haven’t found this to be burdensome.
Pick an afternoon, get a cup of coffee, and spend a little upfront time making the rest of your working life better.
The other downside to a VM is that it can be slower than if you use “native” local development environments such as Valet, Mamp, or what have you.
These “native” tools install the development environment on your computer itself, so there’s no VM layer to go through. I’ve found that the convenience and functionality offered by an actual VM is worth it; not to mention the time saved by having it match your production environment, and not having to tinker around with some oddball setup.
In general, local development paradoxically can often be slower than your production server regardless of what tool you use. That’s because you’re running things like XDebug, devMode is on, templateCaching is off, and in general things are set up for development/debugging rather than performance.
Your mileage, of course, may vary. Use whatever tool works; half of the battle is just the fact that you’re using something for local development.
Tool up. Be awesome.