Creating a PHP 8 Development Environment Using Vagrant and Ubuntu 20.04
We’ve spent a lot of time discussing how to use Vagrant to create our development environment so now it’s time to bring everything we’ve learned together so we can finally develop some code.
Vagrant Provision
One of the pieces of Vagrant we haven’t discussed yet is the ability for Vagrant to install and setup packages in our VMs using its provisioning system. Vagrant will automatically run these commands when we vagrant up
our environment the first time and it also provides the vagrant provision
command to have it run the provisioning manually.
We define this set of commands using the config.vm.provision
directive in our Vagrantfile. To get started we’re going to use the “inline” mode of the “shell” provisioner. There are several different provisioners supported by Vagrant but the shell mode is nice because it allows us to keep all of the provisioning steps inside the Vagrantfile and doesn’t require any additional software. We’ve found that as the complexity of the provisioning increases it’s best to move to a solution like Ansible, Puppet, or Chef.
Vagrant.configure("2") do |config|
config.vm.box = "generic/ubuntu2004"
config.vm.network "private_network", ip: "192.168.33.10"
config.vm.synced_folder ".", "/home/vagrant/our-awesome-project"
config.vm.provision "shell", inline: <<-SHELL
echo "our commands to here"`
SHELL
end
The downside to using the inline mode is that as the number of steps grows or as we need to support multiple VMs in our environment it gets harder to maintain. When this happens we can extract the setup portion of the script into a shell script and call it using the method below.
Vagrant.configure("2") do |config|
config.vm.box = "generic/ubuntu2004"
config.vm.network "private_network", ip: "192.168.33.10"
config.vm.synced_folder ".", "/home/vagrant/our-awesome-project"
config.vm.provision "shell" path: "setup.sh"
end
Basic Steps to Setup Our LAMP Stack
Let’s take a step back and discuss what needs to happen to set up a LAMP stack using Ubuntu, Apache, MySQL, and PHP 8. To get our installation working there are several things we need to do.
1. Setup Our VM To Use An Alternative Repository
For this setup, we’re using the Long Term Support (LTS) release of Ubuntu so we have 5 years of support. The downside to that decision is that we’ll be “stuck” at version 7.4 of PHP even though the most current version of PHP is 8.0. Thankfully, there is an alternative repository maintained by Ondřej Surý (https://launchpad.net/~ondrej/+archive/ubuntu/php/) that allows us to install newer versions of PHP on the LTS versions of Ubuntu. Compiling PHP from source is such a pain and if we ever meet Ondřej we owe him a drink.
To get the Ondřej repository setup we need to run the commands below to install the prerequisite packages and then add the repository.
apt-get update
apt-get install -y lsb-release ca-certificates apt-transport-https software-properties-common
add-apt-repository ppa:ondrej/php
2. Install Apache, MySQL, and PHP 8
Now we can install the rest of our LAMP stack.
apt-get update
apt-get install -y apache2 mysql-server php8.0 php8.0-mysql
3. Create A Virtual Host For Apache And Enable It
Our next step is to create a virtual host for Apache so we can serve files out of the /home/vagrant
directory.
To do this we need to create a basic configuration file. We’re going to create a “setup” directory in our project directory and create a file named “development.conf” with the contents below.
<VirtualHost *:80>
ServerAdmin webmaster@localhost
DocumentRoot /home/vagrant/our-awesome-project/public
<Directory /home/vagrant/our-awesome-project/public>
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
This will set up a basic virtual host to serve whatever we put in the “public” directory of our project.
The commands we’re going to add to our Vagrantfile will copy this file to the appropriate directory inside our VM, enable it, disable the default site, and reload Apache so it notices the change.
cp /home/vagrant/our-awesome-project/setup/development.conf /etc/apache2/sites-available/development.conf
a2ensite development.conf
a2dissite 000-default.conf
systemctl reload apache2
4. Create A Development Database And User
The last step is to create a development database and user. We almost always need to create at least one database per project and we recommend creating a specific user per project. We could set up the connection to use the root user but it’s a bad practice as it increases the attack surface of our database.
echo "create database development" | mysql
echo "CREATE USER 'development'@'localhost' IDENTIFIED BY 'development'" | mysql
echo "GRANT ALL PRIVILEGES ON development.* TO 'development'@'localhost';" | mysql
echo "flush privileges" | mysql
Bringing It All Together
Here is the completed Vagrantfile which includes a static IP address and a synced folder.
Vagrant.configure("2") do |config|
config.vm.box = "generic/ubuntu2004"
config.vm.network "private_network", ip: "192.168.33.10"
config.vm.synced_folder ".", "/home/vagrant/our-awesome-project"
config.vm.provision "shell", inline: <<-SHELL
apt-get update
apt-get install -y lsb-release ca-certificates apt-transport-https software-properties-common
add-apt-repository ppa:ondrej/php
apt-get update
apt-get install -y apache2 mysql-server php8.0 php8.0-mysql
cp /home/vagrant/our-awesome-project/setup/development.conf /etc/apache2/sites-available/development.conf
a2ensite development.conf
a2dissite 000-default.conf
systemctl reload apache2
echo "create database development" | mysql
echo "CREATE USER 'development'@'localhost' IDENTIFIED BY 'development'" | mysql
echo "GRANT ALL PRIVILEGES ON development.* TO 'development'@'localhost';" | mysql
echo "flush privileges" | mysql
SHELL
end
Now we can run vagrant provision
to have it run the steps we’ve outlined in our Vagrantfile.
vagrant provision
==> default: Running provisioner: shell...
default: Running: inline script
default: Hit:1 http://archive.ubuntu.com/ubuntu focal InRelease
default: Get:2 http://security.ubuntu.com/ubuntu focal-security InRelease [109 kB]
default: Get:3 http://archive.ubuntu.com/ubuntu focal-updates InRelease [114 kB]
default: Get:4 http://archive.ubuntu.com/ubuntu focal-backports InRelease [101 kB]
default: Fetched 324 kB in 3s (106 kB/s)
default: Reading package lists...
To test our setup we can create a very basic phpinfo.php
file in our public directory.
Conclusion
In this article, we discussed how to use Vagrant’s provisioning system to configure a basic LAMP development environment so we can finally start working on our project.
Scott Keck-Warren
Scott is the Director of Technology at WeCare Connect where he strives to provide solutions for his customers needs. He's the father of two and can be found most weekends working on projects around the house with his loving partner.
Top Posts
- Working With Soft Deletes in Laravel (By Example)
- Fixing CMake was unable to find a build program corresponding to "Unix Makefiles"
- Upgrading to Laravel 8.x
- Get The Count of the Number of Users in an AD Group
- Multiple Vagrant VMs in One Vagrantfile
- Fixing the "this is larger than GitHub's recommended maximum file size of 50.00 MB" error
- Changing the Directory Vagrant Stores the VMs In
- Accepting Android SDK Licenses From The OSX Command Line
- Fixing the 'Target class [config] does not exist' Error
- Using Rectangle to Manage MacOS Windows