When we first launched Grav Premium products, we chose Gumroad as our payment and licensing provider. It was quick to set up, easy to integrate, and gave us the licensing capabilities we needed to get started.
However, over time Gumroad changed how they handle their callback and webhook system. This meant we were no longer able to maintain the seamless integration we had when we first launched. Purchases and license management became more disconnected than we wanted, and the experience wasn't up to the standard we hold ourselves to.
Rather than work around those limitations, we decided to build something better from the ground up.
We've built a completely custom Licensing Portal that puts you in full control of your Grav Premium licenses. Here's what you can expect:
Centralized License Management - Log in and see all your licenses in one place. No more hunting through old emails trying to find a license key.
Seamless Purchase Flow - When you purchase a premium product, you're taken directly back to the portal where your new license is ready and waiting. The whole lifecycle from purchase to installation is smooth and connected.
Easy License Recovery - Lost a license key? Simply log into the portal to retrieve it along with installation instructions.
Consistent Experience - Whether you're buying from the Grav Premium page, the Downloads page, or directly from the Admin plugin, all purchase links now go through our licensing system.
If you purchase Grav Premium products through the Admin plugin, you'll need to update to the latest version for the new purchase links to work correctly. The old Gumroad links are no longer active.
You can update the Admin plugin through the admin dashboard as you normally would, or via the CLI with:
bin/gpm update admin
Existing licenses purchased through Gumroad continue to work. Your license keys are still valid and will function as before for downloads and updates. The change only affects how new purchases are made.
This is a brand new system, and while we've tested it thoroughly, we know that real-world usage is the true test. If you run into any issues with the new licensing portal or purchase process, please don't hesitate to reach out:
We'll get any problems sorted as quickly as possible. Thank you for your continued support of Grav and Grav Premium!
]]>TLDR: This document outlines the steps required to upgrade an existing Tailwind 3 version of the Typhoon Premium Theme to Tailwind 4.
This is a major update and probably worth your while getting your theme updated to ensure you can take advantage of all the cool new stuff available as part of the Tailwind CSS v4.0 release.
There are fundamental architectural changes in version 4 that requires an initial automatic migration process, followed by some CLI work to upgrade tailwind and modify some scripts, then various fixes in the CSS files to address changed classnames, and lastly some fixes to ensure CSS is loaded with the same specificity as the existing version to minimize the customization to CSS. There's a lengthy Upgrade Guide available in the TailwindCSS documentation, but this guide below shows you the bits specific for Typhoon's configuration.
The first step in the process is to use the TailwindCSS automatic migration. In order to do this, we first have to cleanup our tailwind.config.js a little bit or the migration will error.
Open up the tailwind.config.js file in your editor and remove the normalize() method that wraps the exports content and because that's removed you can also remove the related consts:
Before:
const colors = require('tailwindcss/colors');
const path = require('path');
const process = require('process');
const dirname = process.env.PWD || process.cwd();
const normalize = (paths) => {
return paths.map((_path) => path.normalize(`${dirname}/${_path}`));
}
module.exports = {
content: normalize([
'../../config/**/*.yaml',
'../../pages/**/*.md',
'./blueprints/**/*.yaml',
'./js/**/*.js',
'./templates/**/*.twig',
'./typhoon.yaml',
'./typhoon.php',
'./available-classes.md',
'../../plugins/sandbox-support/templates/**/*.twig',
]),
...
After:
const colors = require('tailwindcss/colors');
module.exports = {
content:[
'../../config/**/*.yaml',
'../../pages/**/*.md',
'./blueprints/**/*.yaml',
'./js/**/*.js',
'./templates/**/*.twig',
'./typhoon.yaml',
'./typhoon.php',
'./available-classes.md',
'../../plugins/sandbox-support/templates/**/*.twig',
],
normalize() was used to get the full path of each of the exports in order to handle symlinks better. This is really only used when your theme is symlinked inside a project. This is quite rare, and generally not needed anymore with Tailwind's improved search mechanism.
Next remove the incompatible plugins multi-column and debug-screens. Luckily TailwindCSS now has great support for CSS columns and this plugin is no longer required. The debug-screens plugin was useful to see the screen size, but it's not essential and is not currently supported in Tailwind4.
Before:
plugins: [
require('@tailwindcss/typography'),
require('@tailwindcss/forms'),
require('tailwindcss-multi-column')(),
require('tailwindcss-debug-screens'),
],
After:
plugins: [
require('@tailwindcss/typography'),
require('@tailwindcss/forms'),
],
Then remove those too plugin dependencies:
npm remove tailwindcss-debug-screens tailwindcss-multi-column
Now we can run the automated upgrade process which will update the NPM packages, make changes to twig templates to switch any old class names to new ones. Run this from the root of your Typhoon (or Typhoon derived theme):
npx @tailwindcss/upgrade
You should get some output similar to this:
➜ npx @tailwindcss/upgrade
≈ tailwindcss v4.0.3
fatal: not a git repository (or any of the parent directories): .git
│ Searching for CSS files in the current directory and its subdirectories…
│ ↳ Linked `./tailwind.config.js` to `./css/site.css`
│ Migrating JavaScript configuration files…
│ ↳ The configuration file at `./tailwind.config.js` could not be automatically migrated to the new CSS configuration
│ format, so your CSS has been updated to load your existing configuration file.
│ Migrating templates…
│ ↳ Migrated templates for configuration file: `./tailwind.config.js`
│ Migrating stylesheets…
│ ↳ Migrated stylesheet: `./css/site.css`
│ Migrating PostCSS configuration…
│ ↳ The PostCSS config contains dynamic JavaScript and can not be automatically migrated.
│ Updating dependencies…
│ ↳ Updated package: `tailwindcss`
At this point you should be upgrade to TailwindCSS 4.0, however you will note in the output of the migration command a few things could not be automatically migrated. Regarding the tailwind.config.js we'll leave this as is and not manually migrate to the new 4.0 way of doing things entirely with CSS variables. We'll stick to importing the existing tailwind js file for now. We do have to fix the PostCSS configuration however.
First we need to modify the postcss.config.js file. It only needs a single command now, and it should be renamed to postcss.config.mjs as it's now an ES module.
Before (postcss.config.js):
module.exports = {
plugins: [
require('postcss-import'),
require('tailwindcss/nesting'),
require('tailwindcss'),
require('autoprefixer'),
],
}
After (postcss.config.mjs):
export default {
plugins: {
"@tailwindcss/postcss": {},
},
};
We need to be able to use the CLI commands, and there are no longer included in the tailwindcss binary so we need to manually install this package:
npm install @tailwindcss/cli
Also, the commands in the package.json to kick of the dev and prod processes to compile the CSS with postCSS need to be modified.
NOTE: if you have the old
watchandbuildcommands you can remove those now, as we have moved todevandwatchbut they do the same thing as before.
Before:
"scripts": {
"dev": "tailwindcss -i ./css/site.css -o ./build/css/site.css --postcss --watch --minify --verbose",
"prod": "NODE_ENV=production tailwindcss -i ./css/site.css -o ./build/css/site.css --postcss --minify"
},
After:
"scripts": {
"dev": "npx @tailwindcss/cli -i ./css/site.css -o ./build/css/site.css --watch --minify --verbose",
"prod": "NODE_ENV=production npx @tailwindcss/cli -i ./css/site.css -o ./build/css/site.css --minify"
},
NOTE: the command has been changed from
tailwindcssto@tailwindcss/cliand we no longer need the--postcssflag.
Now we can try to compile the CSS with the CLI command:
npm run dev
> [email protected] dev
> npx @tailwindcss/cli -i ./css/site.css -o ./build/css/site.css --watch --minify --verbose
Error: Cannot apply unknown utility class: bg-opacity-10
As you can see we have an error that is due to a deprecated class being used. It's time for some cleanup!
There are quite a few deprecated utilities and these will throw an error. The previous compile told us that bg-opacity-10 class is deprecated and this is correct, you know set the opacity on the bg color itself with the /10 modifier. In this case, I searched the files in Typhoon for bg-opacity- and found the culprit in css/custom/dark.css line 17:
Before:
pre {
@apply bg-blue-300 bg-opacity-10 text-blue-200;
}
After:
pre {
@apply bg-blue-300/10 text-blue-200;
}
This one change allowed me to run the dev command and get a successful compile:
npm run dev
> [email protected] dev
> npx @tailwindcss/cli -i ./css/site.css...
]]>
The CMS Critic Awards Are Back — Nominations successful, now please VOTE for Grav
🙏 Thanks to everyone that helped nominate Grav in this years CMS Critic Awards. The turnout was great and we were nominated in a total of 4 categories!
Voting closes on February 24th, 2025, so there's only a small window to get your vote in to ensure Grav can win some (All 😊) of these categories!
The process is quick and easy, just visit: https://cmscritic.com/vote and enter your name + email, then select Grav in the dropdowns for the following categories:
We face some stiff competition as usual, but with our amazing open source powered community I'm sure we can overcome some of these larger and more well-funded projects. Thanks again!
]]>The CMS Critic Awards Are Back — Time to Show Grav Some Love!
Get ready to crank up the excitement because the CMS Critic Awards are here, and it's your chance to shine a spotlight on our favorite flat-file CMS: Grav!
In the past, Grav has snagged awards for Best Flat File CMS and Best Open Source CMS, and even landed nominations for Best Blogging Software and Best CMS for Education. Now we’re aiming to keep that winning streak going in 2025 and beyond—but we can’t do it without you.
By nominating Grav, you’re helping us secure a spot on this year’s voting card. Every nomination boosts our visibility, draws in more users, and sparks the interest of developers, theme designers, and plugin creators who can help supercharge Grav for everyone.
Simply put: more nominations mean more people learn about Grav, and that means we get to innovate even faster!
Ready to lend a hand? It’s simple:
The whole process takes just a minute, but your impact could last for years. More nominations → more eyes on Grav → even more awesome additions to our ecosystem.
Thanks a million for being such an amazing part of the Grav community. Your passion and dedication inspire us every day. Together, we can keep pushing Grav to new heights—and shape the future of CMS in the process!
Nominate Grav Today: CMSCritic.com
]]>The current stable release of Grav 1.7 requires PHP 7.3.6, which ended security fix status in December 2021. We can't update to newer libraries that support PHP 8.4 and still maintain support for PHP 7.3, as it would result in breaking compatibility. Enter Grav 1.8.
Grav 1.8, which is currently in a beta release phase, focuses on updating Grav itself to be fully compatible with PHP 8.4 while also updating the underlying supporting libraries to much more recent versions that also support PHP 8.4. This does mean that we have to up our base PHP requirements for Grav 1.7 to PHP 8.2 as this is a good common lowest level that all the required libraries support. PHP 8.2 was released in December 2022, and is actively supported until December 2025, with security updates planned until December 2026.
Grav relies on many great libraries such as various Symfony framework libraries for caching, yaml, http-client, processing, etc., and we can jump from version 4.4 all the way up to the very latest 6.4, taking advantage of fixes and new functionality. Also, we can move from Twig 1 to Twig 2, but unfortunately not to Twig 3. The problem with our Twig requirement is that plugins and themes rely on the ability to use the Twig Defer extension to add CSS/JS assets to themes, but this extension is not compatible (and may never be) with Twig 3. Upgrading to Twig 3 would effectively break every Grav site, so until we have a suitable solution, we cannot entertain a move to Twig 3.
Along with updates to Grav itself, quite a few other plugins will require updating to fully support PHP 8.4. The good news is that this can usually be handled with code that is backwards compatible even down to PHP 7.3, so this is a fairly clean process. Quite a few plugins have already been released with these PHP 8.4 fixes in preparation for Grav 1.8's final release.
Please help us out by testing the beta release on a 'copy' of you sites. It's not recommend for use in production yet, however i've been daily driving Grav 1.8 beta for the past few months and have been fixing issues in it, and plugins and themes as I find them. But I alone cannot test every situation that might arise, I need your help to ensure that 1.8 is thoroughly tested before it gets a stable release.
Check out the Download Grav page and try out the latest 1.8.0 beta release available.
I will be putting together an upgrade document for developers for Grav 1.8 to outline a few and relatively simple solutions to issues you might run across in your plugins that will be required in order to fully support Grav 1.8 specifically but also PHP 8.4 in general. So stay tuned for that coming soon!
Thanks!
-- Andy Miller (Grav Maintainer + Lead Developer)
]]>We have tried to find a solution that will allow the plugin to continue to function, but it seems the functionality available in the Basic Display API, is not available in the regular Instagram API. Even if it was, the regular API has further restrictions requiring a Business or Creator account in order to use it. It really seems like Meta is clamping down on external viewing of Instagram imagery, unless you use their very limited embed options.
Because of this API deprecation, we have been forced to remove the Instagram API from our list of premium plugins.
Users of Instagram Feed should disable this plugin before the December 4th, 2024 cutoff to ensure your site does not error out.
If you have purchased the Instagram Feed plugin in the last 3 months and would like a refund, please contact us at premium@getgrav.org.
]]>This is a guide to help those with prior Homebrew mutliple PHP-based installations that are looking to upgrade to the new Hombrew/core PHP setup from the prior Homebrew/php keg which is now deprecated.
With the deprecation of Homebrew/php tap, many of the prior formulaes we used in this guide are no longer available. The cleanest way to migrate from the old brew formulae to the new pecl package approach is to remove everything PHP-related and reinstall with the new instructions.
The first step in this process is to update all the latest packages then upgrade them. This will actually 'migrate' the core PHP packages (which are the only ones supported), but there's a bunch of symlinks utilized that could cause problems down the road, so after upgrading, we'll remove all PHP packages, to provide a fresh start:
brew update
brew upgrade
brew cleanup
You can then double check the current installed PHP packages with:
brew list | grep php
Now we just need to remove everything:
brew uninstall --force php56 php56-apcu php56-opcache php56-xdebug php56-yaml
brew uninstall --force php70 php70-apcu php70-opcache php70-xdebug php70-yaml
brew uninstall --force php71 php71-apcu php71-opcache php71-xdebug php71-yaml
brew uninstall --force php72 php72-apcu php72-opcache php72-xdebug php72-yaml
brew uninstall --force php80 php80-apcu php80-opcache php80-xdebug php80-yaml
brew uninstall --force php81 php81-apcu php81-opcache php81-xdebug php81-yaml
brew uninstall --force php82 php82-apcu php82-opcache php82-xdebug php82-yaml
brew cleanup
Don't worry if you don't have all these packages installed, this is just a cumulative list and it will skip over anything that's not installed.
Now we can check to see if anything PHP-related is left:
brew list | grep php
If you don't see anything you are all good. If something is still left, you can uninstall those individually using the same brew uninstall --force syntax as above.
Now we want to clean out the old configuration options for PHP:
rm -Rf /usr/local/etc/php/*
Now you've cleaned up your prior installation, you can jump to the PHP Installation section of Part 1 of the guide.
]]>In Part 1 of this 3-part series, we covered configuring Apache on macOS Big Sur 11.0 to work better with your local user account, as well as the installation process for installing multiple versions of PHP. In Part 2, we covered installing MySQL, Virtual Hosts, APC caching, YAML, and Xdebug.
In this Part 3, we will cover getting your site setup with LetsEncrypt SSL support for this setup.
This guide is intended for experienced web developers. If you are a beginner developer, you will be better served using MAMP or MAMP Pro.
In order to get SSL setup and running properly four our Homebrew-powered Apache setup, we need to first create an SSL Certificate. This used to be a pain and cost money for a valid SSL certificate, but thankfully we now have Let's Encrypt, a non-profit Certificate Authority that provides certificates to 225 million websites!
This does require that you have registered a domain name with a company such as Hover, GoDaddy, Network Solutions, etc. You should configure this so that a valid host is available to point to your local webserver. You will probably also need to setup port forwarding so your external IP address is routed internally to your webserver. Usually this consists of setting up a port forward for HTTP, HTTPS with ports 80 and 443 to the internal IP address of your computer.
This is a process that depends on several factors:
I'll leave this process up to you as it might require some Googling to get the this process setup depending all the factors listed above. A quick way to test if you have things setup is to try reaching host via your phone or some other device that is not on your internal network.
Let's assume you have registered the domain grav.rocks (p.s. I already own this one, you need to use your own!), and you have configured the host dev.grav.rocks to be port-forwarded to your local development machine. You have tested this and you can confirm that when you browse to http://dev.grav.rocks on your phone, you are indeed seeing the webserver of your internal network. You have successfully configured remote access, but now you want to get SSL working.
Throughout this guide I use dev.grav.rocks as an example host. You will need to replace this with your own hostname
Now you have a valid host that is accessible from the internet, we need to generate a valid LetsEncrypt SSL certificate. First we should install the certbot tool that will facilitate this process:
brew services stop httpd
brew update
brew upgrade
brew install certbot
To be able to use certbot in a non-root setup (like we have with Brew), we need to create a cli.ini file so that the certbot command will use local paths rather than root access-only system paths:
mkdir -pv ~/.config/letsencrypt
code ~/.config/letsencrypt/cli.ini
This assumes you have Visual Studio Code installed and have enabled the CLI code command. See the first part of this series to find out more about this.
In this new file paste the following:
work-dir = /opt/homebrew/etc/certbot
logs-dir = /opt/homebrew/etc/certbot/logs
config-dir = /opt/homebrew/etc/certbot/certs
Save the file.
Now we can run certbot without requiring sudo which would limit our ability to run Apache as a non-root user.
certbot certonly --standalone
This kicks off a process that requires your response in a few places. Enter email address, agree to Terms of Services, Choose Y or N to join mailing list. Lastly when prompted, enter the name of the host you want to use, e.g. dev.grav.rocks.
Certbot will then try to authenticate by challenging the domain names provided:
Obtaining a new certificate
Performing the following challenges:
http-01 challenge for dev.grav.rocks
Waiting for verification...
Cleaning up challenges
Non-standard path(s), might not work with crontab installed by your operating system package manager
If successful, certbot will generate a fullchain.pem and a privkey.pem file that we can use to configure our SSL certificate in the Apache configuration. The output should look something like this:
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at:
/opt/homebrew/etc/certbot/certs/live/dev.grav.rocks/fullchain.pem
Your key file has been saved at:
/opt/homebrew/etc/certbot/certs/live/dev.grav.rocks/privkey.pem
Your cert will expire on 2021-02-12. To obtain a new or tweaked
version of this certificate in the future, simply run certbot
again. To non-interactively renew *all* of your certificates, run
"certbot renew"
- Your account credentials have been saved in your Certbot
configuration directory at /opt/homebrew/etc/certbot/certs. You should
make a secure backup of this folder now. This configuration
directory will also contain certificates and private keys obtained
by Certbot so making regular backups of this folder is ideal.
- If you like Certbot, please consider supporting our work by:
The important parts to jot down are the full paths to the .pem files which we'll use in the following section:
Certificate: /opt/homebrew/etc/certbot/certs/live/dev.grav.rocks/fullchain.pem
Key File: /opt/homebrew/etc/certbot/certs/live/dev.grav.rocks/privkey.pem
The first step is to make some modifications to your httpd.conf:
code /opt/homebrew/etc/httpd/httpd.conf
In this file you should uncomment both the socache_shmcb_module, ssl_module, and also the include for the httpd-ssl.conf by removing the leading # symbol on those lines:
LoadModule socache_shmcb_module lib/httpd/modules/mod_socache_shmcb.so
...
LoadModule ssl_module lib/httpd/modules/mod_ssl.so
...
Include /opt/homebrew/etc/httpd/extra/httpd-ssl.conf
Next we need to change the default 8443 port to the more standard 443 and comment out some sample code. So we need to open the SSL config file:
code /opt/homebrew/etc/httpd/extra/httpd-ssl.conf
find:
Listen 8443
replace it with:
Listen 443
then find:
<VirtualHost _default_:8443>
# General setup for...
]]>
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.
This guide is intended for experienced web developers. If you are a beginner developer, you will be better served using MAMP or MAMP Pro.
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.
Next we need to install TablePlus with Homebrew (it's awesome and there's a free version!).
brew install --cask tableplus
You should be create a new MySQL connection by clicking the +, give it a Name and check Use socket option after you enter a User of root and your newly created password.

If you need to stop the server, you can use the simple command:
brew services stop mariadb
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.
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.
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.
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.3 | Xdebug 3.3 |
| PHP 8.4 | not available |
To install specific versions of...
]]>Developing web applications on macOS is a real joy. There are plenty of options for setting up your development environments, including the ever-popular MAMP Pro that provides a nice UI on top of Apache, PHP and MySQL. However, there are times when MAMP Pro has slow downs, or out of date versions, or is simply behaving badly due to its restrictive system of configuration templates and non-standard builds.
It is times like these that people often look for an alternative approach, and luckily there is one, and it is relatively straight-forward to setup.
In this blog post, we will walk you through setting up and configuring Apache 2.4 and multiple PHP versions. In the second blog post in this two-post series, we will cover MySQL, Apache virtual hosts, APC caching, and Xdebug installation.
If you have followed this guide in the past with the Homebrew/php tap, and are looking to upgrade to the new Homebrew/core approach, then you should first clean-up your current installation by following our new Upgrading Homebrew.
This guide is intended for experienced web developers. If you are a beginner developer, you will be better served using MAMP or MAMP Pro.
If you don't already have XCode installed, it's best to first install the command line tools as these will be used by homebrew:
xcode-select --install
This process relies heavily on the macOS package manager called Homebrew. Using the brew command you can easily add powerful functionality to your mac, but first we have to install it. This is a simple process, but you need to launch your Terminal (/Applications/Utilities/Terminal) application and then enter:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
Just follow the terminal prompts and enter your password where required. This may take a few minutes.
If this is a fresh install and you don't have your path setup properly, you can follow the installation "next steps" which are already customized for you, or you can manually add the following paths to your .bashrc or .zshrc:
(echo; echo 'eval "$(/opt/homebrew/bin/brew shellenv)"') >> ~/.zprofile
eval "$(/opt/homebrew/bin/brew shellenv)"
Now you can test your installation to ensure you have installed brew correctly, simply type:
brew --version
Homebrew 4.3.23
You should probably also run the following command to ensure everything is configured correctly:
brew doctor
It will instruct you if you need to correct anything.
When installing fresh on Sequoia, I ran into a few libraries that were missing when completing all the steps below. To make things easier, please simply run this now:
brew install openssl
The latest macOS 13.0 Sequoia comes with Apache 2.4 pre-installed, however, it is no longer a simple task to use this version with Homebrew because Apple has removed some required scripts in this release. However, the solution is to install Apache 2.4 via Homebrew and then configure it to run on the standard ports (80/443).
If you already have the built-in Apache running, it will need to be shutdown first, and any auto-loading scripts removed. It really doesn't hurt to just run all these commands in order - even if it's a fresh installation:
sudo apachectl -k stop
sudo launchctl unload -w /System/Library/LaunchDaemons/org.apache.httpd.plist 2>/dev/null
Now we need to install the new version provided by Brew:
brew install httpd
Without options, httpd won't need to be built from source, so it installs pretty quickly. Upon completion you should see a message like:
🍺 /opt/homebrew/Cellar/httpd/2.4.62: 1,664 files, 32.2MB
Now we just need to configure things so that our new Apache server is auto-started
brew services start httpd
You now have installed Homebrew's Apache, and configured it to auto-start with a privileged account. It should already be running, so you can try to reach your server in a browser by pointing it at http://localhost:8080, you should see a simple header that says "It works!".

If you get a message that the browser can't connect to the server, first check to ensure the server is up.
ps -aef | grep httpd
You should see a few httpd processes if Apache is up and running.
Try to restart Apache with:
brew services restart httpd
You can watch the Apache error log in a new Terminal tab/window during a restart to see if anything is invalid or causing a problem:
tail -f /opt/homebrew/var/log/httpd/error_log
Apache is controlled via the brew services command so some useful commands to use are:
brew services stop httpd
brew services start httpd
brew services restart httpd
In past guides, I've always provided instructions to edit files using the default TextEdit application that comes pre-installed. However, this is not what I use myself as it's a terrible editor and when testing my guide for Sequoia, I kept running into problems with encoding, finding line numbers etc. The better solution is to simply install a better editor. So please install the amazingly versatile yet, 100% free, Visual Studio Code. It's available on Mac, Windows, and Linux, but right now we only care about the mac version.
We can make use of the HomeBrew and install VSCode and the accompanying code CLI command in one shot with:
brew install --cask visual-studio-code
If you already have Visual Studio Code installed, you can easily create a code symlink with:
ln -s /Applications/Visual\ Studio\ Code.app/Contents/Resources/app/bin/code /opt/homebrew/bin/code
Now that we have a working web server, we will want to do is make some configuration changes so it works better as a local development server.
In the latest version of Brew, you have to manually set the listen port from the default of 8080 to 80, so we will need to edit Apache's configuration file /opt/homebrew/etc/httpd/httpd.conf.
If you followed the instructions above you should be able to use Visual Studio Code to edit your files using the code Terminal command. However, if you want to use the default TextEditor application to perform...