In this tutorial, we will look into how to set up PhpStorm to use Xdebug in a dockerized PHP project. For a non-trivial PHP project example, we choose the development of a WordPress theme.
Table of Contents
PhpStorm is a popular PHP IDE with many useful features including Docker and Xdebug support. In this tutorial, we are using version 2019.3.2.
You will need the Xdebug helper for Chrome or an equivalent helper for other browsers.
This tutorial is written for Windows 10 and Docker Desktop running Linux containers. Make sure the Docker Daemon is exposed on port 2375. To check if it is, go to Settings > Generaland tick the respective checkbox:
The version of WordPress we are going to work with is 5.4.1. It should work also with newer versions: download the most recent WordPress and update the reference to the newer WordPress Docker image in the Dockerfile that is mentioned below.
The WordPress theme that is the subject of this development project can be a scratch-built custom one or a modification of an existing theme. For simplicity’s sake, we will be debugging an existing theme BeOnePage Lite by BeTheme.
The companion repository for this tutorial can be found on GitHub: wordpress_xdebug
The project will use a container built from an official WordPress image. The tag used in this project is
In an empty project folder, we create a docker-compose configuration file,
docker-compose-local.yml. In this file, we define two services. The first one is for the database server:
db: image: mysql:8.0 container_name: db_blog_xdb restart: unless-stopped env_file: .env environment: MYSQL_ROOT_PASSWORD: $MYSQL_ROOT_PASSWORD MYSQL_USER: $MYSQL_USER MYSQL_PASSWORD: $MYSQL_PASSWORD MYSQL_DATABASE: $DB_NAME ports: - 42333:3306 volumes: - dbdata:/var/lib/mysql command: '--default-authentication-plugin=mysql_native_password' networks: - app-network
file docker-compose-local.yml, line 4
This is a simple database service configuration that uses an official MySQL image. It reads environment variable values from the
.env file and maps to the host port 42333 to allow MySQL clients that run on the host machine to connect to the database.
The second service runs the WordPress code:
wp: depends_on: - db build: context: ./ dockerfile: Dockerfile_local container_name: wp_blog_xdb restart: unless-stopped env_file: .env ports: - "80:80" environment: WORDPRESS_DB_HOST: db:3306 WORDPRESS_DB_USER: $MYSQL_USER WORDPRESS_DB_PASSWORD: $MYSQL_PASSWORD WORDPRESS_DB_NAME: $DB_NAME XDEBUG_CONFIG: remote_host=host.docker.internal volumes: - ./src/wordpress:/var/www/html - ./src/themes/beonepage:/var/www/html/wp-content/themes/beonepage networks: - app-network
file docker-compose-local.yml, line 22
The build instructions for this image will be available in a separate Dockerfile. Note that we bind two project directories as volumes:
./src/wordpress/ for the core WordPress files and
./src/themes/beonepage that hosts the files for the custom theme.
We place the core WordPress files into a separate directory so that we could exclude it from the repository using
.gitignore. We do not need the core files to be deployed live from the repository, because they will be provided by a WordPress official image that will be the basis for the live version of the container. But in the development environment, we still need the core files in the project to step into them when debugging.
.env file is used by both services contains variables and is required for the MySQL operation. This file’s content is simple:
MYSQL_ROOT_PASSWORD=password MYSQL_USER=db_admin MYSQL_PASSWORD=password DB_NAME=my_blog_db
The full content of the
docker-compose-local.yml file is this:
version: "3" services: db: image: mysql:8.0 container_name: db_blog_xdb restart: unless-stopped env_file: .env environment: MYSQL_ROOT_PASSWORD: $MYSQL_ROOT_PASSWORD MYSQL_USER: $MYSQL_USER MYSQL_PASSWORD: $MYSQL_PASSWORD MYSQL_DATABASE: $DB_NAME ports: - 42333:3306 volumes: - dbdata:/var/lib/mysql command: '--default-authentication-plugin=mysql_native_password' networks: - app-network wp: depends_on: - db build: context: ./ dockerfile: Dockerfile_local container_name: wp_blog_xdb restart: unless-stopped env_file: .env ports: - "80:80" environment: WORDPRESS_DB_HOST: db:3306 WORDPRESS_DB_USER: $MYSQL_USER WORDPRESS_DB_PASSWORD: $MYSQL_PASSWORD WORDPRESS_DB_NAME: $DB_NAME XDEBUG_CONFIG: remote_host=host.docker.internal volumes: - ./src/wordpress:/var/www/html - ./src/themes/beonepage:/var/www/html/wp-content/themes/beonepage networks: - app-network volumes: dbdata: networks: app-network: driver: bridge
For the service wp, we need a custom image based on WordPress docker image tagged
5.4.1-php7.2-apache. We name the Dockerfile
Dockerfile_local and add instructions there that install and enable the Xdebug extension:
FROM wordpress:5.4.1-php7.2-apache RUN pecl install xdebug-2.6.0 RUN docker-php-ext-enable xdebug RUN echo "xdebug.remote_enable=1" >> /usr/local/etc/php/php.ini
WordPress Source Code
As mentioned above, we will need the source code for WordPress in our project to step into code when debugging. In the project directory, create a path
src/wordpress. Download WordPress version 5.4.1 and place the extracted files there, so that the main
index.php and directories
wp-includes are available directly under
Next, in the
src/ directory add a subfolder
themes and place there the extracted BeOnePage theme so that the theme’s files are available under
Finally, exclude all directories that we are not going to need in the project repository by adding the
.gitignore file into the project root:
.idea/ .env src/wordpress/
The final project structure will look like this:
├── src │ ├── themes │ │ ├── beonepage │ ├── wordpress │ │ ├── wp-admin │ │ ├── wp-content │ │ ├── wp-includes │ │ ├── index.php │ │ ├── ... ├── .env ├── .gitignore ├── docker-compose-local.yml ├── Dockerfile_local
Launching the Docker Project
We are now ready to launch the prepared WordPress project using PhpStorm Docker tools.
First, we need to create a Run Configuration. To do that, in the project view right-click the file
docker-compose-local.yml and select “Create docker-compose-local…”:
This will open the “Create Run Configuration” dialog that looks like this:
For our project, there is nothing required to change in this dialog. However, you might want to check “–build, force build images” if your project has some changes that can affect the composition of the services’ images.
If the “Server” setting does not show “Docker”, it means that PhpStorm can’t connect to the Docker daemon. The error message can read, for example:
“Cannot connect: Cannot connect to the Docker daemon at tcp://localhost:2375. Is the docker daemon running?”
To fix this, open Docker Desktop and check if there is any problem with the docker daemon. Also, make sure that the daemon is exposed at port 2375 as described in the “Prerequisites” section earlier in this post.
Another problem can happen when PhpStorm fails to start the service containers with an error message like this:
Failed ... com.intellij.execution.process.ProcessNotCreatedException: Cannot run program docker-compose CreateProcess error=193, %1 is not a valid Win32 application
This problem happens on Windows machines and the reason is that the tool settings for the Docker executables lack “.exe” extensions in file paths. Simply adding the missing extensions should solve it:
Starting the Service Containers
Once the Run Configuration is created, we can build the images and start the containers by clicking the run button in the IDE toolbar. The deploy log in the IDE will show this:
Deploying 'Compose: docker-compose-local.yml'... "C:\Program Files\Docker\Docker\resources\bin\docker-compose.exe" -f C:\__projects\docker\wordpress_xdebug\docker-compose-local.yml up -d Creating network "wordpress_xdebug_app-network" with driver "bridge" Creating volume "wordpress_xdebug_dbdata" with default driver Creating db_blog_xdb ... Creating wp_blog_xdb ... 'Compose: docker-compose-local.yml' has been deployed successfully.
Alternatively, this could be done from PowerShell running in the privileged mode:
cd <project directory> docker-compose -f ./docker-compose-local.yml up -d --build
Wait a minute before testing the project in the browser. The db service takes some time to launch the MySQL service and start accepting connections. You can follow this process using the
docker-compose -f ./docker-compose-local.yml logs -f
Wait until the log shows this line:
[System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: '8.0.20' socket: '/var/run/mysqld/mysqld.sock' port: 3306 MySQL Community Server - GPL.
Now, go ahead and open the
http://localhost. You will be greeted with the familiar WordPress installation wizard. Finish it and log into the admin area. There, activate the BeOnePage theme. Now your blog will look like this:
We are now ready to start the first debugging session. Open the core WordPress index file located at
src/wordpress/index.php and place a breakpoint in the last line
require __DIR__ . '/wp-blog-header.php';
Now, in the IDE toolbar, click the “Start listening for PHP Debug connections” button:
In your browser, activate the Xdebug Helper:
Reload the index page and make sure the execution stops at the breakpoint. If yes, try stepping in and go a few levels deeper. Test breakpoints in other locations in the core files directory.
It can happen that the breakpoint is missed, or there are Xdebug connection errors like this appear:
<em>Cannot accept external Xdebug connection: Cannot evaluate expression 'isset($_SERVER['PHP_IDE_CONFIG'])'</em>
In this case, open the project settings and under “Languages and Frameworks” > “PHP” > “Servers” delete all server configurations. They will be automatically fixed and recreated the next time you start debugging:
Debugging the Custom Theme
Now that the core files debugging works, we need to try debugging the custom theme files located at
/src/themes/beonepage. To enable this debugging simply add a mapping to the theme directory:
Now, the breakpoints in the theme files should work as well.
In this tutorial, we showed how to enable debugging of PHP files in a dockerized WordPress project with PhpStorm.
Once the project is ready for deployment, you will have to work out a way to bring the theme modifications to the production environment. The volume mapping we used in the docker-compose service configuration will not be necessary for a live container so you may need to create a Docker file for the production version. You can find more information on deployment Deploy Containerized WordPress Websites with GitLab and Nginx-Proxy