Setting Up Laravel Octane with Swoole on MacOS

Swoole or Open Swoole allow for concurrency with Laravel Octane, while RoadRunner does not. This article will cover my experience installing Laravel Octane with Swoole.

Table of Contents

  1. Prerequisites
  2. Installing Swoole
  3. Creating Project
  4. Configuring Environment
  5. Hot Reloading
  6. Troubleshooting

Prerequisites

  1. Homebrew https://brew.sh/
  2. PHP via brew https://formulae.brew.sh/formula/php#default (as of 04 Dec, 2023 PHP 8.1+ is required for Laravel Octane as per Server Prerequisites https://laravel.com/docs/10.x/octane#server-prerequisites)
  3. PECL (comes with PHP via brew)
  4. Composer for PHP dependencies https://getcomposer.org/doc/00-intro.md#installation-linux-unix-macos
  5. Laravel https://laravel.com/docs/10.x/installation#creating-a-laravel-project
  6. Swoole https://github.com/swoole/swoole-src

Additional prerequisites for production-like environment including HTTPS and custom domain support:

  1. NGINX via brew https://formulae.brew.sh/formula/nginx#default
  2. dnsmasq via brew https://formulae.brew.sh/formula/dnsmasq#default
  3. mkcert via brew https://formulae.brew.sh/formula/mkcert#default

Installing Swoole

To use Laravel Octane with Swoole, you need to install Swoole before installing Octane.

To install Swoole, just run pecl install swoole. If you run in any trouble, please refer to troubleshooting. Installation will prompt you with some of the options, select those that you need, here is what I used for my project:

pecl install swoole

# enable sockets supports? [no] : yes
#
# enable openssl support? [no] : yes
# 
# enable mysqlnd support? [no] : yes
# 
# enable curl support? [no] : yes
# 
# enable cares support? [no] : no
# 
# enable brotli support? [yes] : yes
# 
# enable PostgreSQL database support? [no] : yes
# 
# enable ODBC database support? [no] : no
# 
# enable Oracle database support? [no] : no
# 
# enable Sqlite database support? [no] : yes

Creating Project

Create Laravel project as usual:

composer create-project laravel/laravel lara-octane

Then, install Laravel Octane:

cd lara-octane

composer require laravel/octane

php artisan octane:install
# follow terminal prompts to choose between RoadRunner and Swoole

Now, you can start Octane server:

php artisan octane:start --port=8001

Although PHP has built-in web server, and Laravel as well as Laravel Octane supports it out-of-the-box, I wouldn’t recommend using it even for local development. In case of using Laravel Octane, please read Configuring Environment next. Without Octane, I recommend to use Laravel Herd for basic needs.

Configuring Environment

We will configure our local environment to access website via domain (eg lara-octane.test) instead of IP.

dnsmasq

After installing dnsmasq with brew install dnsmasq, locate dnsmasq.conf (should be in /opt/homebrew/etc/), and update address= and listen-address= fields:

# dnsmasq.conf
# ...
address=/.test/127.0.0.1
listen-address=127.0.0.1
# ...

You can also create separate config file for this:

# dnsmasq.conf
# ...
conf-dir=/opt/homebrew/etc/dnsmasq.d # uncomment this
# ...

# dnsmasq.d/test
address=/.test/127.0.0.1
listen-address=127.0.0.1

You might also need to setup DNS resolving:

mkdir -p /etc/resolver
nano /etc/resolver/test

# test
nameserver 127.0.0.1
domain test
search_order 1

Now, when setting up Nginx config for Laravel Octane, you should do a proxy pass:

# lara-octane.test

listen 80;
server_name lara-octane.test;
proxy_pass http://127.0.0.1:$lara_octane_port;

mkcert

To setup https, we need mkcert.

brew install mkcert

mkdir -p /opt/homebrew/Cellar/mkcert/$MKCERT_VER/certificates
cd /opt/homebrew/Cellar/mkcert/$MKCERT_VER/certificates

Then we install local authority and issue as many certificates as we need, you can also issue certificate for multiple domains as well as wildcard subdomains:

mkcert -install
mkcert lara-octane.test

Then, enable https and link to those certificates in Nginx config (notice we change 80 to 443 in listen and http to https in proxy_pass):

# lara-octane.test

listen 443 ssl;
server_name lara-octane.test;

ssl_certificate /opt/homebrew/Cellar/mkcert/$MKCERT_VER/certificates/lara-octane.test.pem;
ssl_certificate_key /opt/homebrew/Cellar/mkcert/$MKCERT_VER/certificates/lara-octane.test-key.pem;

proxy_pass https://127.0.0.1:$lara_octane_port;

Hot Reloading

If you’re using Vite and have dev server running, pages will still detect filechanges like a normal vite dev server would do.

To enable hot reloading of server files, you must install chokidar with npm locally, and then start Octane server:

npm install --save-dev chokidar

php artisan octane:start --watch

You may configure the directories and files that should be watched using the watch configuration option within your application’s config/octane.php configuration file.

Troubleshooting

Libraries or Extensions Will not Load or Wrong PHP Version Used

If you have Laravel Herd installed, it uses its’ own php binary, which can be found under PathToHerd/bin. There should be symlink of php to Herd’s binary, and path to Herd should be added to your $PATH variable. To use Laravel Octane, we must use PHP installed with homebrew, so the safest option would be to remove symlink:

whereis herd

cd PathToHerd/bin

ln -al 

# look for php symlink
rm php

Then, when you need your Laravel Herd server, you can run

herd use 8.3 # or whatever version you use

Can not Load libpq

Locate libpq.pc and extend PKG_CONFIG_PATH:

cd /opt/homebrew && find ./* -name "*libpq.pc*"

export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:${FOLDER_WITH_LIBPQ.PC}

If it is not installed, install one of the options described in output.

# this would be libpq if installed via brew, or you can install postgresql
brew install pibpq
brew install postgresq

Fatal Error: pcre2.h Not Found

This might be pcre2.h, ares.h, or any other library headers depending on your selections during Swoole setup. Example message is as follows:

In file included from /private/tmp/pear/temp/swoole/ext-src/php_swoole.cc:21:

/opt/homebrew/Cellar/php/8.3.0/include/php/ext/pcre/php_pcre.h:23:10: fatal error: 'pcre2.h' file not found

#include "pcre2.h"
         ^~~~~~~~~

Search for libname.h in /opt/homebrew/:

cd /opt/homebrew && find ./ -name "*libname.h*"

If libname.h exists, but not in /opt/homebrew/include, try to brew link parent library. If it does exist in /opt/homebrew/include/, try to extend link:

sudo ln -s /opt/homebrew/include/libname.h /usr/local/include/

Otherwise, install target package with brew:

# install
brew install libname

# link to /opt/homebrew/include/
brew link libname

# link to /usr/local/include
ln -s /opt/homebrew/iclude/libname.h /usr/local/include/

You might need to link included header files multiple times, for example when one header file includes others. You can grep for includes inside those:

cat /opt/homeberew/include/libname.h | grep '#include'

ld: library not found for -lssl

Check for/install openssl with brew, then adjust LIBRARY_PATH:

# openssl should be located in /opt/homebrew/opt/
export LIBRARY_PATH=$LIBRARY_PATH:/opt/homebrew/opt/openssl@1.1/lib/

How to Use C-Ares?

I did not figure this one out. It was not necessary for my project at the moment, so I left this out. You can help with this one via comments below or by contacting me directly. Credit where credit’s due.

Composer segfault

Remove swoole.so extension in php.ini:

php --ini

nano path/to/php.ini

# remove extension=swoole.so, usually first line
$ cd ..