Setting up XDebug 3 on a Docker Container with Visual Studio Code

Using and configuring XDebug since the release of version 3 has been a breeze. Similarly, getting XDebug to work when using a Docker Container as a dev environment is equally easy. Follow these steps.

1. Add the installation commands in your Dockerfile

The first step is to install the xdebug module for PHP in the Docker Container. You can do that in the the Dockerfile for the container by adding the following lines (assume lines before and lines after this snippet):


&& pecl install xdebug \ && docker-php-ext-enable xdebug \

2. Update docker-compose.yml

If you are using docker-compose.yml, you will also need to add the following lines to add the internal host, and to set the xdebug environment variables:


extra_hosts: - "host.docker.internal:host-gateway" environment: XDEBUG_MODE: develop,debug XDEBUG_CONFIG: client_host=host.docker.internal start_with_request=yes

3. Update your container’s PHP configuration files

Inside your container’s php.ini file (or docker-php-ext-xdebug.ini, if you have it), add the following lines:

[xdebug]
zend_extension=xdebug
xdebug.mode=develop,debug
xdebug.start_with_request=yes
xdebug.remote_port=9003
xdebug.client_port=9003
xdebug.remote_host=host.docker.internal

4. Start your container and test to make sure everything works

Create a file named xdebug_info.php in your container’s document root, and the following lines to it:

<?php

xdebug_info();

Start your container and visit it in your browser, loading xdebug_info.php. You should see that XDebug is now correctly installed.

5. Setup VSCode to properly connect to XDebug

As a first step, you will need to install a PHP debugging plugin in VSCode. I recommend PHP Debug from the XDebug developers. It’s easy to setup and works very well. You can install it through the plugin tab in VSCode. The plugin repository is here: https://github.com/xdebug/vscode-php-debug.

Next, click the Debug icon in the left sidebar, then under ‘Run’ from the main menu, select ‘Add configuration’. Adjust the launch section of your settings to look like this. Note, adjust the pathMappings entry to match your setup. The ${workspaceFolder} references the folder you open in VSCode. The path on the left side is the path to that folder inside the Docker container.


"launch": { "configurations": [ { "name": "Listen for Xdebug", "type": "php", "request": "launch", "port": 9003 }, { "name": "Listen on Docker for Xdebug", "type": "php", "request": "launch", "port": 9003, "pathMappings": { "/var/www": "${workspaceFolder}" } }, ] }

6. Select a project and debug a file

Open a project folder, and load a file into the editor. In the editor, click beside the line number where you want XDebug to make its first stop and add a breakpoint. A red dot should appear.

Now, click the Debug icon in the left sidebar. At the top of the sidebar, you should now see the debug options you added to your settings file. Select the ‘Listen on Docker for Xdebug’ option, then click the little green arrow beside it.

When XDebug is active, the status bar at the bottom of the editor should become orange. As well, the XDEbug control applet should appear at the top of the editor window.

Because you have setup XDebug to Open With Request you can now simply load your page into your browser. In the editor, you will see script execution stop at your breakpoint, and you can now inspect all breakpoints, the call stack, SuperGlobals, constants and more.

Use the XDebug applet at the top of the editor pane to navigate through your code, stepping over, into or out of functions as you need to.

Addendum

I have discovered through use (and errors, of course), that the pathMappings in your launch.json config are very important. They default above show a path mapping to /var/www on the docker host. In most cases, however, I tend to open the project folder alone in VSCode, not the base Docker shared folder. If the folder you open in VSCode does not match your pathMappings, then XDebug will freeze any and all PHP scripts until you either quit and/or resolve the issue. For me, that meant pathMappings like this:

"pathMappings": {
         "/var/www/code": "${workspaceFolder}"
}

I hope this saves you some of the issues I ran into trying to figure this out.