I have a Docker Compose stack running on a cloud server. One of the services is PHP with Xdebug.
When I run the stack on my local machine, I can use Xdebug just fine. But when I run it on the remote cloud server, no matter how I configure things, I can’t seem to get Xdebug to connect back to my local IDE.
I’ve tried changing various Xdebug settings (discover_client_host
etc.) but nothing seems to work.
My latest attempt is as follows:
- From
docker-compose.yml
:
[...]
environment:
- XDEBUG_MODE=debug
- XDEBUG_CONFIG=discover_client_host=On
ports:
- 9003:9003
[...]
networks:
internal:
driver: bridge
- When I run
docker compose up
on the cloud server I can see that exposes port 9003:
sudo netstat -nlp | grep 9003
tcp 0 0 0.0.0.0:9003 0.0.0.0:* LISTEN 2119936/docker-prox
tcp6 0 0 :::9003 :::* LISTEN 2119943/docker-prox
- So then I try to create a port forward via an SSH tunnel from my local machine like this:
ssh -R 9003:localhost:9003 [email protected]
But I get an error: Warning: remote port forwarding failed for listen port 9003
presumably because port 9003 is already in use.
But if that’s the case, how can I ever access port 9003 inside the Docker container from my local machine?
2
Answers
This turned out to be quite the puzzle, and several pieces had to fit together rather precisely to solve it:
docker-compose.yml
:This allows the Docker container to resolve the host machine's internal IP address, as explained in this question and this article.
As per Derick's answer, I removed the
ports:
section fromdocker-compose.yml
.On the remote machine I had to enable
GatewayPorts clientspecified
in/etc/ssh/sshd_config
(then restart the sshd service).This allows you to create an SSH port forward tunnel which listens on all network interfaces (
0.0.0.0
or*
) which is required in order for the Docker container's virtual network interface to reach your client machine via the tunnel. By default, theGatewayPorts
setting limits remote port forwardings to bind to thelocalhost
interface only which Docker can't "see".*
:After doing all this, I was finally able to connect to Xdebug running inside a Docker container on the remote server from my local machine. 🎉
P.S. A useful command while debugging this was
nc -vz 127.0.0.1 9003
which allowed me to check if my SSH port forward was working on the host machine, at least.If you set your docker container to expose port 9003, it will open that port. Which means that your
ssh -R
command can’t open that same port.You need to remove:
And then your
ssh -R 9003...
command will work.As Xdebug needs to connect to your machine, it also means that it needs to connect to this port
9003
that yourssh -R
sets up. If you setxdebug.discover_client_host=1
, then it will try to use your local machine’s global IP address, which will likely not work. Instead, you need to setxdebug.discover_client_host=0
.The ssh tunnel that you setup basically creates (from the POV of your docker container) a port 9003 on the host machine. If that is already in the docker container too, then you can set
xdebug.client_host=localhost
.I believe however, that your SSH opens a shell on the host where docker runs in. In which case you need to set
xdebug.client_host
to the IP address of it’s local gateway, or, if you’re using xdebug 3.2, you can setxdebug.client_host=xdebug://gateway
.