Debugging PHP app using Xdebug and Remote Docker PHP Container

No so long ago I’ve started using Docker as my primary development environment. Before that I had everything (WEB-server, PHP, MySql, etc) installed on my Mac and being run natively. Docker brings more flexibility and it is just fun. So now my setup includes Mac OS with PhpStorm installed and remote Ubuntu server running Docker containers needed for my WEB application.

Docker Development Environment

Official PHP5.6-FPM is missing some extensions, so we extend it and build our own. Dockerfile for PHP service:

FROM php:5.6-fpm

RUN apt-get -qq update && apt-get -qq install libxml++2.6-dev > /dev/null
RUN apt-get update && apt-get install -y \
        libfreetype6-dev \
        libcurl4-gnutls-dev \
        build-essential \
        libtool \
        uuid-dev \
        libsodium-dev \
        libjpeg62-turbo-dev \
        libpng12-dev \
    && docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ \
    && docker-php-ext-install -j$(nproc) gd mbstring mysql mysqli pdo pdo_mysql soap

RUN apt-get install -y libmcrypt-dev
RUN docker-php-ext-install mcrypt

RUN apt-get install -y libicu-dev
RUN pecl install intl
RUN docker-php-ext-install intl
RUN yes | pecl install xdebug \
    && echo "zend_extension=$(find /usr/local/lib/php/extensions/ -name" > /usr/local/etc/php/conf.d/xdebug.ini \
    && echo "xdebug.remote_enable=on" >> /usr/local/etc/php/conf.d/xdebug.ini \
    && echo "xdebug.remote_port=9001" >> /usr/local/etc/php/conf.d/xdebug.ini \
    && echo "xdebug.remote_connect_back=0" >> /usr/local/etc/php/conf.d/xdebug.ini \
    && echo "xdebug.idekey=PHPSTORM" >> /usr/local/etc/php/conf.d/xdebug.ini \
    && echo "xdebug.remote_log='/tmp/xdebug_log/xdebug.log'" >> /usr/local/etc/php/conf.d/xdebug.ini

As you can see there are some xdebug settings. I have set remote port to 9001 and enabled xdebug logging so it will be easier to check if it works (don’t forget to turn it off later).
Now lets take a look at docker-compose.yml file:

version: '2'
    image: nginx:latest
     - "8080:80"
     - ./source:/source
     - ./nginx.conf:/etc/nginx/conf.d/default.conf
     - php
    build: ./php
       XDEBUG_CONFIG: "remote_host="
     - ./source:/source
     - ./logs:/tmp/xdebug_log
    image: mariadb:latest
       - db_data:/var/lib/mysql
      MYSQL_DATABASE: 'test'
      MYSQL_USER: 'root'
      MYSQL_PASSWORD: 'test'

Important part here is to set xdebug remote host in environment variables. To get correct IP address you can run ifconfig command and find what IP address is used by docker0 interface. Alternatively use the following command in container:

/sbin/ip route|awk '/default/ { print $3 }'

Also set 777 permissions to logs folder.

Now we can execute docker-compose run to build and run our services.

Lets check if xdebug can connect to remote host using netcat tool. Leave this command running in console and navigate to some php script with xdebug trigger turned on:

netcat -l 9001

If you see something like this then it is ok:

<?xml version="1.0" encoding="iso-8859-1"?>
<init xmlns="urn:debugger_protocol_v1" xmlns:xdebug="" fileuri="file:///source/info.php" language="PHP" xdebug:language_version="5.6.27" protocol_version="1.0" appid="6" idekey="XDEBUG_ECLIPSE"><engine version="2.5.1"><![CDATA[Xdebug]]></engine><author><![CDATA[Derick Rethans]]></author><url><![CDATA[]]></url><copyright><![CDATA[Copyright (c) 2002-2017 by Derick Rethans]]></copyright></init>

If it is not – check xdebug log file.

Next step is to create SSH-tunnel and configure PhpStorm.

On working computer run the following command to create SSH-tunnel:

ssh -R 9001:localhost:9001

In PhpStorm set debug port to 9001:

Preferences PhpStorm

Now you should be able to debug your application in PhpStorm.