I have been trying out a new development environment, because I was dissatisfied with both MAMP Pro's performance and Docker for Mac's performance when running PHP applications locally.
I have been using these setups for a couple of years and was wary of trying a manually managed stack of a web server, PHP and database. But with a bit of experience with Caddy and after some benchmarking, I was pleasantly surprised at both the performance and ease of use of this new combination.
What do I need this to do?
I have a couple of expectations of a local development environment, which should be possible for me to consider a setup:
- Works on macOS
- Low verbosity
- Minimal interactions in daily usage
- Multiple PHP versions in parallel
- High performance
MAMP Pro and Docker for Mac had issues, especially with the performance part. This was due to different reasons.
MAMP's PHP has performance problems I don't really understand. I just saw much higher response times when comparing it to a basic PHP installation with Homebrew.
Docker for Mac has problems with I/O performance, especially with the high number of files usually present in a modern PHP application. Attempts with anonymous Docker volumes, mutagen, syncing via rsync or other ideas all felt clunky, brittle or didn't provide much of a performance improvement.
So that led me to a setup with Caddy and PHP via Homebrew.
Install all the PHP versions you want to use for your projects:
brew install [email protected] [email protected] php
Setup PHP-FPM to use different socket files for each version to keep management simple.
$ vim /usr/local/etc/php/7.4/php-fpm.d/www.conf
listen = /usr/local/var/php/php7.4.sock
You can also tune the FPM configuration. Maybe something like this works for you:
pm.max_children = 32
pm.start_servers = 2
pm.min_spare_servers = 2
pm.max_spare_servers = 5
pm.max_requests = 500
Then, you can set up the PHP-FPM services to start automatically:
brew services start [email protected]
brew services start [email protected]
brew services start php
First, install Caddy with
brew install caddy. Open
/usr/local/etc/Caddyfile and add a block for each of your projects, like this:
root * /Users/me/code/my-project/public
php_fastcgi unix//usr/local/var/php/php7.4.sock # or any other PHP version
Start up Caddy once with
caddy run --config /usr/local/etc/Caddyfile to make sure everything works as expected. Caddy will install a certificate in your local key store, so your browsers will accept Caddy's self-generated TLS certificates.
If all is well, you can set up the Caddy service like this:
brew services start caddy
Last, but not least, you have to add your domains to
/etc/hosts to make them accessible by name:
$ sudo vim /etc/hosts
If you're using any other services (like MySQL, Elasticsearch, Redis...) you can start them up whichever way you want. I'm using MySQL via Homebrew, and start up a project-specific Docker container for Redis and Elasticsearch.
This gives me a bit of isolation between project data and makes configuration handling easier.
I have found some important MySQL parameters for Homebrew's MySQL installation. Those gave me a much better performance in Shopware 6, which is what I work with most days. I haven't tuned MySQL much, so take those parameters with a grain of salt.
Use these in your
/usr/local/etc/my.cnf, but make sure you verify them for your use cases and adapt accordingly:
group_concat_max_len = 2048
key_buffer_size = 16777216
max_allowed_packet = 134217728
sync_binlog = 0
table_open_cache = 1024
I currently work with a 16" MacBook Pro 2019 with a 6-core i7 and 32 GB of RAM, to give those numbers some context.
So far, I'm very pleased with this setup. It's fast, easy to use, and removes most of the complexity of local setups in day-to-day usage. Let me know if you like it as well 🙂