Debugging node.js in Docker using Node Inspector

In this post I’ll describe a convenient approach to debugging a node.js docker container, using the library node-inspector. I think it’s also an interesting case study on how sometimes you need to think a little differently when working with containers.


Although it’s possible to debug node.js using your favourite IDE, it’s always convenient to have browser-based methods for probing data or code, so that’s why we like to have Node Inspector available.


There are multiple theoretical ways to achieve this, so I’ll start with the ones I didn’t choose or that didn’t work, before describing how it now works.

Integrate Node Inspector with the node-app itself

The most obvious way to achieve this would be to run Node Inspector within the same node.js container, but I don’t like that for a couple of reasons:

  1. It makes it harder to run a "vanilla"/standard node.js image if you need both your node-app to run as well as Node Inspector in parallel
  2. I like my containers to be as similar in dev as they are in production, to avoid “works on my machine” problems

So for these reasons I’m going to rule out any solution that requires changes to how my core node-app container starts in dev, so that it mirror the way it starts in production.

Connecting Node Inspector remotely to the node-app container

This was the next idea - i.e. use Docker’s inbuilt DNS to connect Node Inspector to node-app:5858 and we should be fine. Unfortunately, Node Inspector doesn’t really work remotely, so this is not possible. i.e. it wasn’t possible to get it to work when the debugger container and node-app containers were on separate IP addresses.

Host networking for all containers

The next possibility - one we used previously - was that all containers run using “host” networking. Therefore when running Node Inspector it could easily attach to localhost:5858 to debug the node.js process. Host networking has a few downsides though, so we avoided this for reasons independent of debugging.

Docker ‘container’ networking

I didn’t know that this type of networking even existed until I was searching for solutions to this very Node Inspector problem. An example of someone getting it to work this way is @seelio on GitHub, with this repository: seelio/node-inspector-docker

The term ‘container’ networking is a bit confusing, so here’s an example from @seelio’s docker-compose.yml:

  container_name: node-inspector-node-app
  # ----------------------------------------------------------
  # Use the image from the script
  image: seelio/node-inspector:latest
  # ----------------------------------------------------------
  # Share a network with the node-app container.
  # This is the only way to get the node-app process
  # to take debug requests from node inspector, since it
  # onlye listens on localhost/, and doesn't like it when you
  # try to map ports through docker ports.
  network_mode: "container:node-app"
  # ----------------------------------------------------------
  # Grab volumes from the node-app container.
  # This makes pulling source maps, etc from the
  # node app container possible.
  # ----------------------------------------------------------
  # It's also important that the node-inspector files be
  # present at the same location in both the node-app and this
  # node-inspector container.
    - node-app

As you can see, the key trick here is network_mode: "container:node-app". essentially means that the Node Inspector container can be a parasite off the node.js container’s networking, which in turn means that Node Inspector can connect to localhost:5858 if the node.js app has bound to it. One important point to note here is that you then need to configure Node Inspector’s port (e.g. 8080 by default) on the node.js container configuration, not Node Inspector’s. e.g.

    # ----------------------------------------------------------
    # Open the app port
    - 3000:3000
    # ----------------------------------------------------------
    # Open the port that node-inspector will listen on
    # This is done here instead of below because the node-
    # inspector container uses --net=container mode
    - 8080:8080

I experienced two problems with this approach. The first seems to be a docker compose bug, because when I tried to cold-start the containers with this type of configuration I got the following error:

ERROR: Service 'debugger' uses the network stack of container 'node-app' which does not exist.

I could overcome this by using a separate docker-compose.yml file for debugger, but still one terminal problem remained: as part of our dev workflow, our node.js node-app container gets restarted. Unfortunately this somehow “broke” the parasite networking from Node Inspector at the same time. i.e. I’d need to restart Node Inspector each time node-app restarts. Although this is achievable, it wasn’t something I wished to do.

The Solution: Hybrid bridge + host networking

The final solution was pretty obvious in hindsight. Although all our production containers (node.js, postgres, etc) use bridge networking, there’s no reason why we can’t use host networking for Node Inspector.

The Docker Compose config for debugger is therefore simple, with most of the below being project-specific settings for us anyway:

    container_name: debugger
    network_mode: host
      service: base
      - /app/containers/debugger:/app/container

One little trick required was the addition of port 5858 mapping for the node-app container so that Node Inspector can see it as port 5858 on the host:

      - "5858:5858" # Port needs to be mapped to host so that debugger container can access it

Important to note:

  • This is contained in our docker-compose.override.yml file, which is only used in development.
  • Our EC2 security group settings ensure that port 5858 can’t actually be seen outside the host
  • Our EC2 security group settings do allow Node Inspector’s own interface port to the outside world, so we use HTTP security to limit access to that

In Summary

  • Use host networking for Node Inspector even if you don’t use it for other containers
  • Map the node.js debug port (e.g. 5858) to the host, but only in your dev environment
  • Preferably don’t allow access to that port from outside the host
  • Allow outside access (for yourself) to Node Inspector’s own port (e.g. 8080) but ideally secure it

I’ve left out a few small details that are mostly project-specific, but if you have any questions then please ask them below and I can provide more details.

Rhys Arkins-

Rhys is the founder of Key Location