Configure xDebug 3 and VSCode with Docker

Some gotchas while setting these up together with nginx Alpine and PHP-FPM

dev

Created on 31 January 2021.

I wouldn't have thought that I needed to write a post such as this but I found many different resources online that were outdated, presented strange/unnecessary/insecure solutions and so on.

You have come to the right place if:

  • you are using VSCode (Visual Studio Code)
  • you have docker installed; and docker-compose
  • maybe use a container for nginx and another one for php-fpm
  • use xDebug 3 which introduced breaking changes

Here's what we need to take into consideration:

  1. Check that xDebug is installed and loaded in your PHP container
  2. Proper xDebug settings
  3. VSCode is configured to connect to xDebug.

Install xDebug

First things first - install xDebug in your docker container.

I have a container running PHP-FPM. It's built on a PHP-FPM image with a couple of instructions added.

Therefore, I have a very simple Dockerfile with these lines:

FROM php:7.4-fpm

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

And my docker-compose file will have something along these lines:

php:
  build:
    dockerfile: Dockerfile
    context: ./
  networks:
    - app-network
  volumes:
    - ./logs/xdebug:/logs/xdebug
    - ./logs/php-fpm/:/tmp/xdebug_log  

Configure xDebug

Next, we should configure xDebug. What we need to do is have a .ini file with the configuration that we want, and to adjust our php service container to load that file.

Let's start with xdebug.ini

zend_extension = xdebug.so

xdebug.log = "/logs/xdebug/remote.log"
//this path works with the volume already set up in docker-compose where we mount the /logs/xdebug folder. 

xdebug.mode = debug,profile,trace
xdebug.start_with_request = yes
xdebug.discover_client_host = 0
xdebug.client_port = 9003

xdebug.client_host=host.docker.internal

For all options and settings available checkout the official documentation.

The other important bit is the client port. In our example it's 9003. Default value is 9001 for xDebug 3. Nevertheless, this information will be used in the next step, when setting up VSCode.

Finally, let's adjust our docker-compose file. Add a new volume to your php service ./xdebug.ini:/usr/local/etc/php/conf.d/xy-xdebug.ini

This line assumes that your xdebug.ini file is next to your docker-compose file. Adjust the path (the one on the left) as needed.

Restart your docker containers. This can be a good time to check that xDebug is loaded

You can docker exec in your php service and run php -version in bash. This should confirm that xDebug is installed.

Then insert phpinfo() in any page and display it. You can use it to check where php is looking for additional .ini files.

This is useful in case your configuration file doesn't seem to work. Adjust path as needed in the volumes section of your docker-compose.

Install plugin in VSCode

Open Visual Studio Code and install the PHP Debug extension.

That's it! Nothing else to do

Configure VSCode to run the debugger

After the extension is installed, you can open the Debug section from the left menu. And then click on the small cog icon from the top.

Another way would be to go to the main menu, click Debug and select 'Add Configuration...'

Choose your environment - this should be PHP

A new file called launch.json should open up. There should be a configurations variable that holds an array of objects.

Here's a sample of an object:

 {
   "name": "xDebug listen",
   "type": "php",
   "request": "launch",
   "port": 9003,
   "stopOnEntry": true,
   "pathMappings": {
     "/app": "${workspaceFolder}/app"
    }
}

Note 2 things:

  • the port is 9003. This is the same as the one from the xdebug.ini file. Make sure they are the same.
  • pathMappings could be important in making sure xDebug works great.

Let's examine this line "/app": "${workspaceFolder}/app". What's on the left is on your docker. What's on your right is locally.

In the left there's the app folder. This folder is also configured in my nginx as part of the root path for my server-block. Substitute this with what you actually have.

In my nginx service, there's this volume mounted: - ./app:/app

This + the nginx setup (.conf file) = my pathMappings setting.

For clarity, here's an example:

If you have any questions, leave a comment below.


If you enjoyed this article and think others should read it, please share it on Twitter or share on Linkedin.