Search code examples
javaubuntuintellij-idearemote-debuggingportforwarding

How do I remotely debug a java app on vagrant VM?


I'm running IntelliJ IDEA 2023.1.2 (Community Edition) and I'm having a problem remotely debugging a java application running on a vagrant VM. I believe it is some kind of networking issue. My vagrant VM is running Ubuntu 20.04.

The problem is that when I run the remote debugger, I see the following error in intellij

Unable to open debugger port (localhost:5005): java.net.SocketException "Connection reset"

The syslog on the vagrant VM shows the following after one of these failed connections

Aug 01 19:14:43 ubuntu2004.localdomain sshd[2095]: debug3: channel 0: waiting for connection
Aug 01 19:14:43 ubuntu2004.localdomain sshd[2095]: debug1: channel 0: connection failed: Connection refused
Aug 01 19:14:43 ubuntu2004.localdomain sshd[2095]: error: connect_to 192.168.121.118 port 5005: failed.

When I attempt to connect with jdb, I see the following error

$> jdb -attach localhost:5005
java.io.IOException: handshake failed - connection prematurally closed
    at jdk.jdi/com.sun.tools.jdi.SocketTransportService.handshake(SocketTransportService.java:142)
    at jdk.jdi/com.sun.tools.jdi.SocketTransportService.attach(SocketTransportService.java:255)
    at jdk.jdi/com.sun.tools.jdi.GenericAttachingConnector.attach(GenericAttachingConnector.java:119)
    at jdk.jdi/com.sun.tools.jdi.SocketAttachingConnector.attach(SocketAttachingConnector.java:83)
    at jdk.jdi/com.sun.tools.example.debug.tty.VMConnection.attachTarget(VMConnection.java:519)
    at jdk.jdi/com.sun.tools.example.debug.tty.VMConnection.open(VMConnection.java:328)
    at jdk.jdi/com.sun.tools.example.debug.tty.Env.init(Env.java:63)
    at jdk.jdi/com.sun.tools.example.debug.tty.TTY.main(TTY.java:1095)

Fatal error:
Unable to attach to target VM.

Here are some additional observations:

  1. The java application which is running on the VM has debugging enabled (i.e., it includes java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 in the process). I realize that the new versions of java suggest using address=*:5005 but for a variety of reasons, I can't change the Java opts on that process.
  2. I have verified that the process is indeed listening on port 5005 on the VM. netstat shows that the process is listening on 5005.
  3. I have forwarded the port to my host machine's port 5005, and can see on the host machine that the port forwarding is enabled.
  4. I can connect to the remote process from the host machine via nc localhost 5005.
  5. This question is similar but it's the inverse of what I want. I have the debugger running on the host and the java app running on the guest.

Any thoughts on what I might be missing?


Solution

  • The following command will bind the debugger server on localhost interface if you are using Java 9+ version:

    java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005

    Vagrant port forwarding is likely expecting an external interface to work properly.

    Since you can't change the Java debugger options (to use address=*:5005), the workaround would be to use socat to forward the port from the external interface to localhost inside the VM like this:

    socat tcp-listen:5006,reuseaddr,fork tcp:localhost:5005
    

    Now you can forward port 5005 to 5006 in Vagrant and it should work.