SSH2 Client and Server for Node.js
ssh2 is a pure JavaScript implementation of an SSH2 client and server for Node.js, enabling secure remote command execution, file transfers (SFTP), and interactive shell sessions. The current stable version is 1.17.0, with development actively maintained against recent OpenSSH versions (e.g., OpenSSH 8.7). This library is distinguished by its comprehensive support for both client and server roles, offering an extensive API for various channel types (exec, shell, direct-tcpip, X11, subsystems) and pluggable authentication methods, including password and public key. It provides fine-grained control over SSH connections, making it suitable for building custom SSH tooling, automating deployments, or implementing secure backend services. While it does not adhere to a strict release cadence, updates are released as features are added or bugs are fixed, ensuring ongoing compatibility and security.
Common errors
-
Error: All configured authentication methods failed
cause The SSH server rejected all attempted authentication methods (e.g., password, private key). This usually means incorrect credentials, an invalid private key, or the server not supporting the client's offered authentication methods.fixVerify the `username`, `password`, or `privateKey` used in the `connect` options. Ensure the `privateKey` path is correct and the key file is readable by the Node.js process. Check server logs for more details on authentication failures. -
Error: connect ECONNREFUSED
cause The client could not establish a TCP connection to the specified host and port. This typically indicates the SSH server is not running, is not accessible from the client's network, or a firewall is blocking the connection.fixConfirm the `host` and `port` are correct. Check if the SSH server process is running on the target machine. Verify network connectivity and firewall rules between the client and server. -
Error: privateKey is required
cause The `privateKey` option was provided with an empty or undefined value, or the file path was incorrect leading to an empty buffer.fixEnsure `privateKey` is correctly populated, either directly with a key string or by reading a valid key file using `readFileSync`. Double-check the path to the private key file.
Warnings
- breaking Version 1.0.0 introduced significant breaking changes. Key classes like `Client` and `Server` became named exports instead of default exports or properties of the main module object. API method signatures, particularly for `Client.exec` and `Client.shell`, changed to pass the stream directly to the callback rather than returning it. `SFTPStream` and `Channel` are no longer directly exported.
- breaking The `hostVerifier()` client option will now be called every time a handshake occurs, including during rekeying. Ensure your host verification logic handles this repeated invocation.
- gotcha Node.js v10.16.0 or newer is required. For Ed25519 key support, Node.js v12.0.0 or newer is necessary.
- gotcha The `cpu-features` package is an optional dependency used to optimize cipher list generation. If it fails to install or build, `ssh2` will still function but might use a less optimal default cipher list.
Install
-
npm install ssh2 -
yarn add ssh2 -
pnpm add ssh2
Imports
- Client
const Client = require('ssh2');import { Client } from 'ssh2'; - Server
const Server = require('ssh2');import { Server } from 'ssh2'; - utils
import { utils } from 'ssh2';import * as utils from 'ssh2/lib/utils';
Quickstart
const { readFileSync } = require('fs');
const { Client } = require('ssh2');
const conn = new Client();
conn.on('ready', () => {
console.log('Client :: ready');
conn.exec('uptime', (err, stream) => {
if (err) throw err;
stream.on('close', (code, signal) => {
console.log(`Stream :: close :: code: ${code}, signal: ${signal}`);
conn.end();
}).on('data', (data) => {
console.log('STDOUT: ' + data);
}).stderr.on('data', (data) => {
console.error('STDERR: ' + data);
});
});
}).on('error', (err) => {
console.error('Client Error:', err.message);
}).connect({
host: process.env.SSH_HOST ?? '127.0.0.1',
port: parseInt(process.env.SSH_PORT ?? '22', 10),
username: process.env.SSH_USERNAME ?? 'user',
privateKey: readFileSync(process.env.SSH_PRIVATE_KEY_PATH ?? './id_rsa')
});