Xdebug Support#
There are two docker containers running FPM, php-fpm
and php-debug
. The php-debug
container has the Xdebug
extension pre-installed. Nginx will automatically route requests to the php-debug
container when the XDEBUG_SESSION
cookie has been set to PHPSTORM
via the Xdebug Helper browser extension.
Xdebug will automatically connect back to the host machine on port 9000
for Xdebug2 and 9003
for Xdebug3 for each
request routed to the php-debug
container (i.e. when the XDEBUG_SESSION
cookie is set). When configuring Xdebug
Helper in your browser, make sure it is setting this cookie with the value PHPSTORM
.
If you use a firewall, allow connection to port 9000
for Xdebug2 and 9003
for Xdebug3.
In similar fashion to the reward shell
command there is also a debug command to launch into an xdebug enabled
container shell for debugging CLI workflows:
reward debug
Xdebug Version#
Reward supports both Xdebug 2 and Xdebug 3 (default).
If you’d like to use Xdebug version 2, you’ll have to configure it explicitly. If it’s empty or omitted, reward defaults to Xdebug 3.
Add the following line to your .env
file:
XDEBUG_VERSION=2
VSCode#
To configure a project in VSCode for debugging, add the following to .vscode/launch.json
in the project directory:
{
"version": "0.2.0",
"configurations": [
{
"name": "Listen for XDebug",
"type": "php",
"request": "launch",
// Change this to 9000 if you are using Xdebug2
"port": 9003,
"pathMappings": {
"/var/www/html": "${workspaceRoot}"
}
}
]
}
Note
If your project has (for example) REWARD_WEB_ROOT=/webroot
in it’s .env
file, to mount webroot/
to /var/www/html
rather than the top-level project directory, you may need to set the pathMapping
above to ${workspaceRoot}/webroot
for the mapping to function correctly.
Once this configuration is in place, make sure you have the PHP Debug extension by Felix Becker installed. This is required for Xdebug support to function in VSCode. Additional information on launch settings specific to Xdebug use in VSCode may be found here.
To learn more about debugging in VSCode, please go here.
PhpStorm#
When it receives the first request, PHP Storm should prompt you if the “Server” configuration is missing. The below image demonstrates how this is set up; the important settings are these:
Name:
clnt-docker
(this is the value of theREWARD_ENV_NAME
variable in the.env
file appended with a-docker
suffix)Host:
127.0.0.1
Port:
80
Debugger: Xdebug
Use path mappings must be enabled, with a mapping to map the project root on the host to
/var/www/html
within the container.
Additional configurations may be required, such as configuring DBGp Proxy
port.
Debugging PHP CLI Commands/Scripts#
You can also debug PHP command line scripts using the following method.
# Open a shell in the environment debug container
reward debug
# Determine the Xdebug host address
php -i | grep -i 'xdebug.*host'
# The result was: 172.24.0.1
# Use the host address with the following example code to run bin/magento command.
# Xdebug2
php -dxdebug.remote_enable=1 -dxdebug.remote_mode=req -dxdebug.remote_port=9000 -dxdebug.remote_host=172.24.0.1 -dxdebug.remote_connect_back=0 bin/magento
# Xdebug3
php -dxdebug.mode=debug -dxdebug.client_host=172.24.0.1 -dxdebug.client_port=9003 -dxdebug.start_with_request=yes bin/magento
Source: Debug a PHP CLI script
Customizing Xdebug Remote Host (or Client Host)#
By default, Xdebug is configured to connect to host.docker.internal
that should resolve to the host machine IP
address.
For some reason in Ubuntu with classic Docker, this does not work. You can customize the remote host by setting the
XDEBUG_REMOTE_HOST
environment variable in the .env
file.
To determine what address should be used, you can run the following command on the host machine:
# determine the ID or the name of the project's docker network
docker network ls
# the output should look like this
NETWORK ID NAME DRIVER SCOPE
9632c97820b4 bridge bridge local
b32df7ba7038 host host local
233d483ba204 magento2_default bridge local
27dcd7a14e50 none null local
044c0e9d99cf reward bridge local
In my case, I’d like to check the network of the project called magento2
, so I’ll need to use the
name magento2_default
or the ID 233d483ba204
.
docker network inspect magento2_default
# the output is a long json, the data we need is in the "IPAM.config.gateway" section
# it's enough to just show the first 20 lines of the output
docker network inspect magento2_default | head -n 20
# or even better if we filter the output
docker network inspect --format "{{(index .IPAM.Config 0).Gateway}}" magento2_default
172.20.0.1
That should output an IP address, that can be added directly to the .env
file.
XDEBUG_REMOTE_HOST=172.20.0.1
If that’s ready, you can restart the php-debug container to apply the changes.
reward env up -- php-debug
Debugging Xdebug instance#
reward debug
sudo bash
cd /etc/php/${PHP_VERSION}/mods-available
vim xdebug.ini
If you are not familiar with vim
, you can use nano
instead. Add the following line to the end of the configuration.
xdebug.remote_log=/proc/self/fd/2
Now save the file and reload the php-fpm configuration using kill -USR2
kill -USR2 1
Exit the container and check its logs.
reward env logs -f php-debug
You should see something like this.
If you still cannot figure out what’s wrong, you should check if you are able to connect to the Xdebug server from the container.
reward debug
sudo bash
apt-get update && apt-get install -y netcat
nc -v host.docker.internal 9003
# the output should be something like this
Connection to host.docker.internal 9003 port [tcp/*] succeeded!
# if you see something like this, then the connection is not working
nc: connect to host host.docker.internal port 9003 (tcp) failed: Connection refused/timed out
# in this case a possible solution would be to update the firewall settings
# for example if you are using Ubuntu, you should enable the traffic from docker network to the host
sudo ufw allow out on docker0 from 172.16.0.0/12
sudo ufw allow in on docker0 from 172.16.0.0/12
sudo ufw reload
# or if the hostname cannot be resolved then you'll see this
nc: getaddrinfo: Name or service not known
# in this case you should use the host machine's IP address instead of the hostname (see the previous section)