macOS 14.0 Sonoma Apache Setup: MySQL, Xdebug & More...

Second part in a multi-part blog series for Mac developers

12 mins

IMPORTANT: It's critical to select the correct type of processor your mac is using so the instructions below will be accurate. This is because Homebrew uses different paths for Apple Silicon and Intel based hardware.

My mac is using an processor.

Part 2: macOS 14.0 Sonoma Web Development Environment

In Part 1 of this 3-part series, we covered configuring Apache on macOS to work better with your local user account, as well as the installation process for installing multiple versions of PHP.

In this Part 2, we will cover installing MySQL, Virtual Hosts, APC caching, YAML, and Xdebug. After finishing this tutorial, be sure to check out how to enable SSL in Part 3 of the series.

10/20/2023 Updated to reflect macOS 14.0 Sonoma
12/25/2022 Updated to reflect macOS 13.0 Ventura
10/29/2021 Updated to reflect macOS 12.0 Monterey and removed PHP 5.6
11/13/2020 Updated to reflect the release of macOS 11.0 Big Sur
12/02/2019 Updated to reflect the latest release of PHP 7.4 and the removal of PHP 7.1 from Official tap
12/02/2019 Updated to reflect the latest release of PHP 7.4 and the removal of PHP 7.1 from Official tap
10/08/2019 Updated to reflect the release of macOS 10.5 Catalina
01/10/2019 Updated to add back PHP 5.6 and PHP 7.0 from and external deprecated keg
12/12/2018 Updated to reflect the latest release of PHP 7.3 and the removal of PHP 7.0 from Brew.

This guide is intended for experienced web developers. If you are a beginner developer, you will be better served using MAMP or MAMP Pro.

MySQL

Although not required for development of Grav, there are times you definitely need an installation of MySQL. In the original guide, we used the Oracle MySQL installation package. However, we now have switched to MariaDB which is a drop-in replacement for MySQL and is easily installed and updated with Brew. Detailed information on the HomeBrew installation process can be found on the mariadb.org site but the essentials are as follows:

Install MariaDB with Brew:

brew update
brew install mariadb

After a successful installation, you can start the server ane ensure it autostarts in the future with:

brew services start mariadb

You should get some positive feedback on that action:

==> Successfully started `mariadb` (label: homebrew.mxcl.mariadb)

You must change MySQL server password and secure your installation. The simplest way to do this is to use the provided script:

sudo /opt/homebrew/bin/mysql_secure_installation

Just answer the questions and fill them in as is appropriate for your environment. You can just press return when prompted for the current root password.

Download TablePlus and install it. (it's awesome and there's a free version!). You should be create a new MySQL connection, give it a Name, a color, and check Use socket option after you enter a User of root and your newly created password.

TablePlus Connection

If you need to stop the server, you can use the simple command:

brew services stop mariadb

Apache Virtual Hosts

A very handy development option is to have multiple virtual hosts set up for you various projects. This means that you can set up names such as grav.mydomain.com which point to your Grav setup, or project-x.mydomain.com for a project-specific URL.

Apache generally performs name-based matching, so you don't need to configure multiple IP addresses. Detailed information can be found on the apache.org site.

Apache already comes preconfigured to support this behavior but it is not enabled. First you will need to uncomment the following lines in your /opt/homebrew/etc/httpd/httpd.conf file:

LoadModule vhost_alias_module lib/httpd/modules/mod_vhost_alias.so

and:

# Virtual hosts
Include /opt/homebrew/etc/httpd/extra/httpd-vhosts.conf

Then you can edit this referenced file and configure it to your needs:

code /opt/homebrew/etc/httpd/extra/httpd-vhosts.conf

This file has some instructions already but the important thing to remember is that these rules are matched in order. When you set up virtual hosts, you will lose your older document root, so you will need to add back support for that first as a virtual host.

<VirtualHost *:80>
    DocumentRoot "/Users/your_user/Sites"
    ServerName localhost
</VirtualHost>

<VirtualHost *:80>
    DocumentRoot "/Users/your_user/Sites/grav-admin"
    ServerName grav-admin.test
</VirtualHost>

Don't forget to change your_user for your actual username on your Mac. For example: DocumentRoot "/Users/bernard/Sites"

As you set up your .test virtual hosts, you may receive a warning such as Warning: DocumentRoot [/Users/your_user/Sites/grav-admin] does not exist when restarting Apache. This just lets you know that the source directory listed for your virtual hosts is not present on the drive. It's an issue that can be resolved by editing this file with the corrected DocumentRoot.

Dnsmasq

We used to recommend using .dev domain name, but since Chrome 63 forces all .dev domains to use SSL, this guide has been updated to use .test

In the example virtualhost we setup above, we defined a ServerName of grav-admin.test. This by default will not resolve to your local machine, but it's often very useful to be able to setup various virtual hosts for development purposes. You can do this by manually adding entries to /etc/hosts ever time, or you can install and configure Dnsmasq to automatically handle wildcard *.test names and forward all of them to localhost (127.0.0.1).

First we install it with brew:

brew install dnsmasq

Then we setup *.test hosts:

echo 'address=/.test/127.0.0.1' > /opt/homebrew/etc/dnsmasq.conf

Start it and ensure it auto-starts on reboot in the future:

sudo brew services start dnsmasq

And lastly, add it to the resolvers:

sudo mkdir -v /etc/resolver
sudo bash -c 'echo "nameserver 127.0.0.1" > /etc/resolver/test'

Now you can test it out by pinging some bogus .test name:

ping bogus.test
PING bogus.test (127.0.0.1): 56 data bytes
64 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.044 ms
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.118 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.045 ms

Voila! we have successfully setup wildcard forwarding of all *.test DNS names to localhost.

Xdebug

One of the most important aspects of any kind of development is the ability to debug and fix your code. PHP comes with limited support to dump variables or log to a file, but for more complex situations you need something more powerful.

Xdebug provides is a debugging and profiling extension for PHP that provides an HTML-friendly output for the var_dump() method that improves the readability of the default version. It also provides other useful dumping methods as well as displaying stack traces. One of the best features however, is the ability to remote debug your code. This means you can set breakpoints, and step through your PHP code inspecting as you go. Full documentation on Xdebug contains extensive information about all the functionality available.

Xdebug for various PHP versions

There are some compatibility issues we need to take into account, as certain versions of PHP can only run certain versions of Xdebug:

PHP Version Compatible Xdebug version
PHP 7.0 Xdebug 2.7
PHP 7.1 Xdebug 2.9
PHP 7.2-7.4 Xdebug 3.1
PHP 8.0-8.2 Xdebug 3.2
PHP 8.3+ Xdebug 3.3alpha

To install specific versions of Xdebug we need to switch to the PHP version we want to install it on, then run these commands:

For PHP 7.0
sphp 7.0
pecl uninstall -r xdebug
pecl install xdebug-2.7.2
For PHP 7.1
sphp 7.1
pecl uninstall -r xdebug
pecl install xdebug-2.9.8
For PHP 7.2 - 7.4

change sphp 7.2 to the version you want to install xdebug for (7.2 - 7.4)

sphp 7.2
pecl uninstall -r xdebug
pecl install xdebug-3.1.6
For PHP 8.0 - 8.2

change sphp 8.2 to the version you want to install xdebug for (8.0 - 8.2)

sphp 8.2
pecl uninstall -r xdebug
pecl install xdebug
For PHP 8.3+

change sphp 8.3 to the version you want to install xdebug for (8.3+)

sphp 8.3
pecl uninstall -r xdebug
pecl install xdebug-3.3.0alpha3

Xdebug Configuration

Like the other PECL-installed modules, this will create a simple entry in the php.ini file, but you really need to configure Xdebug for it to be useful. So let's just go ahead and create our configuration file as we'll need it shortly anyway.

You will now need to remove the zend_extension="xdebug.so" entry that PECL adds to the top of your php.ini. So edit this file and remove the top line. In this example we will use 7.2 but it's the same procedure for each version of PHP.

code /opt/homebrew/etc/php/7.2/php.ini

Once that line is removed, we can add a new file with a proper entry to the recently bulit xdebug.so library:

code /opt/homebrew/etc/php/7.2/conf.d/ext-xdebug.ini

For Xdebug versions prior to 3.0 (ie, PHP 5.6 through PHP 7.1) you can paste the following into the file:

[xdebug]
zend_extension="xdebug.so"
xdebug.remote_enable=1
xdebug.remote_host=localhost
xdebug.remote_handler=dbgp
xdebug.remote_port=9000

However, Xdebug version 3.0+ (ie, PHP 7.2+) has a simplified syntax and should look like this:

[xdebug]
zend_extension="xdebug.so"
xdebug.mode=debug

Restart Apache with the brew services stop httpd; brew services start httpd command to pick up your changes. You should check the http://localhost/info.php to ensure that Xdebug information is displayed:

if Xdebug still shows up in php -v the most likely cause is you didn't remove the zend_extension="xdebug.so"" entry at the top of php.ini

Restart Apache with the brew services stop httpd; brew services start httpd command to pick up your changes.

Xdebug Switcher Script

W00fz created a great tool for quickly enabling/disabling xdebug. Install this with brew:

curl -L https://gist.githubusercontent.com/rhukster/073a2c1270ccb2c6868e7aced92001cf/raw/c1629293bcf628cd6ded20c201c4ef0a2fa79144/xdebug > /opt/homebrew/bin/xdebug
chmod +x /opt/homebrew/bin/xdebug

Using it is simple, you can get the current state with:

xdebug

And then turn it on or off with:

xdebug on
xdebug off

CLI Enabled Xdebug

There are times when you want to debug from the CLI, and you can do this by setting an environment variable. My preferred approach is to use a simple script that works with all versions of Xdebug. First create a file in your user's bin/ folder (create the folder if it doesn't already exist), and call it xdebug.conf then save this:

export XDEBUG_MODE=debug  
export PHP_IDE_CONFIG=serverName=localhost  
export XDEBUG_CONFIG=idekey=PHPSTORM remote_port=9000 remote_host=localhost remote_enable=1 remote_handler=dbgp  

Then ensure it's executable:

chmod +x ~/bin/xdebug.conf

Then when you need to debug, simply run it whenever you need it:

~/bin/xdebug.conf

APC Cache

Caching in PHP is a big part of the performance equation. There are two types of caching typically available, and both have a big impact on speed and performance.

The first type of cache is called an opcode cache, and this is what takes your PHP script and compiles it for faster execution. This alone can typically result in a 3X speed increase!.

The second type of cache is a user cache, and this is a data-store that PHP can use to quickly store and retrieve data from. These typically run in memory which means they are transient, but very fast.

All PHP packages now come pre-built with Zend OPcache by default, but you can still install APCu Cache as a data store.

Install APCu

Switch to PHP 7.0 mode, then run the following brew commands to install autoconf:

sphp 7.0
brew install autoconf

Then you can install APCu via PECL. PECL is a PHP package manager that is now the preferred way to install PHP packages. Using it requires a little more manual work than before when these packages were available via a single one-line brew install command.

For PHP 7.0 and above you can use the latest 5.x release of APCu, so the process is the same for all. First let's switch to PHP 7.0 and install the APCu library:

sphp 7.0
pecl install apcu

Answer any question by simply pressing Return to accept the default values

Restart Apache with the brew services stop httpd; brew services start httpd command to pick up your changes.

[Optional] APCu Configuration

This is probably enough for most people, but if you are like me and like a little more control over your settings, and also the ability to more easily enable/disable the extension, we have some extra optional steps.

You will now need to remove the extension="apcu.so" entry that PECL adds to the top of your php.ini. So edit this file and remove the top line:

code /opt/homebrew/etc/php/7.0/php.ini

Once that line is removed, we can add a new file with a proper entry to the recently built apcu.so library:

code /opt/homebrew/etc/php/7.0/conf.d/ext-apcu.ini

In this file paste the following:

[apcu]
extension="apcu.so"
apc.enabled=1
apc.shm_size=64M
apc.ttl=7200
apc.enable_cli=1

Restart Apache with the brew services stop httpd; brew services start httpd command to pick up your changes.

APCu for other PHP versions

For PHP 7.1 do the following:

sphp 7.1
pecl uninstall -r apcu
pecl install apcu

The uninstall -r enables PECL to only remove registration, it does not actually uninstall anything.

Again if you are OK with the ACPu defaults, you can leave things as-is, but you can choose to repeat the Optional APCu Configuration steps to create an APCu configuration file fore each PHP version.

For all other versions, just switch to the appropriate PHP versiona dn run the two pecl commands.

YAML

With recent versions of Grav, we now make use of the native PECL YAML library that allow YAML processing to be done by highly efficient libYAML C library rather than by they Symfony PHP library. This can result in a 5X improvement in YAML processing times! Luckily this is a simple process to install for any PHP version:

First we need to install libyaml:

brew install libyaml

Then you can install PHP YAML via PECL.

For PHP 7.0 we have to install a specific version of YAML:

pecl install yaml-2.0.4

For PHP 7.1+ simply use the latest version of YAML:

pecl install yaml

When prompted for "Please provide the prefix of libyaml installation [autodetect]" - Enter the following path:

/opt/homebrew/Cellar/libyaml/0.2.5

And it should complete successfully.

Restart Apache with the brew services stop httpd; brew services start httpd command to pick up your changes.

YAML for other PHP versions

First let's switch to PHP 8.2 and install the YAML library:

sphp 8.2
pecl uninstall -r yaml
pecl install yaml

Restart Apache with the brew services stop httpd; brew services start httpd command to pick up your changes.

The uninstall -r enables PECL to only remove registration, it does not actually uninstall anything.

and for all other versions simply repeat the steps above after switching to the appropriate version of PHP.

[Optional] YAML Configuration

If you are feeling adventurous, or you like to keep things uniform, you can follow the same procedure as APCu and remove the default extension-"yaml.so" entry in each PHP's php.ini and instead, create a conf.d/ext-yaml.ini file:

[yaml]
extension="yaml.so"

You should now be all set with a Rockin' PHP development environment! To find out how to enable SSL on Apache, check out Part 3 in the series.

NOTE: The brew installation actually creates configuration files in /opt/homebrew/etc/php/7.0/conf.d, /opt/homebrew/etc/php/7.1/conf.d, /opt/homebrew/etc/php/7.2/conf.d, /opt/homebrew/etc/php/7.3/conf.d, /opt/homebrew/etc/php/7.4/conf.d, /opt/homebrew/etc/php/8.0/conf.d, /opt/homebrew/etc/php/81/conf.d and /opt/homebrew/etc/php/82/conf.d respectively. If you want to uninstall a PHP extension, simply rename the .ini file to .ini.bak and restart apache. Alternatively, you can simply use brew to uninstall it, and reinstall it again when you need it.

Grav Premium
Turbo-charge your Grav site - from the creators of Grav