What is tunnel-ssh?
The tunnel-ssh npm package allows you to create SSH tunnels in Node.js applications. This can be useful for securely connecting to remote servers, databases, or other services that require SSH tunneling.
What are tunnel-ssh's main functionalities?
Basic SSH Tunnel
This code sample demonstrates how to set up a basic SSH tunnel using the tunnel-ssh package. The configuration object includes details such as the SSH username, host, port, destination host and port, local host and port, and the private key for authentication.
const tunnel = require('tunnel-ssh');
const config = {
username: 'user',
host: 'remote.server.com',
port: 22,
dstHost: '127.0.0.1',
dstPort: 27017,
localHost: '127.0.0.1',
localPort: 27017,
privateKey: require('fs').readFileSync('/path/to/private/key')
};
tunnel(config, function (error, server) {
if (error) {
console.error('SSH connection error: ', error);
} else {
console.log('SSH tunnel established');
}
});
SSH Tunnel with Forwarding
This code sample shows how to set up an SSH tunnel with port forwarding. The 'keepAlive' option is set to true to maintain the connection. This is useful for applications that need to keep a persistent connection to a remote database or service.
const tunnel = require('tunnel-ssh');
const config = {
username: 'user',
host: 'remote.server.com',
port: 22,
dstHost: '127.0.0.1',
dstPort: 3306,
localHost: '127.0.0.1',
localPort: 3306,
privateKey: require('fs').readFileSync('/path/to/private/key'),
keepAlive: true
};
tunnel(config, function (error, server) {
if (error) {
console.error('SSH connection error: ', error);
} else {
console.log('SSH tunnel with forwarding established');
}
});
Dynamic Port Forwarding
This code sample demonstrates how to set up a dynamic SSH tunnel, which can be used as a SOCKS proxy. The 'dynamic' option is set to true, allowing the tunnel to dynamically forward traffic to different destinations.
const tunnel = require('tunnel-ssh');
const config = {
username: 'user',
host: 'remote.server.com',
port: 22,
dstHost: '0.0.0.0',
dstPort: 0,
localHost: '127.0.0.1',
localPort: 1080,
privateKey: require('fs').readFileSync('/path/to/private/key'),
dynamic: true
};
tunnel(config, function (error, server) {
if (error) {
console.error('SSH connection error: ', error);
} else {
console.log('Dynamic SSH tunnel established');
}
});
Other packages similar to tunnel-ssh
ssh2
The ssh2 package is a more general-purpose SSH client for Node.js. It provides a wide range of SSH functionalities, including tunneling, executing commands, and file transfers. Compared to tunnel-ssh, ssh2 offers more flexibility and control over SSH connections but requires more setup and configuration.
node-ssh
The node-ssh package is a high-level SSH client for Node.js that simplifies the process of connecting to SSH servers, executing commands, and transferring files. It is easier to use than ssh2 but offers less control over the SSH connection. It is a good alternative to tunnel-ssh for users who need basic SSH functionalities without the complexity.
ssh2-sftp-client
The ssh2-sftp-client package is built on top of ssh2 and provides a simplified API for SFTP (SSH File Transfer Protocol) operations. While it focuses on file transfers, it can also be used to create SSH tunnels. It is a good choice for users who primarily need SFTP capabilities with occasional SSH tunneling.
Tunnel-SSH
==========
ssh -L [LOCAL_IP:]LOCAL_PORT:DESTINATION:DESTINATION_PORT [USER@]SSH_SERVER
Tunnel-ssh is based on the fantastic ssh2 library by Brian White.
Latest Release 5.0.0
Breaking change in 5.0.0
Please note that release 5.0.0 uses a complete different approch for configuration and is not compatible to prio versions.
New Features
- Reuse of ssh client instead of creating a new one for each connection
- Promise / Async Await support
Concept
Tunnel-ssh v5 is designed to be very extendable and does not provide as much sematic sugar as prio versions.
The design goal was to use the original settings for each part used in the project to be able to use all possible binding features from client and server.
The configuration is separated in the following parts:
- Tunnel server
- TCP Server
- SSH Client
- SSH Forwarding
Tunnel Server Options
This configuration controls be behaviour of the tunnel server.
Currently there is only one option available.
Example:
const tunnelOptions = {
autoClose:true
}
autoclose - closes the Tunnel-Server once all clients disconnect from the server.
Its useful for tooling or scripts that require a temporary ssh tunnel to operate.
For example a mongodump.
Set this option to false will keep the server alive until you close it manually.
TCP Server options
Controls the behaviour of the tcp server on your local machine.
For all possible options please refere to the official node.js documentation:
ServerListenOptions
Example:
const serverOptions = {
host:'127.0.0.1',
port: 27017
}
SSH client options
Options to tell the ssh client how to connect to your remote machine.
For all possible options please refere to the ssh2 documentation:
ssh2 documentation
You will find different examples there for using a privateKey, password etc..
Example:
const sshOptions = {
host: '192.168.100.100',
port: 22,
username: 'frylock',
password: 'nodejsrules'
};
SSH Forwarding options
Options to control the source and destination of the tunnel.
Example:
const forwardOptions = {
srcAddr:'0.0.0.0',
srcPort:27017,
dstAddr:'127.0.0.1',
dstPort:27017
}
API
Tunnel-SSH exposes currently only one method: createTunnel
createTunnel(tunnelOptions, serverOptions, sshOptions, forwardOptions);
The method retuns a promise containing the server and ssh-client instance. For most cases you will not need those instances. But in case you want to extend the functionallity you can use them to
bind to there events like that:
createTunnel(tunnelOptions, serverOptions, sshOptions, forwardOptions).
then(([server, conn], error)=>{
server.on('error',(e)=>{
console.log(e);
});
conn.on('error',(e)=>{
console.log(e);
});
});
For a list of all possible Events please refere to the node.js documentation for the server and the ssh2 documentation for the client.
Usage Example
The following example shows how to connect to a remote mongodb and bind it to all local interfaces.
import {createTunnel} from 'tunnel-ssh';
const port = 27017;
const tunnelOptions = {
autoClose:true
};
const serverOptions = {
port: port
};
const sshOptions = {
host: '192.168.100.100',
port: 22,
username: 'frylock',
password: 'nodejsrules'
};
const forwardOptions = {
srcAddr:'0.0.0.0',
srcPort:port,
dstAddr:'127.0.0.1',
dstPort:port
};
let [server, conn] = await createTunnel(tunnelOptions, serverOptions, sshOptions, forwardOptions);
server.on('connection', (connection) =>{
console.log('new connection');
});
Too complicated ?
If you just searching for an easy way to forward a remote port to your local machine try the followwing:
import {createTunnel} from 'tunnel-ssh';
const sshOptions = {
host: '192.168.100.100',
port: 22,
username: 'frylock',
password: 'nodejsrules'
};
function mySimpleTunnel(sshOptions, port, autoClose = true){
let forwardOptions = {
srcAddr:'127.0.0.1',
srcPort:port,
dstAddr:'127.0.0.1',
dstPort:port
}
let tunnelOptions = {
autoClose:autoClose
}
let serverOptions = {
port: port
}
return createTunnel(tunnelOptions, serverOptions, sshOptions, autoClose);
}
await tunnel(sshOptions, 27017);