You can use RoadRunner with the Xdebug extension. To enable it, configure your IDE to accept remote connections.
{% hint style="info" %} If you run multiple PHP processes you have to extend the maximum number of allowed connections to the number of active workers, otherwise some calls would not be caught on your breakpoints. {% endhint %}
To activate Xdebug, set xdebug.mode=debug in your php.ini.
To enable Xdebug in your application, set the environment variable XDEBUG_SESSION:
{% code title=".rr.yaml" %}
version: "3"
rpc:
listen: tcp://127.0.0.1:6001
server:
command: "php worker.php"
env:
XDEBUG_SESSION: 1
http:
address: "0.0.0.0:8080"
pool:
num_workers: 1
debug: true{% endcode %}
Please keep in mind this guide: xdebug3.
You should be able to use breakpoints and view state at this point.
{% code %}
export PHP_IDE_CONFIG="serverName=octane-app.test"
export XDEBUG_SESSION="mode=debug start_with_request=yes client_host=127.0.0.1 client_port=9003 idekey=PHPSTORM"
php -dvariables_order=EGPCS artisan octane:start --max-requests=250 --server=roadrunner --port=8000 --rpc-port=6001 --watch --workers=1{% endcode %}
The application image below uses the official RoadRunner v3 image.
First, create a docker-compose.yml file in your project root, or copy the environment and extra_hosts sections into your existing docker-compose.yml:
{% code title="docker-compose.yml" %}
services:
api:
build:
context: ./
dockerfile: Dockerfile
container_name: projectName-api
command: rr serve -c .rr.yaml
tty: true
ports:
- "8080:8080"
volumes:
- ./api:/app
networks:
- default
environment:
- PHP_IDE_CONFIG=serverName=docker
extra_hosts:
- "host.docker.internal:host-gateway"{% endcode %}
Create api/public/ for the static middleware. Put the PHP worker and its Composer dependencies in api/, which is mounted at /app. Create api/.rr.yaml with this configuration:
{% code title=".rr.yaml" %}
version: "3"
rpc:
listen: 'tcp://127.0.0.1:6001'
http:
address: '0.0.0.0:8080'
middleware:
- gzip
- static
static:
dir: public
forbid:
- .php
- .htaccess
pool:
debug: true
num_workers: 1
supervisor:
max_worker_memory: 100
server:
command: 'php app.php'
relay: pipes
env:
XDEBUG_SESSION: 1
metrics:
address: '127.0.0.1:2112'{% endcode %}
Next, create a Dockerfile in your project root or copy the following content:
{% code title="Dockerfile" %}
FROM ghcr.io/roadrunner-server/roadrunner:3.0.0 AS roadrunner
FROM php:8.5-cli-alpine
ENV XDEBUG_VERSION=3.5.3
RUN apk add --no-cache autoconf g++ make postgresql-dev coreutils --update linux-headers \
&& pecl install xdebug-$XDEBUG_VERSION \
&& rm -rf /tmp/pear \
&& docker-php-ext-configure pgsql --with-pgsql=/usr/local/pgsql \
&& docker-php-ext-install pdo_pgsql sockets \
&& docker-php-ext-enable xdebug \
&& apk del linux-headers make g++ autoconf
RUN mv $PHP_INI_DIR/php.ini-development $PHP_INI_DIR/php.ini
COPY xdebug.ini /usr/local/etc/php/conf.d/xdebug.ini
RUN curl -sS https://getcomposer.org/installer | php \
&& mv composer.phar /usr/local/bin/composer \
&& chmod +x /usr/local/bin/composer
RUN addgroup -g 1000 app && adduser -u 1000 -G app -s /bin/sh -D app
WORKDIR /app
COPY --from=roadrunner /usr/bin/rr /usr/local/bin/rr
RUN chown app:app /usr/local/bin/rr && chmod +x /usr/local/bin/rr
USER app{% endcode %}
The example uses Xdebug 3.5.3 and runs as the app user.
Next, create an xdebug.ini file in your project root or copy the following content:
{% code title="xdebug.ini" %}
xdebug.mode=develop,debug
xdebug.start_with_request=yes
xdebug.discover_client_host=0
xdebug.client_host=host.docker.internal
xdebug.client_port=9003
xdebug.log=/dev/stdout
xdebug.log_level=0{% endcode %}
Next, change the settings in your IDE so it can accept remote connections. For example, in PhpStorm go to PHP > Debug and set the following options:
Next, create a Server entry in your IDE. For example, in PhpStorm go to PHP > Servers and set the following options:
Also check the Docker settings in your IDE. For example, in PhpStorm go to Build, Execution, Deployment > Docker and set the following options:
- Xdebug 3 installed and properly configured.
- Number of jobs workers set to
1withjobs.pool.num_workersconfiguration option in.rr.yaml.
If you have any active Xdebug listener while starting RoadRunner with Xdebug enabled, disable it. This will prevent a false-positive debug session.
Once RoadRunner starts all workers, enable XDebug listener and reset jobs workers with:
./rr reset jobsNow you should see the debug session started:
- Step over to where the job task is being resolved with
$consumer->waitTask(). - As soon as you reach it, the debugger stops but the session remains active.
- Trigger task consumption with either an HTTP request or a console command (depending on how your application works), and continue debugging the job worker within the active session.
- You can continue debugging jobs as long as the debug session is active.
If the connection/session is broken or times out, you can repeat the instructions above to reestablish the connection by resetting job workers.



