10up/wp-local-docker-v2

Xdebug Not Working with Windows 10, WSL and VS Code

jg314 opened this issue ยท 35 comments

jg314 commented

Describe the bug
I just started using WP Local Docker, so thank you so much for developing such a great resource. Since I'm not super familiar with Linux and Docker, it's taking me some time to get up to speed. The good news is that I've got most things configured at this point. The only item I can't figure out is Xdebug.

When I try to run debugging using VS Code, breakpoints don't work and I get this message in debug.log on every page load:

Xdebug: [Step Debug] Could not connect to debugging client. Tried: 10.0.128.3:9003 (from HTTP_X_FORWARDED_FOR HTTP header), host.docker.internal:9003 (fallback through xdebug.client_host/xdebug.client_port) :-(

I've used Xdebug a lot in the past, so I'm pretty confident I know how to use it generally, but I can't seem to get it working with Windows 10, WSL and Docker. Can you give me any advice?

Thanks a ton.

Environment information

  • Device: Acer Laptop
  • OS: Windows 10 with WSL
  • Docker Desktop version: 4.5.1
  • Browser and version: Chrome v99.0.4844.51
  • WordPress version: 5.9.2

This might be an issue with WSL 2 not forwarding ports properly. I can't provide an in-depth explanation of the issue but here's how I managed to get XDebug working under WSL 2.

1- Get your WSL 2 IP Adress with ip addr show eth0 | grep -oP '(?<=inet\s)\d+(\.\d+){3}'
2 - Add a manual host entry to your Windows 10 hosts file that points to that IP (e.g: wsl2.test)
3 - Edit config/php-fpm/docker-php-ext-xdebug.ini and add/replace the following line:

xdebug.remote_host = wsl2.test ; replace with your host name or IP address

4 - Perform a global restart 10updocker stop all && 10updocker start env-name

Keep in mind that WSL 2 Ip address will change every time you restart your machine or just WSL itself. I know it's possible to have windows automatically update the hosts file with the correct IP address but I haven't managed to get that running.

jg314 commented

Thanks @nicholasio, I'll give that a try. I really appreciate the message.

So, just to clarify, WP Local Docker doesn't work out of the box with WSL 2? I want to make sure I understand what the expectations should be for other sites I add moving forward.

This is more of a WSL 2 limitation than an issue with WP Local Docker. For the most part if should work "out of the box"

jg314 commented

That's definitely helpful. So as I create other sites in the future I shouldn't need to make the adjustments you included at #294 (comment)?

Thanks again for the help.

You would need to perform steps 3 and 4 for every site. Hopefully, this will be fixed in WSL 2 soon.

jg314 commented

Awesome, thanks again @nicholasio. I'll give that a try and see how it goes.

@jg314 You might want to try out changing the port from 9000 to 9003 in launch.json (#295)

jg314 commented

Thanks a ton for the suggestion @samimakela. I'm already using port 9003, so I don't think that's the problem.

@nicholasio, unfortunately, the steps you outlined at #294 (comment) didn't seem to work for me. Here's what I've got in docker-php-ext-xdebug.ini:

xdebug.mode = debug
xdebug.idekey = VSCODE
xdebug.client_host = host.docker.internal
xdebug.start_with_request = yes
xdebug.discover_client_host = 1
xdebug.remote_host = my-custom-url.test

And here's that error I'm still getting:

Xdebug: [Step Debug] Could not connect to debugging client. Tried: 10.0.0.1:9003 (from HTTP_X_FORWARDED_FOR HTTP header), host.docker.internal:9003 (fallback through xdebug.client_host/xdebug.client_port) :-(

I'd love any suggestions you might offer to help troubleshoot the cause. Thanks again for all your help.

@jg314 Can you show your launch.json?

jg314 commented

Absolutely, here's the portion for Xdebug:

{
  "name": "Listen for Xdebug",
  "type": "php",
  "request": "launch",
  "port": 9003,
  "pathMappings": {
    "/var/www/html": "${workspaceFolder}",
  }
},

For ${workspaceFolder} I'm opening VS Code directly into the /wordpress folder.

jg314 commented

Hey @nicholasio, any thoughts? I definitely don't want to push you, but I'd love your suggestions if you have a moment. For what it's worth, after some playing around I'm now getting a new error. It used to be:

Xdebug: [Step Debug] Could not connect to debugging client. Tried: 10.0.128.3:9003 (from HTTP_X_FORWARDED_FOR HTTP header), host.docker.internal:9003 (fallback through xdebug.client_host/xdebug.client_port) :-(

Now the error is:

Xdebug: [Step Debug] Time-out connecting to debugging client, waited: 200 ms. Tried: 10.0.0.1:9003 (from HTTP_X_FORWARDED_FOR HTTP header), 172.26.160.1:9003 (fallback through xdebug.client_host/xdebug.client_port) :-(

Thanks a ton.

Hey everyone!
I know i'm a bit late but i think i figured out how to solve this problem.
What i did is set the client_host in SAIL_XDEBUG_CONFIG to my WSL2 IP (you can find it with the command in step 1 from @nicholasio comment).
Also, you gonna need to install XDebug Helper Extension (Chromium based browsers) and make sure it is enabled every time you want to use the debugger.
Unfortunately each time you restart your machine or your WSL, the IP will be different. So you're gonna need reset the IP on .env, run sail down and sail up.
If anyone have a better solution, please leave it here.

Hope this helps someone!

I'll leave my docker-compose.yml and .env files for reference.

.env:

APP_NAME=Laravel
APP_ENV=local
APP_KEY=base64:qsbYfFLOPGWQnZTYMwy/xAXBiOHDEyImAntbxHrUrzI=
APP_DEBUG=true
APP_URL=http://localhost:8000
APP_PORT=8000
APP_SERVICE=app

LOG_CHANNEL=stack
LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=debug

DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=developm
DB_USERNAME=sail
DB_PASSWORD=password
FORWARD_DB_PORT=3306

SAIL_XDEBUG_MODE=develop,debug
SAIL_XDEBUG_CONFIG="client_host=172.26.89.150"
BROADCAST_DRIVER=log
CACHE_DRIVER=file
FILESYSTEM_DISK=local
QUEUE_CONNECTION=sync
SESSION_DRIVER=file
SESSION_LIFETIME=120

MEMCACHED_HOST=memcached

REDIS_HOST=redis
REDIS_PASSWORD=null
REDIS_PORT=6379

MAIL_MAILER=smtp
MAIL_HOST=mailhog
MAIL_PORT=1025
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS="hello@example.com"
MAIL_FROM_NAME="${APP_NAME}"

AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=
AWS_USE_PATH_STYLE_ENDPOINT=false

PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_HOST=
PUSHER_PORT=443
PUSHER_SCHEME=https
PUSHER_APP_CLUSTER=mt1

VITE_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
VITE_PUSHER_HOST="${PUSHER_HOST}"
VITE_PUSHER_PORT="${PUSHER_PORT}"
VITE_PUSHER_SCHEME="${PUSHER_SCHEME}"
VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"

docker-compose.yml:

version: "3"
services:
  app:
    build:
      context: ./vendor/laravel/sail/runtimes/8.1
      dockerfile: Dockerfile
      args:
        WWWGROUP: "${WWWGROUP}"
        XDEBUG: "${APP_DEBUG:-false}"
        XDEBUG_PORT: "${SAIL_XDEBUG_PORT:-9003}"
    image: sail-8.1/app
    extra_hosts:
      - "host.docker.internal:host-gateway"
    ports:
      - "${APP_PORT:-80}:80"
      - "${VITE_PORT:-5173}:${VITE_PORT:-5173}"
    environment:
      WWWUSER: "${WWWUSER}"
      LARAVEL_SAIL: 1
      XDEBUG_MODE: "${SAIL_XDEBUG_MODE:-off}"
      XDEBUG_CONFIG: "${SAIL_XDEBUG_CONFIG:-client_host=host.docker.internal}"
    volumes:
      - ".:/var/www/html"
    networks:
      - sail
    depends_on:
      - mysql
  mysql:
    image: "mysql/mysql-server:8.0"
    ports:
      - "${FORWARD_DB_PORT:-3306}:3306"
    environment:
      MYSQL_ROOT_PASSWORD: "${DB_PASSWORD}"
      MYSQL_ROOT_HOST: "%"
      MYSQL_DATABASE: "${DB_DATABASE}"
      MYSQL_USER: "${DB_USERNAME}"
      MYSQL_PASSWORD: "${DB_PASSWORD}"
      MYSQL_ALLOW_EMPTY_PASSWORD: 1
    volumes:
      - "sail-mysql:/var/lib/mysql"
      - "./vendor/laravel/sail/database/mysql/create-testing-database.sh:/docker-entrypoint-initdb.d/10-create-testing-database.sh"
    networks:
      - sail
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-p${DB_PASSWORD}"]
      retries: 3
      timeout: 5s
networks:
  sail:
    driver: bridge
volumes:
  sail-mysql:
    driver: local

Hey @nicholasio, any thoughts? I definitely don't want to push you, but I'd love your suggestions if you have a moment. For what it's worth, after some playing around I'm now getting a new error. It used to be:

Xdebug: [Step Debug] Could not connect to debugging client. Tried: 10.0.128.3:9003 (from HTTP_X_FORWARDED_FOR HTTP header), host.docker.internal:9003 (fallback through xdebug.client_host/xdebug.client_port) :-(

Now the error is:

Xdebug: [Step Debug] Time-out connecting to debugging client, waited: 200 ms. Tried: 10.0.0.1:9003 (from HTTP_X_FORWARDED_FOR HTTP header), 172.26.160.1:9003 (fallback through xdebug.client_host/xdebug.client_port) :-(

Thanks a ton.

@jg314 Did you ever fix this? I came across this issue through a Google Search because I am currently pulling hair out over this. I used to have this working but it seems like a Visual Studio Code update has broken this.

My setup:

  • Running Visual Studio Code inside WSL2.
  • XDebug 3.1.5 with similar configuration to yours for both Visual Studio Code launch.json and php.ini.
  • PHP running inside Docker container.
  • Running Windows 10 and 11 (machine depending).

I've also double checked that my settings are being correctly recognised by XDebug by using a combination of phpinfo(); and xdebug_info();.

jg314 commented

@LoveDuckie, unfortunately not. I dropped a lot of hours trying to make it happen with no luck. I'm sure there's a way. I just wasn't able to devote anymore time to it.

I'm hoping to work on it again in the future, but I'm not sure when that will be.

Good luck and let me know if you figure it out.

@LoveDuckie, unfortunately not. I dropped a lot of hours trying to make it happen with no luck. I'm sure there's a way. I just wasn't able to devote anymore time to it.

I'm hoping to work on it again in the future, but I'm not sure when that will be.

Good luck and let me know if you figure it out.

@jg314 Thanks for the super fast response!

I'll definitely let you know if I find a fix. I think the problem is something to do with port-forwarding between the Visual Studio Code process running in windows, and the extension listening on port 9003 in WSL2. Not 100% sure what the problem is but I think I'm sort of close.

image

So this configuration option is what fixed it for me.

And then I updated my Xdebug configuration to define the client_host as the host machine IP which I found in the Visual Studio Code log output.

image

;zend_extension=xdebug
; -------------------------------------
; XDebug 3+
; -------------------------------------
xdebug.client_host=172.30.173.132
; xdebug.client_host=172.30.160.1
; xdebug.client_host=172.18.0.1
xdebug.client_port=9003
xdebug.discover_client_host=true
xdebug.client_discovery_header=HTTP_FORWARD_HOST
xdebug.output_dir=/var/www/tmp/xdebug
xdebug.mode=debug
; xdebug.idekey=VSCODE
xdebug.start_with_request=yes
xdebug.remote_enable=1
; xdebug.show_error_trace=yes
; xdebug.show_exception_trace=yes
; xdebug.show_local_vars=yes
; xdebug.start_upon_error=yes
xdebug.log_level=7

xdebug.log=/var/log/php/xdebug/xdebug-remote.log

In case you didn't get pinged by my last message @jg314

jg314 commented

This is great @LoveDuckie. Thanks a ton for taking time time to outline everything. I have a few questions for you:

  • I'm not able to see the VS Code log output to grab the host machine IP. What command did you use to generate that?
  • Did you use the default launch.json file generated by VS Code for debugging, or did you make customizations? If you did, can you post those?
  • The Xdebug settings you posted include a ton more info than the default generated by WP Local Docker within /config/php-fpm/docker-php-ext-xdebug.ini. Are all those changes necessary to make it work?

Thanks again for all the time you've put into this. I'm pumped that someone was able to get this working.

jg314 commented

I was finally able to get Xdebug working with WSL 2, Docker and WP Local Docker. I followed very closely to the steps outlined at #294 (comment).

Here are the steps I followed in case this will help someone else:

  1. Start Docker Desktop.
  2. Within the WSL 2 terminal enter this command to get the needed IP address: ip addr show eth0 | grep -oP '(?<=inet\s)\d+(\.\d+){3}'
  3. Open the file at /config/php-fpm/docker-php-ext-xdebug.ini within the WP Local Docker website you're working on. Set xdebug.client_host to be whatever IP address was returned in step 2. For example, the final line might look like xdebug.client_host = 192.168.119.150. Until we can find a better solution, you'll need to repeat steps 2 and 3 every time WSL 2 restarts.
  4. Run 10updocker stop all in the WSL 2 terminal.
  5. Run 10updocker start env-name in the WSL 2 terminal. Make sure to replace env-name with the name of your environment.
  6. If you get the error Xdebug: [Step Debug] Time-out connecting to debugging client... take a look at https://xdebug.org/docs/all_settings#start_with_request. It's likely Xdebug is running on every page load, even if VS Code isn't debugging.

For what it's worth @LoveDuckie, I didn't need to change the Remote.WSL2: Connection Method setting in VS Code. It worked with the default wslExeProxy option for me.

Thanks again for the help @LoveDuckie and @nicholasio.

FWIW: I think we would not have this problem if we were running the docker daemon inside WSL 2 directly instead of Docker Desktop.

I was finally able to get Xdebug working with WSL 2, Docker and WP Local Docker. I followed very closely to the steps outlined at #294 (comment).

Here are the steps I followed in case this will help someone else:

  1. Start Docker Desktop.
  2. Within the WSL 2 terminal enter this command to get the needed IP address: ip addr show eth0 | grep -oP '(?<=inet\s)\d+(\.\d+){3}'
  3. Open the file at /config/php-fpm/docker-php-ext-xdebug.ini within the WP Local Docker website you're working on. Set xdebug.client_host to be whatever IP address was returned in step 2. For example, the final line might look like xdebug.client_host = 192.168.119.150. Until we can find a better solution, you'll need to repeat steps 2 and 3 every time WSL 2 restarts.
  4. Run 10updocker stop all in the WSL 2 terminal.
  5. Run 10updocker start env-name in the WSL 2 terminal. Make sure to replace env-name with the name of your environment.
  6. If you get the error Xdebug: [Step Debug] Time-out connecting to debugging client... take a look at https://xdebug.org/docs/all_settings#start_with_request. It's likely Xdebug is running on every page load, even if VS Code isn't debugging.

For what it's worth @LoveDuckie, I didn't need to change the Remote.WSL2: Connection Method setting in VS Code. It worked with the default wslExeProxy option for me.

Thanks again for the help @LoveDuckie and @nicholasio.

Regarding step 3, what you wrote is not working for me.

When I type ip addr show eth0 | grep -oP '(?<=inet\s)\d+(\.\d+){3}' on my WSL2 terminal, what I get is 172.20.111.76. If I use this IP as the xdebug.client_host, Xdebug is not working. What works for me is using my PC's IP as the xdebug.client_host, for example xdebug.client_host=192.168.1.2.

For some reason, I believe that this is the case for you too since the IP 192.168.119.150 looks like a DHCP-assigned IP for a PC, please correct me if I'm wrong.

Also, why do you think that host.docker.internal is it not working when it's clearly mentioned in the documentation?

jg314 commented

Thanks for noting so clearly what works for you @kmgalanakis. When I use the output from ip addr show eth0 | grep -oP '(?<=inet\s)\d+(\.\d+){3}' it does work for me, but maybe something on your computer is set up differently. I'm definitely not an expert in WSL 2 or Docker, so I don't have much else to add. Hopefully someone else can chime in to clarify what's going on.

I had the same issue on WSL2, where I had to manually add the PC IP.
To make it work with xdebug.client_host = host.docker.internal, I had to modify docker-compose.yml and add

extra_hosts:
      - host.docker.internal:host-gateway

This should go under the php-fpm entry, like:

services:
   php-fpm:
      extra_hosts:
        - host.docker.internal:host-gateway

@gsarig I tried that before but it didn't work, though I just tried again and it worked perfectly! Thanks.

jg314 commented

Thanks a ton for the tip @gsarig. It would be amazing to avoid updating the IP address every time WSL 2 restarts. A few questions:

  • Can you point to where the docker-compose.yml file is that needs to be modified?
  • Does that docker-compose.yml file need to be updated for each WordPress environment, or can it be changed only once?

@jg314 the docker-compose.yml file should be at the root of your project. For example, under wp-local-docker-sites/example-test/docker-compose.yml.

It does need to be updated for each WordPress environment or, at least, I haven't found a global config file where I could set it.

jg314 commented

Thanks a ton @gsarig. It didn't work for me unfortunately. Here's the relevant part of docker-compose.yml:

phpfpm:
    image: wp-php-fpm-dev-7.4-xxxxx
    depends_on:
      - memcached
    networks:
      - default
      - wplocaldocker
    extra_hosts:
      - host.docker.internal:host-gateway
    dns:
      - 10.0.0.2
    volumes:
      - './wordpress:/var/www/html:cached'
      - './config/php-fpm/docker-php-ext-xdebug.ini:/etc/php/7.4/fpm/conf.d/docker-php-ext-xdebug.ini:cached'
      - 'wplocaldockerCache:/var/www/.wp-cli/cache:cached'
      - '~/.ssh:/home/xxxxx/.ssh:cached'
      - './config/php-fpm/wp-cli.local.yml:/var/www/.wp-cli/config.yml:cached'
    cap_add:
      - SYS_PTRACE
    environment:
      ENABLE_XDEBUG: 'true'
      PHP_IDE_CONFIG: serverName=xxxxxxxxx-test
    build:
      dockerfile: php-fpm
      context: .containers
      args:
        PHP_IMAGE: '10up/wp-php-fpm-dev:7.4-ubuntu'
        CALLING_USER: xxxxx
        CALLING_UID: 1000

Any ideas on what might be going on? Thanks again for the help.

@jg314 Did you restart your server after making the change? Something like 10updocker stop all && 10updocker start xxxxx?

If you did and it still doesn't work for you, do you get any specific error?

@jg314 mine looks exactly like yours

jg314 commented

Yep, I ran docker compose restart and 10updocker restart a few different times. I ended up with the same errors I was running into when I created this issue. It was one of these two:

Xdebug: [Step Debug] Could not connect to debugging client... or Xdebug: [Step Debug] Time-out connecting to debugging client, waited...

I'm not looking to waste all your time, so if there isn't an easy solution here I'll stick with the approach I outlined at #294 (comment).

@jg314 I'm also getting this error when I don't have my IDE listening to incoming connections. Is your IDE listening to incoming connections?

jg314 commented

@kmgalanakis, unfortunately yes. I have VS Code listening for connections. Once I switched back to using the hardcoded IP address and restarted the environment debugging immediately started working again.

Thanks again for the help.

@jg314 to be honest I'm using PHPSTORM and I know that @gsarig also does the same. Maybe I can check with VSCode tomorrow and see how it looks. I will keep you posted.

jg314 commented

Thanks again @kmgalanakis. I'm definitely lacking on experience with Docker, Linux and WSL 2, so I really appreciate the suggestions.

swayok commented

It was all ok until I moved to another country and my xdebug, that worked correctly for a year, stopped connecting to IDE. It was a big surprise for me because I had no idea why (actually it was the change of the router I was connected to).

And after several hours of depression I have found something valuable and solved my issue.

In your hosts file in Windows you might have next lines:

192.168.1.101 host.docker.internal
192.168.1.101 gateway.docker.internal

As you can see - you IP address must be 192.168.1.101 for this routing to work. My IP in wi-fi info wasn't.
So I've changed my IP address in windows network settings (wi-fi network in my case) to static IP instead of DHCP and xdebug was able to connect to IDE (PHPStorm in my case).

If you do not have these lines - add them with you IP as target. Then you might need to restart your WSL so that hosts file is updated in it.

Xdebug configs:

xdebug.mode=develop,debug
xdebug.start_with_request=yes
xdebug.client_host=host.docker.internal
xdebug.client_port=9003

As for docker compose file - there is nothing specific needed. You doo not need to expose ports or add extra_hosts. I have everything working without any additional configs.