Preface: The steps here worked for me on Mac. You may run into issues with Windows if you are using WSL2.
This article describes the steps you need to do to debug WordPress PHP code that is running inside a Docker container. The instructions here are tested to work with a Docker container based on wordpress:php7.4-fpm-alpine image. For other images YMMV when following these instructions (esp. the part where we install Xdebug)
The first step is to install Xdebug which is PHP’s debugger. Do this by running following from inside the Docker container ref (Do not install Xdebug using apk add or you will run into issues ):
apk --no-cache add pcre-dev ${PHPIZE_DEPS} \
&& pecl install xdebug-3.1.6 \
&& docker-php-ext-enable xdebug \
&& apk del pcre-dev ${PHPIZE_DEPS}
pecl is the equivalent of npm for PHP and can be found in /usr/local/bin.
This will do following things:
- build and install Xdebug (I have specified version 3.1.6 because versions higher than 3.1.6 require PHP 8) under
/usr/local/lib/php/extensions/no-debug-non-zts-20190902/xdebug.so - create a
/usr/local/etc/php/conf.d/docker-php-ext-xdebug.inifile with just following line in it:
zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20190902/xdebug.so
Tip: When you open /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini it might already have a line in it:
zend_extension=xdebug.so
You only need one of the two. If you add both, you might see following message in PHP-FPM logs when you restart fpm process:
Cannot load Xdebug - it was already loaded
For more see here.
You can now check if Xdebug is installed successfully by running:
bash-5.0# php -v
PHP 7.4.4 (cli) (built: Mar 24 2020 01:34:16) ( NTS )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies
with Xdebug v3.0.2, Copyright (c) 2002-2021, by Derick Rethans
with Zend OPcache v7.4.4, Copyright (c), by Zend Technologies
If you want to see all the ini files that PHP loads, you can do that by running:
# php --ini
Now to enable remote debugging add following lines to docker-php-ext-xdebug.ini. For Windows see later:
xdebug.mode = debug
xdebug.start_with_request = yes
xdebug.client_port = 9000
xdebug.remote_handler=dbgp
xdebug.client_host=host.docker.internal
xdebug.idekey=VSCODE
xdebug.log=/usr/local/etc/php/xdebug.log
If the log file does not exist one will be created at time of debugging. But it gets created with root as its owner and is inaccessible to the www-data user which is the user php-fpm runs as. So you might as well create the file and chown the owner to www-data.
Refer this page for an explanation of the settings.
Install PHP debug extension for VS Code. After installing the extension, create or open existing launch.json and add following section to it:
{
"name": "Listen for XDebug",
"type": "php",
"request": "launch",
"port": 9000,
"log": true,
"externalConsole": false,
"pathMappings": {
"/var/www/html": "${workspaceRoot}/www-html",
},
"ignore": [
"**/vendor/**/*.php"
]
}
The pathMappings is used to map code inside the Docker container to code stored locally. Correct it as appropriate in your case. The port should match the port declared in xdebug.client_port.
Now run VS Code in debug mode with above configuration. The blue ribbon should turn orange and you will be able to set breakpoints.
Next, we need to restart the php-fpm process for xdebug settings in docker-php-ext-xdebug.ini to take effect. I do this by just restarting the container. An alternate way – one that I haven’t tried – is to run this from inside the container:
# kill -USR2 1
Now you can make a request and the VS Code debugger should break!
You might be wondering two things:
- we have
php-fpmrunning on port 9000 in our Docker container. Then how come we can use same port inxdebug.client_port? - we did not have to publish the port. How come VS Code is able to connect to Xdebug?
The answer is that it works because Xdebug is the client and it is VS Code that is the server in this setup!
If you don’t have VS Code running you will see following errors in Docker log because Xdebug is not able to connect to VS Code:
NOTICE: PHP message: Xdebug: [Step Debug] Could not connect to debugging client. Tried: host.docker.internal:9000 (through xdebug.client_host/xdebug.client_port) 😦
Comment out the xdebug settings (i.e., turn xdebug off) when VS Code is not running to avoid the errors.
Windows Issues
On Windows (Windows 11, Docker Desktop, WSL2) I couldn’t get it to work. I think the underlying issue is some firewall that blocks WSL2 (and thus Xdebug) from connecting to VS Code. You can verify it using the steps described here. Then it randomly worked one day with this config (no guarantees it will continue to work. I am still keeping my fingers crossed):
zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20190902/xdebug.so
xdebug.mode=debug
xdebug.start_with_request=yes
xdebug.client_port=9003
xdebug.remote_handler=dbgp
xdebug.client_host=x.x.x.x
xdebug.discover_client_host=true
xdebug.client_discovery_header=HTTP_FORWARD_HOST
xdebug.remote_enable=1
xdebug.idekey=VSCODE
xdebug.log=/usr/local/etc/php/xdebug.log
where you replace x.x.x.x with
$ ip addr show eth0 | grep -oP '(?<=inet\s)\d+(\.\d+){3}'
Above command has to be run from WSL2 command prompt. Do not run it inside the Docker container. If you are on a home network, the IP that you will get is likely to begin with 192.168. If you get an IP that begins with something else, chances are its not going to work.
Also refer this and this. On second link you can see someone saying:
When I type
ip addr show eth0 | grep -oP '(?<=inet\s)\d+(\.\d+){3}'on my WSL2 terminal, what I get is172.20.111.76. If I use this IP as thexdebug.client_host, Xdebug is not working.
My experience was different. When I ran the command on WSL2 command prompt I got an IP that began with 192.168. 192.168.0.0 is the starting point of the reserved private network space that encompasses all IP addresses through the 192.168.0.0-192.168.255.255 range