Easily debug your Laravel Sail applications with xDebug10 min read

Photo by Dominik Lückmann on Unsplash

Laravel, with version 8, introduces a very practical wrapper for a docker environment: Laravel Sail. I personally find it way more easy to use than Laravel Homestead, that had the same purpose of proposing a development environment in a virtual machine. Especially when it comes to deployment.

Coming from low level software development, I’ve been used to this incredibly powerful tool that is a debugger. Placing breakpoints into my code, and being able to watch every variable while going through the code step by step is just great. And it helps understand what is really going on, which is, I think, non-negligible for beginners.

Unfortunately, The Laravel Sail environment does not ship with xDebug installed. Which is an issue being discussed quite roughly on the github repository! I won’t go into the argument. I understand both sides, and I wouldn’t know how to settle it. But since the outcome, for now, is to not embed the xDebug option onto Laravel Sail, I will show here how you can very easily add xDebug to your configuration.

Publish Laravel Sail docker files

I assume that you have Docker Desktop installed and running on your computer. I also assume that you have a Laravel 8 project created. If not, just follow the guide.

You need to publish Sail’s Dockerfiles by executing the sail:publish command:

./vendor/bin/sail artisan sail:publish

A new directory named docker should appear at the root of your project. Inside you will find 2 directories named 7.4 and 8.0. And in both of them you will find a Dockerfile. Open them.

Edit the Dockerfile

We are going to add xDebug to the container as an option. This way it will be present in your development environment if you want it, but not on your deployed version.

Here is what your Dockerfile should look like once edited:

FROM ubuntu:20.04

LABEL maintainer="Taylor Otwell"

ARG WWWGROUP
ARG XDEBUG

WORKDIR /var/www/html

ENV DEBIAN_FRONTEND noninteractive
ENV TZ=UTC

RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

RUN apt-get update \
    && apt-get install -y gnupg gosu curl ca-certificates zip unzip git supervisor sqlite3 libcap2-bin libpng-dev python2 \
    && mkdir -p ~/.gnupg \
    && chmod 600 ~/.gnupg \
    && echo "disable-ipv6" >> ~/.gnupg/dirmngr.conf \
    && apt-key adv --homedir ~/.gnupg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys E5267A6C \
    && apt-key adv --homedir ~/.gnupg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys C300EE8C \
    && echo "deb http://ppa.launchpad.net/ondrej/php/ubuntu focal main" > /etc/apt/sources.list.d/ppa_ondrej_php.list \
    && apt-get update \
    && apt-get install -y php8.0-cli php8.0-dev \
       php8.0-pgsql php8.0-sqlite3 php8.0-gd \
       php8.0-curl php8.0-memcached \
       php8.0-imap php8.0-mysql php8.0-mbstring \
       php8.0-xml php8.0-zip php8.0-bcmath php8.0-soap \
       php8.0-intl php8.0-readline \
       php8.0-msgpack php8.0-igbinary php8.0-ldap \
       php8.0-redis

RUN if [ ${XDEBUG}] ; then \
    apt-get install -y php-xdebug; \
fi;

RUN php -r "readfile('http://getcomposer.org/installer');" | php -- --install-dir=/usr/bin/ --filename=composer \
    && curl -sL https://deb.nodesource.com/setup_15.x | bash - \
    && apt-get install -y nodejs \
    && curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \
    && echo "deb https://dl.yarnpkg.com/debian/ stable main" > /etc/apt/sources.list.d/yarn.list \
    && apt-get update \
    && apt-get install -y yarn \
    && apt-get install -y mysql-client \
    && apt-get install -y postgresql-client \
    && apt-get -y autoremove \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

RUN pecl channel-update https://pecl.php.net/channel.xml \
    && pecl install swoole

RUN setcap "cap_net_bind_service=+ep" /usr/bin/php8.0

RUN groupadd --force -g $WWWGROUP sail
RUN useradd -ms /bin/bash --no-user-group -g $WWWGROUP -u 1337 sail

COPY start-container /usr/local/bin/start-container
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
COPY php.ini /etc/php/8.0/cli/conf.d/99-sail.ini
RUN chmod +x /usr/local/bin/start-container

EXPOSE 8000

ENTRYPOINT ["start-container"]

Line 6
We add an argument named XDEBUG that can be provided when executing this Dockerfile.

Lines 33 to 35
We insert a condition for installing xDebug, depending on the value of the XDEBUG argument. It is important that the insert is made in this spot. Be careful to do exactly as I did when cutting the RUN instruction in half.

Initialize PHP with xdebug

In those same 2 directories named 7.4 and 8.0, you will find a php.ini file. Open them.

We need ton configure xdebug. Just add the following in the php.ini file:

[XDebug]
zend_extension = xdebug.so
xdebug.mode = debug
xdebug.start_with_request = yes
xdebug.discover_client_host = true
xdebug.idekey = VSC
xdebug.client_host = host.docker.internal
xdebug.client_port = 9003

Notice that the port 9003 is specified for xDebug client. You can choose another but this one is fine.

Propagate the argument through the docker-compose

To be passed over to the Dockerfile, the XDEBUG argument needs to be set in the docker-compose.yml file. This file is located at the root of you project.

To make it dynamic, and allow xDebug to be activated or not depending on whether it’s executing on the production server or on the development environment, tothe XDEBUG argument will be assigned a variable which I’ll name SAIL_XDEBUG, but you are free to name it as you wish. So, locate the laravel.test section of the docker-compose file and add the argument as follow:

  laravel.test:
    build:
      context: ./docker/8.0
      dockerfile: Dockerfile
      args:
        WWWGROUP: "${WWWGROUP}"
        XDEBUG: ${SAIL_DEBUG}
    image: sail-8.0/app
    ports:
      - "${APP_PORT:-80}:80"
    environment:
      WWWUSER: "${WWWUSER}"
      LARAVEL_SAIL: 1
    volumes:
      - ".:/var/www/html"
    networks:
      - sail
    depends_on:
      - mysql
      - selenium

Activate xDebug from your env file

Now to activate xDebug on your development environment, you just need to add SAIL_DEBUG=true to your .env file. Each time you change it, you will need to rebuild the docker image of your app. So let’s do it. Back in your console, run:

./vendor/bin/sail build --no-cache

It will take a few minutes…

To make sure XDebug is active, run the command:

./vendor/bin/sail php -v

You should see a mention to PHP XDebug with it’s version.

Start debugging with VSCode

I’ll show you how to configure VSCode to start debugging, but the configuration should be similar for other editors.

Installation of the extension

To install it in VSCode, we need to :

  • Click on the “Extensions” icon (or Ctrl + Shift + X),
  • then use the search field to find the extension (type xdebug),
  • and finally install it (click on the little green “Install” button).
The PHP extension by Felix Becker
The PHP extension by Felix Becker

To work, you need PHP installed on your computer. We can check it’s installed by typing the php -version command in a console. It should output the currently installed version of PHP.

php -version
php -version

If not, you can download the last version (nonthread safe) on this site.

Configuration of a listener

The PHP Debug extension is able to manage many configurations if we need to listen to many instances of Xdebug. We are going to create only one here, for our container.

For that we need to :

  • Click on the “debug” icon on the sidebar (or Ctrl + Shift + D),
  • then click on the gear icon titled “Open launch.json” next to the drop-down menu at the top of the left side panel,
  • then click on PHP in the list of proposed environments. A hidden folder named .vscode containing a file named launch.json is created in our project root folder.

We can easily deduce that the configuration of our extension is liked to our project, which is convenient because all of our projects don’t necessarily use Docker and will likely have different configurations.

Inside our launch.json file, we notice 2 configurations that we can delete (or not, doesn’t matter). We are gonna create a new one :

{
     "name": "Listen for XDebug on Docker App",
     "type": "php",
     "request": "launch",
     "port": 9003,
     "pathMappings": {
         "/var/www/html": "${workspaceFolder}"
     },
     "hostname": "localhost",
     "xdebugSettings": {
         "max_data": 65535,
         "show_hidden": 1,
         "max_children": 100,
         "max_depth": 5
     }
 },

Let’s debug

You’re up. Give it a try!

If you want more details on this configuration, have a look at my article on Debug with VSCode, Xdebug, and Docker on Windows.


I hope you enjoyed this article.

Thanks for reading me. Have a nice day!

Related Posts

7 Responses
  1. Kathie Nguyen

    Hi, Thanks for the post. I soptted an error: where you said SAILDEBUG=true, it should be SAIL_DEBUG=true (to match the var name in the docker-compose file. It just couldn’t build with the incorrect name!

  2. Dave

    Hi, I am getting the following error while running: php -v

    PHP Warning: Failed loading Zend extension ‘xdebug.so’ (tried: /usr/lib/php/20200930/xdebug.so (/usr/lib/php/20200930/xdebug.so: cannot open shared object file: No such file or directory), /usr/lib/php/20200930/xdebug.so.so (/usr/lib/php/20200930/xdebug.so.so: cannot open shared object file: No such file or directory)) in Unknown on line 0
    PHP 8.0.8 (cli) (built: Jul 1 2021 15:26:46) ( NTS )
    Copyright (c) The PHP Group
    Zend Engine v4.0.8, Copyright (c) Zend Technologies
    with Zend OPcache v8.0.8, Copyright (c), by Zend Technologies

  3. Jo

    Hi all,

    I’ve been looking for this.
    Unfortunately, I can’t get it to work…

    With either of these options:
    – pecl install xdebug;
    – apt-get install -y php-xdebug;
    – apt-get install -y php8.0-xdebug;

    I always get this message from “sail php -v” :

    “PHP Warning: Failed loading Zend extension ‘xdebug.so’ (tried: /usr/lib/php/20200930/xdebug.so (/usr/lib/php/20200930/xdebug.so: cannot open shared object file: No such file or directory), /usr/lib/php/20200930/xdebug.so.so (/usr/lib/php/20200930/xdebug.so.so: cannot open shared object file: No such file or directory)) in Unknown on line 0”

Leave a Reply