How to reverse SSH tunnel to remote docker container for Xdebug?

Question:

There are many posts on SO and elsewhere on how to set this up. So far I’ve been unsuccessful in getting it working.

Setup
Local machine – Windows 10, with Cygwin, git bash, and WSL2 with Ubuntu installed; and MacBook Air (Mojave)
Host machine – AWS EC2 instance running Amazon Linux 2
Docker container – CentOS 7.8 running PHP with Xdebug
Goal
Remotely debug PHP code in container from local machine by utilizing a reverse tunnel from the local machine to the container.

I have gotten this working before when the PHP code was installed locally on the host machine, so the question is not around Xdebug. As soon as I moved the PHP code into the container, debugging no longer works.

What I’ve tried
Setting up a reverse tunnel from the local machine to the host EC2 instance works. For this I’m doing ssh -vvv -i "aws.pem" -R 9000:localhost:9000 user@ec2instance in terminal, cygwin, or git bash and testing with nc -z localhost 9000 || echo 'no tunnel open' on the host machine.

When I docker exec -it container bash into the container and run nc, the tunnel is not available.

I’m using docker-compose:

I have tried with and without mapping the 9000 port. I have tried variations of the ssh tunnel:

ssh -vvv -i "aws.pem" -R :9000:localhost:9000 user@ec2instance
ssh -vvv -i "aws.pem" -R 0.0.0.0:9000:localhost:9000 user@ec2instance
ssh -vvv -i "aws.pem" -R \*:9000:localhost:9000 user@ec2instance
ssh -vvv -i "aws.pem" -R 9000:172.20.0.2:9000 user@ec2instance (container IP)

I’ve also tried using ssh -L with no luck.

Several posts, like this one suggest adding GatewayPorts yes on the host machine. I’ve tried this as well with no change.

I have not tried using --network=host, primarily due to security concerns. I also would rather not use ngrok, as I’d like to be able to use localhost or host.docker.internal for the xdebug.remote_host setting.

For completeness, here is what I have for Xdebug:

Answer:

I got this working. After reading up on the ssh man page and looking over things again, I realized I was binding to the docker container IP not the bridge (docker0) IP.

I updated my connect command to ssh -vvv -i "aws.pem" -R 9000:172.17.0.1:9000 user@ec2instance with the right IP and the tunnel started working. I do still have GatewayPorts enabled (per the man page) and removed the 9000:9000 mapping.

I then updated my xdebug.remote_host value to the same IP and debugging is now working. Not sure why host.docker.internal didn’t work, but that’s for another day.

Leave a Reply