Easy and simple ssh connections with node.js

Martin Wentzel
Stocard
2 min readJul 4, 2018

--

We at Stocard aim to write all of our code with JavaScript or Typescript. This e.g. includes our internal CLI (which is based on oclif).

Some of our internal tools need to access our servers, either to execute a command or to forward some ports. What to do in this case? Probably every developer has his/her own set of shortcuts (sophisticated ssh configs, well-maintained bash configs), but as the amount of servers and ports grow and change on a regular basis, this is not maintainable anymore. Do you want to open a ssh tunnel manually every time you want to use an internal tool? How do you maintain the different server URLs?

We wanted to equip our internal CLI with the capability to open tunnels, forward ports and execute commands, so that our developers do not have to care about maintaining their ssh configs and constantly updating their own scripts.

So, I set out on the quest to open ssh tunnels programmatically with the following requirements:

  • needs to be in JavaScript or Typescript
  • needs port forwarding
  • can execute commands on the remote server
  • support for bastion (jump) hosts as our infrastructure uses bastion hosts

I found adit which was sufficient for port forwarding, but has no jump host support. It does also not support command execution. Moreover, it did not seem to clean up resources correctly. I was not able to close the ssh connection. I also took a look at ssh2. It actually is able to comply with all 4 requirements, but everything has to be done manually: connecting to the bastion host, then piping streams to forward a port from the remote host to your local host.

I decided to write our own solution: node-ssh-forward

It currently supports:

  • bastion hosts
  • port forwarding
  • interactive shell on the remote server
  • command execution on the remote server

Using is easy

The equivalent to

$ ssh -L 9000:localhost:80 -J your-jump-host.com example.com

is

const SSHConnection = require('node-ssh-forward').SSHConnectionconst sshConnection = new SSHConnection({
endHost: 'example.com',
bastionHost: 'your-jump-host.com'
})
await sshConnection.forward({
fromPort: 9000,
toPort: 80,
})

Also executing a command on the server is straight-forward:

const SSHConnection = require('node-ssh-forward').SSHConnectionconst sshConnection = new SSHConnection({
endHost: 'example.com',
bastionHost: 'your-jump-host.com'
})
await sshConnection.executeCommand('uptime')

Opening a tty is a no-brainer:

const SSHConnection = require('node-ssh-forward').SSHConnectionconst sshConnection = new SSHConnection({
endHost: 'example.com',
bastionHost: 'your-jump-host.com'
})
await sshConnection.tty()

The connection closes after you exit from the server.

Check it out and include it in your own project!

--

--