'PhpStorm Xdebug remote ssh debugging of CLI script on Vagrant breakpoints not triggering
I am trying to debug a PHP script which is checked out locally on a Windows machine, then mapped to a Ubuntu VM (configured using Vagrant) which have Nginx, PHP and Xdebug installed. Also it's important to point out that I have php-fpm working in this setup and I have had a PHP script running as well, but in VSCode and not PhpStorm.
My PhpStorm config is:
My Xdebug config (currently, I have tried a million different config now):
zend_extension=xdebug.so
xdebug.mode=debug
xdebug.client_host=127.0.0.1
xdebug.client_port=9003
xdebug.remote_enable=1
I then configure my SSH tunnel like so:
putty.exe -ssh <vm-ip> -R 9003:localhost:9003
I am able to run the file and get its output in PhpStorm, but my breakpoints are not working. I just get the following:
And this is the content of the php file I am trying to debug:
So as we can see, the script executes without problem, the breakpoints just don't trigger. And as mentioned I have Xdebug working in PhpStorm for php-fpm when debugging websites, but when trying to debug a single PHP script I run into this problem.
I have tried so many different things, which makes me sure I am overlooking something basic I have forgotten. Right now I am suspecting PhpStorm for being annoying.. on output we can see the script is invoked with:
[vagrant://C:\vagrant]:/usr/bin/php -dxdebug.mode=debug -dxdebug.client_port=9002 -dxdebug.client_host=192.168.1.185
I have not entered these -d arguments anywhere and I am not sure why PhpStorm keeps adding them (also it uses port 9002 and I have configured 9003). But I am not able to get anything working in VSCode as well, so I am properly doing something wrong.
My Xdebug config for php-fpm which is currently working in PhpStorm is:
zend_extension=xdebug.so
xdebug.mode=develop,debug
xdebug.idekey=PHPSTORM
xdebug.output_dir=/tmp/xdebug
xdebug.log=/tmp/xdebug/xdebug.log
xdebug.remote_log=/root/logs/xdebug.log
xdebug.force_display_errors=1
xdebug.force_error_reporting=1
xdebug.remote_enable=1
xdebug.remote_handler=dbgp
xdebug.remote_host=127.0.0.1
xdebug.remote_autostart=1
xdebug.client_host=127.0.0.1
xdebug.client_port=9003
xdebug.remote_connect_back=0
xdebug.var_display_max_depth=-1
xdebug.var_display_max_children=-1
xdebug.var_display_max_data=-1
.. i then have a PHP | Servers settings for this as well:
If I try to use this config for PHP CLI script debugging, it's not working either (+ its PhpStorm waiting for Xdebug connections which I guess works a bit differently from PHP CLI script debugging)
What am I doing wrong since my breakpoints are not triggering when running single CLI scripts?
Solution 1:[1]
I found a solution, it stupid but it works..
So essentially what annoyed me a lot, was that PHPSTORM added intepretor arguments which i did not specify, which i also mentioned above in the question.. it ended up executing the following on VM:
[vagrant://C:\vagrant]:/usr/bin/php -dxdebug.mode=debug -dxdebug.client_port=9002 -dxdebug.client_host=192.168.1.185
I did not spoecify these -d arguments and could not for the life of me figure out how to make PHPSTORM remove them.. as mentioned in the question comments the port is specified through settings | php | debug | "debug port" so at least i could change that.. but the client_host was still wrong.
What i did to fix is, is just overriding it again so the cmd executed on the VM ended up being this (obs: i have used a lot of different ports to try and fix it.. which is why i am now using 9004):
[vagrant://C:\vagrant]:/usr/bin/php -dxdebug.mode=debug -dxdebug.client_port=9004 -dxdebug.client_host=192.168.1.185 -dxdebug.client_host=127.0.0.1 thefile-i-wanna-debug.php
My guess is this overrides the first, wrong, argument and then makes everything work. You do this by adding intepretor arguments like so in your run-configuration:
and the xdebug config i ended up with, now matches all the guides i have found on SSH debugging as well, and is only:
zend_extension=xdebug.so
xdebug.idekey=PHPSTORM
xdebug.mode=debug
xdebug.client_host=127.0.0.1
xdebug.client_port=9004
Success! :-D
Solution 2:[2]
The enumerate call returns a tuple on each loop, not a single value. So, your i is being set to a tuple, which consists of the index (starting at 1) and the element in the pointlist. You can fix this many ways. One is to change:
for i in enumerate(pointlist, start=1):
to:
for i in range(len(pointlist), start=1):
Or you can keep the enumerate call and drop the returned element of pointlist, which doesn't really make much sense, but it's an option:
for i, _ in enumerate(pointlist, start=1):
Here, the _ is a placeholder that takes the pointlist value to prevent i from being a tuple. The first option is much better.
Note that list indeces start at 0, not 1, so you're start=1 is probably going to break your logic. You might be much better off with the default start value of 0.
Solution 3:[3]
you might want to use range instead of enumerate.
import random
X=1350
Y=250
p1=[X, Y]
p2=[X, Y]
p3=[X, Y]
p4=[X, Y]
p5=[X, Y]
p6=[X, Y]
p7=[X, Y]
p8=[X, Y]
p9=[X, Y]
p10=[X, Y]
p11=[X, Y]
pointlist = [p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11]
limit1=1150
limit2=1250
for i in range(len(pointlist)):
pointlist[i][0] = random.randrange(limit1, limit2)
limit1-=100
limit2-=100
if you still want to use enumerate.
import random
X=1350
Y=250
p1=[X, Y]
p2=[X, Y]
p3=[X, Y]
p4=[X, Y]
p5=[X, Y]
p6=[X, Y]
p7=[X, Y]
p8=[X, Y]
p9=[X, Y]
p10=[X, Y]
p11=[X, Y]
pointlist = [p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11]
limit1=1150
limit2=1250
for i in enumerate(pointlist, start=0):
index = i[0] # get the index from here.
value = i[1]
pointlist[index][0] = random.randrange(limit1, limit2)
limit1-=100
limit2-=100
Solution 4:[4]
Off-topic.
Adding to Mat's amazing answer:
I believe you explicitly created p1...p11 so when you change the x-coordinate of a point, other points will not be affected. If you are not going to use the references p1...p11, I suggest using a list comprehension:
point_list = [[X, Y] for _ in range(11)]
The inner list [X, Y] is created 11 times, and they are 11 separate objects, so changing any one of it will not affect the others. You can visualise it using Python Tutor.
I personally prefer using custom objects than dealing with nested lists in your case, as it better displays the intent of the code. Here is how I would have coded it:
import random
class Coordinate:
"""
A container that represents a coordinate point.
Functions to manipulate the coordinates (called methods)
can be added here.
You can optionally convert it to a dataclass using
functools.dataclass decorator to clean up the code further.
"""
def __init__(self, x: float, y: float) -> None:
""" At creation of the Coordinate object,
we set its x, y-coordinate values. """
self.x = x
self.y = y
def __repr__(self) -> str:
""" Defines how a Coordinate should be represented as a string."""
return f'Coordinate({self.x}, {self.y})'
X = 1350
Y = 250
coords = [Coordinate(X, Y) for _ in range(11)]
lower_bound = 1150
upper_bound = 1250
for coord in coords:
# Here we are saying we want to change the x-coordinate,
# instead of the ambiguous coord[0] = ...
coord.x = random.randrange(1150, 1250)
lower_bound -= 100
upper_bound -= 100
print(coords)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Thor A. Pedersen |
| Solution 2 | Gary02127 |
| Solution 3 | |
| Solution 4 | Bill Ong |








