How to Start Using Laravel Homestead as Development Environment

You have multiple choices for your development environment. You could just install everything on your host machine, you could use virtual machines, you could use Docker, you could use a remote server. I personally found that the easiest solution is to use Laravel Homestead which is a pre-packaged Vagrant box with most of the stuff you will need for developing in PHP. It's quick to set up, and you don't need to install all kinds of software on your host machine (something I dislike personally).

Code for this article can be found at GitHub repository.

First please make sure that you have Vagrant installed (it will be different depending on the OS).

Please keep in mind that this is for using one VM for one project. If you want to have multiple projects on a single VM check the official documentation.

Add the Homestead as the development dependency:

composer require --dev laravel/homestead

Then generate the Vagrantfile, and Homestead.yaml file by running:

php vendor/bin/homestead make

Open Homestead.yaml file to add type: nfs to folders configuration. This option improves performance (might need additional plugins depending on the OS). Below is an example of how that configuration might look (our project will be named february) :

# Homestead.yaml
# ...

folders:
    - map: "/Users/ifdattic/projects/february" # directory on host
      to: "/home/vagrant/february" # directory on VM
      type: nfs # add this for performance

# ...

Next modify the sites configuration. You will probably want to change the domain of your application by modifying map property. If you're doing this for the Symfony project you will also need to change the to property, and add type: symfony. Below is an example of how that configuration might look:

# Homestead.yaml
# ...

sites:
    # example of Symfony project
    - map: www.february.dev
      to: "/home/vagrant/february/web" # public directory on VM
      type: symfony # use Symfony configuration

    # example of Laravel project
    - map: www.february.dev
      to: "/home/vagrant/february/public" # public directory on VM

# ...

If you have multiple projects with their own VMs you will want to change the IP address to avoid conflicts (you can run php -r 'echo mt_rand(0, 255);' to get a random number):

# Homestead.yaml

ip: "192.168.10.222" # go with 192.168.10.random-number-up-to-255

# ...

To make the domain, and IP work you will need to edit the hosts file on your OS. The location is different for each OS, on Unix like systems it's at /etc/hosts. Inside that file add the line which contains the IP followed by domain of your project. With current example configuration it would be:

# /etc/hosts
# ...

192.168.10.222 www.february.dev

# ...

You might also want to change how much RAM virtual machine has (memory property), how many CPUs it uses (cpus property), or the name of the project (hostname and name properties).

# Homestead.yaml
# ...

memory: 2048
cpus: 1
hostname: february
name: february

# ...

The default Vagrant configuration is good enough, but I personally like to make a few changes that improve the CLI experience inside a VM.

One change I like to do is use my own .bash_aliases file. This functionality is available by default, but I like to change the location of the file. Modify the line which has aliasesPath variable:

# Vagrantfile
# ...

aliasesPath = ".provision/.bash_aliases"

# ...

You can make your own aliases file, here is the example of a good starting point:

# .provision/.bash_aliases

# Easier navigation
alias ..="cd .."
alias ...="cd ../.."
alias ....="cd ../../.."
alias .....="cd ../../../.."

# Shortcuts
alias g="git"
alias h="history"

# Testing tools
alias fixtures="sf hautelook:fixtures:load --purge-with-truncate"
alias behat="vendor/bin/behat --no-snippets"
alias bjs="vendor/bin/behat --no-snippets --tags=javascript"
alias bnojs="vendor/bin/behat --no-snippets --tags=~javascript"
alias phpspec="vendor/bin/phpspec"
alias psp="vendor/bin/phpspec"
alias phpunit="vendor/bin/phpunit"
alias selenium="DISPLAY=:1 xvfb-run java -jar /var/selenium/selenium-server-standalone-2.53.1.jar"

# Symfony console
alias prod="bin/console --env=prod"
alias dev="bin/console --env=dev"
alias sf="bin/console"

# Edit hosts file
alias hosts='sudo $EDITOR /etc/hosts'

Now the following code is not aliases, but if you want to configure your development box further (in an easy way), add the following code at the end of .provision/.bash_aliases file:

### Not aliases, but extra provisioning
if [ -f ~/.bash_extra ]; then
    . ~/.bash_extra
fi

In the .provision/.bash_extra you can put any commands you want. For example to automatically move to your project directory you could add a cd command:

# .provision/.bash_extra

cd february

Depending on your environment you might need multiple files what configure how your environment behaves. Expand Vagrantfile to provision development environment with additional files:

# Vagrantfile
# ...

files = {
  '.provision/.inputrc' => '~/.inputrc',
  '.provision/.bash_extra' => '~/.bash_extra',
  '.provision/.phpspec.yml' => '~/.phpspec.yml',
}

# ...
    files.each do |source, destination|
        if File.exist? source then
            config.vm.provision "file", source: source, destination: destination
        end
    end

# ...

The hash files key contains the source file, and value of it contains the destination of the file. Just modify it according to your needs.

Here is the .inputrc file I like to use (it modifies the behavior of your terminal, making it easier to work with it):

# .provision/.inputrc

# Make Tab autocomplete regardless of filename case
set completion-ignore-case on

# List all matches in case multiple possible completions are possible
set show-all-if-ambiguous on

# Immediately add a trailing slash when autocompleting symlinks to directories
set mark-symlinked-directories on

# Use the text that has already been typed as the prefix for searching through
# commands (i.e. more intelligent Up/Down behavior)
"\e[B": history-search-forward
"\e[A": history-search-backward

Now that you have all the configurations ready you can start your virtual machine. It might take some time if this is the first time running it:

vagrant up

After VM finishes provisioning you should see your web application by opening an application URL (www.february.dev in this case) in the browser. If it's a Symfony project, and you try opening a development version it will inform you that you have no access to it. Fix it by removing the code which checks that the script is being accessed from local environment. Your deployment process to production should remove app_dev.php file to make sure no one has access to development version.

You can execute commands in your VM, for example to run the test suite. Connect to your VM by running:

vagrant ssh

If you're having issues connecting you might need to clear out your ~/.ssh/known_hosts file.

To finish your set up copy Homestead.yaml file to Homestead.yaml.dist. If other people work on your project they will want to have the same configuration, but there are few options which will change for each of them. The one which will be different for everyone would be folders.map option. In the Homestead.yaml.dist file replace that option with an empty string:

# Homestead.yaml.dist
# ...

folders:
    - map: "" # directory of the project on host machine, `pwd` command in bash
    # ...

# ...

Commit Homestead.yaml.dist file to repository, and add Homestead.yaml file to .gitignore file to avoid committing it accidentally. Anyone who wants to get the same environment after cloning the repository should just copy Homestead.yaml.dist file as Homestead.yaml file, and enter the directory of the project (most of the time it will be output of pwd command).

If you're running a Symfony application, and need to check it with the production configuration you will need to comment out (remove) internal; line from your NGINX configuration. The NGINX configuration can be found at /etc/nginx/sites-available directory. The configuration file is the map value of your site option (from Homestead.yaml, in this case it would be www.february.dev). Then restart NGINX service, and clear your Symfony cache:

sudo service nginx restart

sf c:c --env=prod

Now you should have an easy to reproduce development environment.

Posted in: PHP, Technical, Tips, Tools

Comments