A WebAssembly port of libssh2 that enables SSH client functionality in JavaScript environments, including browsers and Node.js.
libssh2.js provides a complete SSH client implementation compiled to WebAssembly using Emscripten. It supports:
- SSH Connections: Establish SSH connections to remote servers
- Authentication: Password and public key authentication
- Terminal Sessions: Interactive shell sessions with PTY support
- Custom Transport: WebSocket bridge support for browser environments
- Cross-Platform: Works in browsers, Node.js, and other JavaScript runtimes
- 🔐 SSH Protocol Support: Full SSH2 protocol implementation
- 🌐 WebAssembly: Native performance in JavaScript environments
- 🔌 Custom Transport: WebSocket bridge for browser compatibility
- 🖥️ Terminal Support: Interactive shell sessions with PTY
- 🔑 Multiple Auth Methods: Password and public key authentication
- 📱 Browser Compatible: Works in modern browsers via WebSocket
- 🚀 Node.js Ready: Native performance in Node.js environments
- 📝 TypeScript Support: Full type definitions included
- Docker: For building the WebAssembly module
- Node.js: Version 22.14.0 or later
- Modern Browser: For browser-based usage (Chrome, Firefox, Safari, Edge)
The project includes a Docker-based build system that compiles libssh2 and OpenSSL to WebAssembly.
# Build the WebAssembly module
docker build -t libssh2-wasm .# Extract the built files
docker create --name temp-container libssh2-wasm
docker cp temp-container:/workspace/libssh2.js ./
docker cp temp-container:/workspace/libssh2.wasm ./
docker rm temp-containerThe build process:
- Sets up Ubuntu 22.04 with Node.js 22.14.0
- Installs Emscripten SDK
- Compiles OpenSSL 1.1.1w for WebAssembly
- Compiles libssh2 with OpenSSL backend
- Compiles the custom bindings to WebAssembly
This package includes full TypeScript support with comprehensive type definitions. The types are automatically included when you install the package and will be resolved by TypeScript automatically.
The package includes a types field in package.json that points to index.d.ts, ensuring TypeScript automatically finds the type definitions:
{
"types": "index.d.ts"
}importSSH2Modulefrom"@verdigris/libssh2.js";asyncfunctionsshExample(){// Initialize the moduleconstSSH2=awaitSSH2Module();// Initialize libssh2SSH2.ccall("ssh2_init","number",[],[]);// Create sessionconstsession=SSH2.ccall("ssh2_session_init_custom","number",[],[]);// Set custom transport callbacksSSH2.customSend=(socket,buffer,length)=>{// Implement your transport logic here// For WebSocket: send data via WebSocketreturnlength;};SSH2.customRecv=(socket,buffer,length)=>{// Implement your transport logic here// For WebSocket: receive data from WebSocketreturnreceivedLength;};// Perform handshakeconsthandshakeResult=SSH2.ccall("ssh2_session_handshake_custom","number",["number"],[session]);// AuthenticateconstauthResult=SSH2.ccall("ssh2_userauth_password_custom","number",["number","string","string"],[session,"username","password"]);}importSSH2Modulefrom"./libssh2.js";// Initialize the moduleconstSSH2=awaitSSH2Module();// Initialize libssh2SSH2.ccall("ssh2_init","number",[],[]);// Create sessionconstsession=SSH2.ccall("ssh2_session_init_custom","number",[],[]);// Set custom transport callbacksSSH2.customSend=(socket,buffer,length)=>{// Implement your transport logic here// For WebSocket: send data via WebSocketreturnlength;};SSH2.customRecv=(socket,buffer,length)=>{// Implement your transport logic here// For WebSocket: receive data from WebSocketreturnreceivedLength;};// Perform handshakeconsthandshakeResult=SSH2.ccall("ssh2_session_handshake_custom","number",["number"],[session]);// AuthenticateconstauthResult=SSH2.ccall("ssh2_userauth_password_custom","number",["number","string","string"],[session,"username","password"]);// Open channelconstchannel=SSH2.ccall("ssh2_channel_open_session_custom","number",["number"],[session]);// Request PTYSSH2.ccall("ssh2_channel_request_pty_custom","number",["number","string"],[channel,"xterm"]);// Set PTY sizeSSH2.ccall("ssh2_channel_request_pty_size","number",["number","number","number"],[channel,80,24]);// Start shellSSH2.ccall("ssh2_channel_shell_custom","number",["number"],[channel]);// Read from channelconstbuffer=SSH2._malloc(1024);constbytesRead=SSH2.ccall("ssh2_channel_read_custom","number",["number","number","number"],[channel,buffer,1024]);// Write to channelSSH2.ccall("ssh2_channel_write_custom","number",["number","string","number"],[channel,"ls -la\n",8]);// Set up WebSocket connectionconstws=newWebSocket("ws://your-ssh-proxy-server");// Custom transport implementationSSH2.customSend=(socket,buffer,length)=>{constdata=newUint8Array(SSH2.HEAPU8.buffer,buffer,length);ws.send(data);returnlength;};SSH2.customRecv=(socket,buffer,length)=>{// Handle incoming WebSocket data// Copy to the provided bufferreturnreceivedLength;};| Function | Description |
|---|---|
ssh2_init() | Initialize libssh2 library |
ssh2_exit() | Cleanup libssh2 library |
ssh2_version() | Get libssh2 version string |
| Function | Description |
|---|---|
ssh2_session_init_custom() | Create new SSH session with custom transport |
ssh2_session_handshake_custom() | Perform SSH handshake |
ssh2_session_set_blocking() | Set session blocking mode |
ssh2_session_free() | Free session resources |
| Function | Description |
|---|---|
ssh2_userauth_password_custom() | Authenticate with username/password |
ssh2_userauth_publickey_fromfile() | Authenticate with public key |
| Function | Description |
|---|---|
ssh2_channel_open_session_custom() | Open new session channel |
ssh2_channel_request_pty_custom() | Request PTY allocation |
ssh2_channel_shell_custom() | Start interactive shell |
ssh2_channel_read_custom() | Read data from channel |
ssh2_channel_write_custom() | Write data to channel |
ssh2_channel_close() | Close channel |
ssh2_channel_free() | Free channel resources |
If you encounter errors like:
There are types at '.../index.d.ts', but this result could not be resolved when respecting package.json "exports"
Solution: Make sure you're using a recent version of TypeScript (4.7+) and that your tsconfig.json has modern module resolution:
{
"compilerOptions": {
"moduleResolution": "node",
"module": "ESNext",
"target": "ES2020"
}
}The package uses ES modules. If you're using CommonJS, you may need to use dynamic imports:
// ES Module import (recommended)importSSH2Modulefrom"@verdigris/libssh2.js";// CommonJS dynamic importconstSSH2Module=awaitimport("@verdigris/libssh2.js");The project consists of three main components:
- ssh2_bindings.c: C bindings that expose libssh2 functionality to JavaScript
- Dockerfile: Build environment for compiling to WebAssembly
- Generated Files:
libssh2.jsandlibssh2.wasm(built output)
The bindings implement a custom transport layer that allows:
- WebSocket bridging for browser environments
- Custom I/O handling for different network protocols
- Integration with existing JavaScript networking code
- Chrome: 67+ (WebAssembly support)
- Firefox: 52+ (WebAssembly support)
- Safari: 11+ (WebAssembly support)
- Edge: 79+ (WebAssembly support)
Note: The package is specifically built for browser environments with -s ENVIRONMENT=web to ensure compatibility with bundlers like Webpack, Vite, and Next.js.
- Node.js: 22.14.0+ (for building)
- Runtime: Any Node.js version with WebAssembly support
- Transport Security: Ensure your WebSocket or transport layer is secure (WSS, etc.)
- Key Management: Store private keys securely
- Authentication: Use strong passwords and key-based authentication when possible
- Network Security: SSH connections should be over secure networks
libssh2.js/
├── ssh2_bindings.c # C bindings for libssh2
├── Dockerfile # Build environment
├── README.md # This file
└── .circleci/ # CI configuration
- Clone the repository
- Ensure Docker is running
- Run the build command
- Extract the generated files
The ssh2_bindings.c file can be modified to:
- Add new SSH functionality
- Customize transport behavior
- Expose additional libssh2 features
- Fork the repository
- Create a feature branch
- Make your changes
- Test thoroughly
- Submit a pull request
This project is based on libssh2, which is licensed under the BSD 3-Clause License.
- libssh2 - The original C library
- Emscripten - WebAssembly compilation toolchain
- OpenSSL - Cryptographic library
For issues and questions:
- Check the libssh2 documentation
- Review the Emscripten WebAssembly guide
- Open an issue in this repository
Note: This is a WebAssembly port of libssh2. For production use, ensure your transport layer (WebSocket, etc.) provides appropriate security measures.