Cannot remote debug node.js app

I’m trying to remotely debug my node.js app through IntelliJ, but always get "cannot connect to /[ipv6 address]:9229” in the IDE. Here’s what I’m doing:

  • My app is running via node --inspect=0.0.0.0
  • Locally I run fly proxy 9229
  • I was initially setting the debugger to connect to localhost:9229, but then I found this related thread which says to use the private IPv6 address, so I also tried to grab the fdaa IPv6 address from fly ips private, and then set the debugger to attach on that address and port 9229, but I always get “cannot connect to …”

Any thoughts on what I might be missing?

You need to explicitly bind the debugger server to your fdaa:: address or ::0, the IPv6 equivalent of 0.0.0.0. So the steps would be:

  • Run app via node --inspect=[::0] (Including the brackets)
  • Run fly proxy 9229
  • Connect your debugger client to localhost:9229

Notes:

  • Connecting the chrome://inspect debugger via Wireguard tunnel address (app-name.internal:9229) directly didn’t work for me , even though the server is reachable via curl.

  • You can use NODE_OPTIONS env var to enable/disable inspect w/o rebuilding the image:

flyctl secrets set NODE_OPTIONS='--inspect=[::0]:1337' -a app-name

It will require the instance to restart due to the env var change though. Unset NODE_OPTIONS if you’d like to restart instance w/o debugger.

  • Node allows to instrument an already running process to start debug via SIGUSR1 signal:
flyctl console ssh -a app-name
kill -s USR1 $(pidof -s node)
app[9d8041j7] gru [info] Debugger listening on ws://127.0.0.1:9229/237aac43-b16b-4506-95a9-22a43b453c41

It will bind to 127.0.0.1 by default and wouldn’t work due to Wireguard being IPv6 only. To change this, you can use --inspect--port via NODE_OPTIONS env var instead. It will configure the desired inspect address to bind to, but won’t start it until receiving a SIGUSR1 signal.

flyctl secrets set NODE_OPTIONS='--inspect-port=[::0]:9229' -a app-name

Now sending a SIGUSR1 again will activate the inspector and correctly bind it to your IPv6 address:

flyctl console ssh -a app-name
kill -s USR1 $(pidof -s node)
app[9d8041j7] gru [info] Debugger listening on ws://[::0]:9229/237aac43-b16b-4506-95a9-22a43b453c41

This is the best option as it allows you to inspect an already running production instance when desired in the future without rebuilding the image, changing env vars or restarting the app.

  • You can detach the debugger from your production app without restart/killing it as well, by running console.log('Closing inspector'); require('inspector').close() on the Console tab of your debug client.
2 Likes