The Ultimate PhpStorm Debugging Guide: Mastering Docker + PHP 8 + Xdebug 3
Content
## Introduction
Using Docker for environment isolation has become a standard practice in modern PHP development. However, many developers face a common frustration: breakpoints not working when trying to debug a PHP application running inside a Docker container with PhpStorm. The core issues usually lie in the Xdebug configuration and the path mappings between PhpStorm and the container.
This article, based on a real-world technical Q&A, provides a clear, actionable guide to help you master the debugging setup for PhpStorm, Docker, and Xdebug 3.
---
## Step 1: Install and Configure Xdebug in Your Docker Container
First, let's ensure the Xdebug extension is correctly installed and enabled in your PHP Docker container.
### 1. Check if Xdebug is Installed
Exec into your Docker container and run the following command:
```bash
php -v
```
If you don't see "with Xdebug" in the output, you need to install it.
### 2. Install Xdebug
Inside the container, using `pecl` is the most common method:
```bash
# You might need to configure a proxy for network access
pecl install xdebug
```
After installation, run `php -v` again to confirm. You should now see something like `with Xdebug v3.4.7`.
### 3. Configure `php.ini`
This is the most critical part. Locate your container's `php.ini` file (you can find its path with `php --ini`) and add the following configuration at the end.
**Note:** The following is the standard configuration for Xdebug 3.
```ini
[xdebug]
; Make sure this points to the correct xdebug.so file path, which may vary.
zend_extension=xdebug.so
; Or use the absolute path prompted after `pecl install`
; zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20240924/xdebug.so
; Enable debug mode
xdebug.mode=debug
; 'trigger' is recommended for better performance, activated by a browser extension.
; Setting it to 'yes' makes every request try to connect to the debugger, which hurts performance.
xdebug.start_with_request = yes
; This is the key for Docker setups!
; host.docker.internal is a special DNS name that resolves to your host machine's IP.
xdebug.client_host = host.docker.internal
; The default debug port for Xdebug 3
xdebug.client_port = 9003
; (Optional) Configure a log file to troubleshoot connection issues
xdebug.log = "/phplogs/xdebug.log"
```
> **Pro Tip:** Setting `xdebug.client_host` to `host.docker.internal` is crucial. It allows Xdebug inside the container to find PhpStorm running on your host machine.
After modifying the configuration, you **must restart your Docker container** or the PHP-FPM service within it for the changes to take effect.
---
## Step 2: Configure PhpStorm
Now, let's set up our IDE.
### 1. Set the Debug Port
* Go to `Settings/Preferences` -> `PHP` -> `Debug`.
* In the **Xdebug** section, ensure the **Debug port** is set to `9003`. This must exactly match the `xdebug.client_port` in your `php.ini`.
* Check the box for **Can accept external connections**.
### 2. Validate Configuration (Highly Recommended)
On the same settings page, click the **Validate** link. PhpStorm will guide you through an automated check of your setup, which can quickly identify most environmental issues.
---
## Step 3: Configure Server Path Mappings (The Core of Docker Debugging)
**This is the most common reason breakpoints don't work in a Docker environment.** You must tell PhpStorm how the code paths inside the container correspond to the project paths on your local machine.
1. **Open Server Configuration**:
* Navigate to `Settings/Preferences` -> `PHP` -> `Servers`.
2. **Add or Edit a Server**:
* Click the `+` icon to add a new server configuration.
* **Name**: Give it a recognizable name, like `wiki.lib00-docker`.
* **Host**: Enter the hostname you use to access the project in your browser, e.g., `myapp.wiki.lib00.com`.
* **Port**: 80 or 443.
* **Debugger**: Make sure `Xdebug` is selected.
3. **Configure Path Mappings**:
* **Check the `Use path mappings` box**.
* In the table below, add a new mapping rule:
* **File/Directory (Local Path)**: Set this to your project's root directory on your local machine. For example: `/Users/DP/projects/my_php_app`.
* **Absolute path on the server (Server Path)**: Set this to the corresponding project root directory inside the Docker container. For example: `/var/www/html`.
Breakpoints will only be recognized and paused when PhpStorm can correctly map a path from Xdebug (e.g., `file:///var/www/html/index.php`) to the file on your local disk (e.g., `/Users/DP/projects/my_php_app/index.php`).
---
## Step 4: Start Debugging
With all configurations in place, it's time to enjoy the debugging experience.
1. **Install Browser Helper**: Install the **Xdebug helper** extension in Chrome/Firefox and set its IDE key to `PHPSTORM`.
2. **Set a Breakpoint**: In the PhpStorm code editor, click in the gutter next to a line number to set a red dot breakpoint.
3. **Start Listening**: Click the telephone icon (Start Listening for PHP Debug Connections) in the top-right corner of PhpStorm. It should turn green.
4. **Trigger Debugging**:
* In your browser, click the Xdebug helper extension icon and select the **Debug** mode.
* Refresh the page you want to debug.
5. **Enter Debug Mode**: PhpStorm will automatically pop up and pause execution at your breakpoint. The Debug tool window will activate, allowing you to inspect variables, execute code, and step through your application.
By following these steps, compiled by DP@lib00, you should be able to set up an efficient PHP debugging environment with Docker and PhpStorm, and finally say goodbye to `var_dump` and `echo` debugging.
Related Contents
Resolving PHP "could not find driver" Error: Ultimate Guide to Missing PDO Database Drivers
Duration: 00:00 | DP | 2026-07-04 08:03:00VS Code PHP Guide: How to Trace Function Definitions Like PHPStorm
Duration: 00:00 | DP | 2026-07-04 20:27:00Resolving Nginx Permission Denied (13) Errors for WebP Images Generated by PHP Imagick
Duration: 00:00 | DP | 2026-07-05 21:17:00Complete Guide to Installing and Configuring Git Server on Synology NAS: Basic to Advanced
Duration: 00:00 | DP | 2026-07-16 20:39:02Why Do .smbdelete Hidden Files Appear After Deleting on Mac SMB Shares? Causes & Ultimate Solutions
Duration: 00:00 | DP | 2026-06-27 19:10:00Complete Guide to Setting Docker Container Timezone to UTC+8 (Asia/Shanghai)
Duration: 00:00 | DP | 2026-06-30 20:43:30How to Fix Chrome Cannot Access Internal IPs (ERR_ADDRESS_UNREACHABLE) When Safari Works
Duration: 00:00 | DP | 2026-07-17 08:41:39Fixing Nginx 500 Error: Internal Redirection Cycle (SPA vs PHP Config)
Duration: 00:00 | DP | 2026-07-02 21:45:50Fixing 'Unable to locate package openjdk-17-jdk' in PHP 8 Docker (Debian Trixie)
Duration: 00:00 | DP | 2026-07-25 09:23:18Docker Compose Advanced: Configuring Static IPs and Cross-Container SOCKS5 Proxies
Duration: 00:00 | DP | 2026-07-26 09:28:30Nginx Reverse Proxy Guide: Elegantly Routing Specific Subdirectories to Docker Containers
Duration: 00:00 | DP | 2026-07-26 21:31:06DevOps Practice: How to Safely Clear Logs of a Running Docker Container?
Duration: 00:00 | DP | 2026-07-27 09:33:42PhpStorm Shortcut Tips: How to Use Cmd+D to Select Next Occurrence Like Sublime Text
Duration: 00:00 | DP | 2026-07-28 09:38:55Practical Guide: Translating Complex Docker Compose to Docker Run Commands
Duration: 00:00 | DP | 2026-07-29 09:44:07Stop Making Timezone Mistakes in PHP: The Ultimate Guide to time() and UTC
Duration: 00:00 | DP | 2026-06-25 11:29:00Beyond 99.9%: A Deep Dive into a User-Centric Weighted Sampling Algorithm for Availability
Duration: 00:00 | DP | 2026-06-26 12:57:00The Ultimate Guide to Docker Cron Logging: Host vs. Container Redirection - Are You Doing It Right?
Duration: 00:00 | DP | 2026-01-05 08:03:52Cron Job Failing? The Ultimate Guide to Fixing 'docker: command not found'
Duration: 00:00 | DP | 2026-08-01 09:59:44Recommended
Why Does My Device Have Three IPv6 Addresses? A Guide to Link-Local, Public, and Privacy Addresses
00:00 | 143Confused after enabling IPv6 and finding multiple ...
Mastering Markdown Spacing: The Ultimate Guide to Controlling Your Document Layout
00:00 | 201Ever struggled with adjusting the vertical spacing...
PHP String Magic: Why `{static::$table}` Fails and 3 Ways to Fix It (Plus Security Tips)
00:00 | 124Why does embedding a static property like `{static...
MySQL TIMESTAMP vs. DATETIME: The Ultimate Showdown on Time Zones, UTC, and Storage
00:00 | 153Ever been confused by TIMESTAMP and DATETIME in My...