Laravel environment: docker, devcontainer and VS Code debug

Published on February 14th, 2024.

Starting new Laravel project

In this post, we will see how to set up a Laravel environment using Docker, Devcontainer, and debug it using Xdebug. I like to use Docker for my development environment because it is easy to set up and it is consistent across different machines. With devcontainer we can use the same environment in Visual Studio Code and Xdebug is a must-have for debugging.

Let's start by creating a new Laravel project using sail (Docker). You'll need to have Docker and Docker Compose installed on your machine. If you don't have it, you can install it by following the instructions on the official website.

You can change 'example-app' to another name.
Open the project in Visual Studio Code and you will be prompted to reopen the project in a devcontainer. Click on the 'Reopen in Container' button and wait for the container to be built. You can check the progress in the bottom right corner of Visual Studio Code.

VsCode and DevContainer

With the VSCode oppened, you will install the devcontainer extension. You will notice this .devcontainer folder in the root of the project. devcontainer folder

You can install the extension by clicking on the extensions icon in the sidebar and search vscodeextensioninstall

I use php inteliphense and xdebug extensions. You can add more extensions.

// https://aka.ms/devcontainer.json
{
	"name": "Existing Docker Compose (Extend)",
	"dockerComposeFile": [
		"../docker-compose.yml"
	],
	"service": "laravel.test",
	"workspaceFolder": "/var/www/html",
	"customizations": {
		"vscode": {
			"extensions": [
                "bmewburn.vscode-intelephense-client",
                "xdebug.php-debug"
			],
			"settings": {}
		}
	},
	"remoteUser": "sail",
	"postCreateCommand": "chown -R 1000:1000 /var/www/html 2>/dev/null || true"
	// "forwardPorts": [],
	// "runServices": [],
	// "shutdownAction": "none",
}

Docker configurations

1) You need to change docker-compose.yml to add new port for xdebug.

2) Change the context and add a copy of vendor/laravel/sail/runtimes/8.3
Add the following lines to the docker-compose.yml file:

version: '3'
services:
    laravel.test:
    build:
        context: ./.devcontainer/vendor-example/laravel/sail/runtimes/8.3
...
        ports:
...
            - '9003:9003'
...
$ mkdir -p .devcontainer/vendor-example/laravel/sail/runtimes/
$ cp -r vendor/laravel/sail/runtimes/8.3 .devcontainer/vendor-example/laravel/sail/runtimes/8.3

3) I like to custom the Dockerfile and add my customizations like install some software: sudo curl, git, git cli and nano, and change the user 'sail' as sudo.
Put the code in right place.
...
RUN apt-get update \
...
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

# My customizations
RUN apt-get update \
    && apt-get install -y sudo nano git curl \
    && curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo gpg --dearmor -o /usr/share/keyrings/githubcli-archive-keyring.gpg \
    && chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg \
    && echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null \
    && apt update \
    && apt install gh -y

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

# allow devContainer use sudo without password
RUN echo sail ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/sail \
    && chmod 0440 /etc/sudoers.d/sail
Your Dockerfile will look like this: Dockerfile
4) Add this code in php.ini
[XDebug]
xdebug.mode=develop,debug
xdebug.start_with_request=yes
xdebug.discover_client_host=0
xdebug.client_host=host.docker.internal

5) I like to custom my bash prompt to show my git branch and the current directory.
#!/usr/bin/env bash

if [ ! -z "$WWWUSER" ]; then
    usermod -u $WWWUSER sail
fi

if [ ! -d /.composer ]; then
    mkdir /.composer
fi

chmod -R ugo+rw /.composer

if [ $# -gt 0 ]; then
    exec gosu $WWWUSER "$@"
else
    # Add custom Git branch name and status to ~/.bashrc
    echo 'parse_git_branch() {
        branch=$(git symbolic-ref HEAD 2> /dev/null || git describe --tags --exact-match 2> /dev/null || git rev-parse --short HEAD 2> /dev/null)
        if [[ -n $branch ]]; then
            branch=$(basename "${branch}")
            status=$(git status --porcelain 2> /dev/null)
            if [[ -n $status ]]; then
                echo "($branch*)"
            else
                echo "($branch)"
            fi
        fi
    }

    export PS1='\''\[\e[32m\]\u@$CONTAINER_NAME\[\e[m\]\[\e[31m\]➜\[\e[34m\]\w\[\e[33m\]$(parse_git_branch)\[\e[00m\] $(if [[ $? == 0 ]]; then echo "\[\e[32m\]\$ "; else echo "\[\e[31m\]\$ "; fi)\[\e[m\]'\'' ' >> /home/sail/.bashrc

    # Add a pest command in the ~/.bashrc
    echo 'export PATH="$PATH:/var/www/html/vendor/bin"' >> /home/sail/.bashrc

    # Alias for 'php artisan'
    echo 'alias pa="php artisan"' >> /home/sail/.bashrc

    exec /usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf
fi

Debug configurations

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Listen for XDebug",
            "type": "php",
            "request": "launch",
            "port": 9003,
            "pathMappings": {
                "/var/www/html": "${workspaceFolder}"
            }
        }
    ]
}

Check environment variables
SAIL_XDEBUG_MODE=develop,debug,coverage
WWWGROUP=1000
WWWUSER=1000

Let's put to work!!

After installing the extension, you can open the command palette (Ctrl+Shift+P) and type 'Remote-Containers: Reopen in Container'. This will build the container and open the project inside it. Or it will appear a button in the bottom right corner of the window.

Now you can start the container and debug your Laravel application. You can set a breakpoint in your code and start the debug configuration in Visual Studio Code. You can check the progress in the bottom right corner of Visual Studio Code.

To open you application use the browser with the URL localhost.

Ensure there is no other service running on port 80.

devcontainer folder

That's it! You now have a Laravel environment using Docker, Devcontainer, and Xdebug. You can use this environment to develop your Laravel applications and debug them using Visual Studio Code. I hope this post was helpful to you. If you have any questions, feel free to ask in the comments section below. Thank you for reading!