Skip to content

Instantly share code, notes, and snippets.

@chadrien
Last active October 31, 2024 12:27
Show Gist options
  • Save chadrien/c90927ec2d160ffea9c4 to your computer and use it in GitHub Desktop.
Save chadrien/c90927ec2d160ffea9c4 to your computer and use it in GitHub Desktop.
Debug PHP in Docker with PHPStorm and Xdebug

Debug your PHP in Docker with Intellij/PHPStorm and Xdebug

  1. For your local dev, create a Dockerfile that is based on your production image and simply install xdebug into it. Exemple:
FROM php:5

RUN yes | pecl install xdebug \
    && echo "zend_extension=$(find /usr/local/lib/php/extensions/ -name xdebug.so)" > /usr/local/etc/php/conf.d/xdebug.ini \
    && echo "xdebug.remote_enable=on" >> /usr/local/etc/php/conf.d/xdebug.ini \
    && echo "xdebug.remote_autostart=off" >> /usr/local/etc/php/conf.d/xdebug.ini
  1. Get you local IP address (ifconfig or such)
  2. Start your container with the following environment variable: XDEBUG_CONFIG="remote_host={{YOUR_IP_ADDRESS}}"
  • Simple docker run: docker run -e XDEBUG_CONFIG="remote_host={{YOUR_IP_ADDRESS}}" your-image

  • With docker-compose:

    # docker-compose.yml
    foo:
      build: path/to/Dockerfile
      environment:
        XDEBUG_CONFIG: remote_host={{YOUR_IP_ADDRESS}}
  1. In Intellij/PHPStorm go to: Languages & Frameworks > PHP > Debug > DBGp Proxy and set the following settings:
  • Host: your IP address
  • Port: 9000

Then you're all set and can start listening for PHP Debug connections from your IDE. On the first run it will ask you to map your local directoryies to the docker directories, but after that nothing will be required anymore!

Happy debugging!

@hernandev
Copy link

hernandev commented May 8, 2018

Hello everyone, here is how I've included support for XDebug on Ambientum:

considering the image start file is start.sh:

#!/usr/bin/env bash

if [[ $XDEBUG_ENABLED == true ]]; then
    # enable xdebug extension
    sudo sed -i "/;zend_extension=xdebug/c\zend_extension=xdebug" /etc/php7/conf.d/00_xdebug.ini

    # enable xdebug remote config
    echo "[xdebug]" | sudo tee -a /etc/php7/conf.d/00_xdebug.ini > /dev/null
    echo "xdebug.remote_enable=1" | sudo tee -a /etc/php7/conf.d/00_xdebug.ini > /dev/null
    echo "xdebug.remote_host=`/sbin/ip route|awk '/default/ { print $3 }'`" | sudo tee -a /etc/php7/conf.d/00_xdebug.ini > /dev/null
    echo "xdebug.remote_port=9000" | sudo tee -a /etc/php7/conf.d/00_xdebug.ini > /dev/null
    echo "xdebug.scream=0" | sudo tee -a /etc/php7/conf.d/00_xdebug.ini > /dev/null
    echo "xdebug.cli_color=1" | sudo tee -a /etc/php7/conf.d/00_xdebug.ini > /dev/null
    echo "xdebug.show_local_vars=1" | sudo tee -a /etc/php7/conf.d/00_xdebug.ini > /dev/null
    echo 'xdebug.idekey = "ambientum"' | sudo tee -a /etc/php7/conf.d/00_xdebug.ini > /dev/null

fi

# run the original command
exec "$@"

This allows automatic host IP detection, using the /sbin/ip route|awk '/default/ { print $3 }'

Also notice the ide key is defaulted to ambientum on the example, and the 00_xdebug.ini may have another path.

If you want to check it out implemented on a image, here is the sources for Ambientum:

https://github.com/codecasts/ambientum/tree/master/php/7.2

@hernandev
Copy link

hernandev commented May 8, 2018

@MikeDevs one way to have the host.docker.internal on ANY Docker version is to include it on the /etc/hosts manually upon start (entry point script):

echo -e "`/sbin/ip route|awk '/default/ { print $3 }'`\tdocker.host.internal" | sudo tee -a /etc/hosts > /dev/null

Doing that line, you can now easily check docker.host.internal by doing

ping docker.host.internal

:)

@stefanosaittamrf
Copy link

When I debug wordpress with this configuration everything seems to work but one thing.
I got 2 requests in every debug request. First request is good one which stops php scripts in normal debug session ( web server is paused and waiting for script to die or continue ). Second request seems to do nothing with web server, but xdebug client is working on breakpoint.

Same happen to me @kil0p did you manage to solve? Also, i have an issue debugging a plugin, since in my dev environment i just expose the plugin directory and hide inside the docker container the wordpress code, the issue happens when my debugger try to step into the actual implementation but since the code is not there it fails. I Don't know if i explain it clearly, if not let me know.

@vjaro
Copy link

vjaro commented Jun 27, 2018

@jtreminio the linux part worked for me. Thank you!

@swashata
Copy link

Hi,

I've found that simply defining xdebug.remote_host=host.docker.internal works just fine.

@paslandau
Copy link

The problem is usually that there is some bug in the networking setup for Docker for Mac / Docker for win that causes the container not to "see" the host machine . The host.docker.internal DNS entry solves this issue for both systems, although we noticed that it does not exist for native Docker under unix.

To make this work for PhpStorm, the xdebug.ini file should contain at least two entries:

xdebug.remote_host=host.docker.internal
xdebug.remote_connect_back=0

(that is, if you want a debugging session triggered from the browser).

For CLI script debugging I suggest to override xdebug.remote_host in the CLI Interpreter settings:

Xdebug CLI Interpreter settings

Source: Fix Xdebug on PhpStorm when run from a Docker container

@darius-v
Copy link

darius-v commented Sep 2, 2018

I tried by the video https://serversforhackers.com/c/getting-xdebug-working, but I am getting error:

Step 3/12 : RUN locale-gen en_US.UTF-8 ---> Running in 0cef4abb96cb /bin/sh: 1: locale-gen: not found ERROR: Service 'app' failed to build: The command '/bin/sh -c locale-gen en_US.UTF-8' returned a non-zero code: 127

when building. How to fix that? I am using xubuntu 16

@darius-v
Copy link

darius-v commented Sep 3, 2018

Found what fixes the problem: nerves-project/nerves#112

Adding

RUN apt-get update && apt-get -y install locales
before
RUN locale-gen en_US.UTF-8

But now getting anotehr error:

ERROR: Service 'app' failed to build: COPY failed: stat /var/lib/docker/tmp/docker-builder196897509/start-container: no such file or directory

Update:

Found that start-container is a file. And thought it has to have ending .sh but its the opposite - it had not to have .sh ending. So after fixing this, it built.

@darius-v
Copy link

darius-v commented Sep 3, 2018

After that I still got error

docker-compose up -d
Recreating 4_try_app_1 ... error

ERROR: for 4_try_app_1  Cannot start service app: b'driver failed programming external connectivity on endpoint 4_try_app_1 (42786abb4be0850f5f801240d69aaa1d76b7de3e10aaad89be0b23a27c2a8181): Error starting userland proxy: listen tcp 0.0.0.0:80: bind: address already in use'

ERROR: for app  Cannot start service app: b'driver failed programming external connectivity on endpoint 4_try_app_1 (42786abb4be0850f5f801240d69aaa1d76b7de3e10aaad89be0b23a27c2a8181): Error starting userland proxy: listen tcp 0.0.0.0:80: bind: address already in use'
ERROR: Encountered errors while bringing up the project.

But tried to changing ports in docker-compose.yml to - "8080:80" and now error is gone. To load page have to go to http://localhost:8080/

And after fixing those errors, I can confirm - that works :) I have not tested with curl, but I have tested running in chrome.

@darius-v
Copy link

darius-v commented Sep 3, 2018

Tested the performance when listening and when not listening. Both times it lasted 2-3 seconds on my machine. So that is not optimal, probably it works always with xdebug mode even when turning off listening in php storm.

echo date('H:i:s') . '<br>';
for($i=1; $i<10000000; $i++) {
    $three++;
}
echo date('H:i:s');

Would be good to find a quick way to turn xdebug off.

I tried commenting this line
#COPY xdebug.ini /etc/php/7.0/mods-available/xdebug.ini
and rebuild

docker-compose build.

And executed again. But still same those 2-3 seconds. So not sure what is causing this. Maybe thats is not xdebug, need to try.

Interesging - tried same script on php 7.1 where I have setup without docker. When turning on listening in phpstorm, then it loads in 4-5 seconds. When turning off - 2-3 seconds. So how in this docker setup it has constantly 2-3 seconds?

@PeteFromSales
Copy link

PeteFromSales commented Sep 7, 2018

@jtreminio 's config worked for me on OSX (Sierra 10.12.6) & Docker CE (18.06.1-ce-mac73 (26764)). However, I'm using Intellij IDEA 2018.2, so despite the xdebug.remote_handler = "dbgp" line, in Intellij I just use the normal Xdebug settings and port (you can probably use port 9000 as well, just check if it's already in use by another service first):

screen shot 2018-09-07 at 9 46 51 am

@dgershman
Copy link

dgershman commented Oct 28, 2018

This worked for me:

FROM php:5.6.38-apache

RUN apt-get update &&\
    apt-get install --no-install-recommends --assume-yes --quiet ca-certificates curl git telnet iputils-ping net-tools &&\
    rm -rf /var/lib/apt/lists/*

RUN pecl install xdebug-2.5.5 && docker-php-ext-enable xdebug \
    && echo "zend_extension=$(find /usr/local/lib/php/extensions/ -name xdebug.so)" >> /usr/local/etc/php/php.ini  \
    && echo "xdebug.remote_port=9000" >> /usr/local/etc/php/php.ini \
    && echo "xdebug.remote_enable=1" >> /usr/local/etc/php/php.ini \
    && echo "xdebug.remote_connect_back=0" >> /usr/local/etc/php/php.ini \
    && echo "xdebug.remote_host=docker.for.mac.localhost" >> /usr/local/etc/php/php.ini \
    && echo "xdebug.idekey=IDEA_DEBUG" >> /usr/local/etc/php/php.ini \
    && echo "xdebug.remote_autostart=1" >> /usr/local/etc/php/php.ini \
    && echo "xdebug.remote_log=/tmp/xdebug.log" >> /usr/local/etc/php/php.ini

My docker-compose.yml

version: '2'
services:
  apache_with_php:
    build: .
    volumes:
    - ./src:/var/www/html/
    ports:
    - "8082:80"

@brotherbigbao
Copy link

For me the followings works on Docker for Mac:

xdebug.remote_autostart=0
xdebug.remote_enable=1
xdebug.default_enable=0
xdebug.remote_host=docker.for.mac.host.internal
xdebug.remote_port=9000
xdebug.remote_connect_back=0
xdebug.profiler_enable=0
xdebug.remote_log="/tmp/xdebug.log"

The docker.for.mac.host.internal host prevent scratching the head regarding IP alias or no network at all on host side. The source comes from the docker documentation https://docs.docker.com/docker-for-mac/networking/#use-cases-and-workarounds

No needs for extra configuration or environment variable in docker compose.

Great!

@Deg5112
Copy link

Deg5112 commented Dec 12, 2018

always end up coming back to this post

the main issue i always have is executing a command/php file directly inside of a docker container.

Having the following env variable living directly in the docker container instance, pointing back to the literal name of the server block, solves the problem. Typically when xdebug first creates a connection, it'll give the server name a default name of _ . you can go change that to whatever you want

PHP_IDE_CONFIG=serverName= ie: name of the server name located in preferences -> languages -> php -> servers

@antishov
Copy link

Great post.
Please note that PHP 7.3+ is not compatible with xdebug 2.6 or lower. You should install at least 2.7.0RC1 version.

@mickambar19
Copy link

xdebug.remote_host=docker.for.mac.host.internal

That helped me. It's working now.

@weinung-chiu
Copy link

weinung-chiu commented Mar 21, 2019

@jtreminio 's mac os config works!
you save my life, thank you!

@tobinski
Copy link

tobinski commented Apr 2, 2019

Be aware of firewall configuration. Maybe the connection to phpstorm on port 9000 is blocked.

@rahilwazir
Copy link

@jtreminio Worked for Linux. Thanks.

@lainosantos
Copy link

Hi,
On linux with firewalld enabled, the container hasn't route for host, so it not attach to host port 9000 (xdebug). The route can be add by:
firewall-cmd --zone=public --add-rich-rule='rule family="ipv4" source address="172.17.0.0/16" accept'

Where 172.17.0.0 is docker container's subnet (check it with ifconfig).

@rwese
Copy link

rwese commented Jun 3, 2019

This will need to be updated for php 7.4, see: https://olvlvl.com/2019-06-install-php-ext-source , pecl won't be available in the php base image.

@brycefranzen
Copy link

@digitalit Thank you!!! Your alias method worked perfectly!

@patrickschur
Copy link

Here is my Dockerfile using PHP 7.4 and the newest version of Xdebug. Because PEAR is no longer enabled by default and may be removed in the future.

FROM php:7.4-rc-apache

ARG XDEBUG_VERSION=2.8.0beta1

RUN mkdir -p /usr/src/php/ext/xdebug && \
    curl -fsSL https://xdebug.org/files/xdebug-${XDEBUG_VERSION}.tgz | tar xz -C /usr/src/php/ext/xdebug --strip 1 && \
    docker-php-ext-install xdebug && \
    echo "xdebug.remote_enable=1" >> /usr/local/etc/php/php.ini

@MiguelAlcaino
Copy link

the linux solution given by @jtreminio works for me like a charm

@patricknelson
Copy link

patricknelson commented Sep 6, 2019

The key here is to now start using host.docker.internal in your remote_host configuration moving forward. Also, I think remote_connect_back is not necessary and should be removed. I've consolidated a simplified but generic explanation where I try to focus strictly on configuring Xdebug to work in Docker, if anyone is interested:

Using Xdebug in Docker (gist)

I did this because even though the core solution for Docker-specific setups is pretty simple (i.e. remote_host=host.docker.internal), any extra code, configuration details or unrelated bugs can start to make things very confusing for beginners who are diving into Docker for the first time. If anything, it'll at least help me for future reference 😄

@andrew-svirin
Copy link

Is it possible to setup connection by next chain: Windows -> Linux (host Docker) -> Docker Linux PHP with PHPUnit ?

@mitogh
Copy link

mitogh commented Dec 25, 2019

MacOS:

[xdebug]
xdebug.remote_host = "docker.for.mac.host.internal"
xdebug.default_enable = 1
xdebug.remote_autostart = 1
xdebug.remote_connect_back = 0
xdebug.remote_enable = 1
xdebug.remote_handler = "dbgp"
xdebug.remote_port = 9000

Linux:

[xdebug]
xdebug.remote_host = "172.18.0.1"
xdebug.default_enable = 1
xdebug.remote_autostart = 1
xdebug.remote_connect_back = 0
xdebug.remote_enable = 1
xdebug.remote_handler = "dbgp"
xdebug.remote_port = 9000

Windows:

[xdebug]
xdebug.remote_host = "docker.for.win.host.internal"
xdebug.default_enable = 1
xdebug.remote_autostart = 1
xdebug.remote_connect_back = 0
xdebug.remote_enable = 1
xdebug.remote_handler = "dbgp"
xdebug.remote_port = 9000

This one is working for me, just replacing the "remote_host" with the value from:

docker network inspect bridge | grep Gateway

@NorthenIrbis
Copy link

sudo iptables -A INPUT -p tcp --dport 9000 -j ACCEPT

@bedger
Copy link

bedger commented Apr 22, 2020

If you have problems with running it on Linux (Ubuntu in my case) & you have a firewall enabled then the solution for you may be opening firewall ports for connection to port 9000 on docker service
sudo ufw enable && sudo ufw allow in from 172.16.0.0/12 to any port 9000 comment xdebug

You can check this discussion for more information

@Raistlfiren
Copy link

Here is a quick reference for XDebug 3 and Docker Gist.

The main change to the xdebug.ini file is:

[XDebug]
zend_extension=xdebug.so

xdebug.mode = debug
xdebug.start_with_request=yes
xdebug.client_host=host.docker.internal

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment