Client-Side Module Architecture

June 17, 2026 · View on GitHub

← Back to Architecture | ← Back to Documentation

Overview

WebSSH2 uses a companion module called webssh2_client which provides the browser-side terminal interface and WebSocket communication layer.

About webssh2_client

  • Repository: https://github.com/billchurch/webssh2_client
  • Purpose: Provides the browser-based terminal emulator and WebSocket client
  • Integration: Automatically included as a dependency in package.json
  • Version: The compatible version is managed through the package.json dependency
  • Technology: SolidJS 1.9.9, xterm.js 5.5.0, Vite 5.0.0

Features

The client module provides:

  • Terminal emulation using xterm.js
  • WebSocket communication with the WebSSH2 server
  • User interface for SSH connections
  • Terminal configuration and customization
  • Session management
  • File transfer capabilities
  • Responsive design for mobile and desktop
  • Keyboard shortcuts and accessibility features

Client-Server Communication

The server integrates with the client module by:

  1. Serving static files from /client/public
  2. Injecting configuration via an inert JSON <script type="application/json"> block (with legacy window.webssh2Config fallback)
  3. Managing WebSocket connections for terminal I/O
  4. Handling authentication and session management

Configuration Injection

The server passes runtime configuration to the client by injecting an inert JSON data block into the served HTML page. This is the primary mechanism and is fully CSP-compatible — it survives a strict script-src 'self' policy because the element is not an executable script:

<script type="application/json" id="webssh2-config">
{
  "socket": { "path": "/ssh/socket.io" },
  "ssh": { "host": "example.com", "port": 22, "username": "user" },
  "header": { "text": "WebSSH2", "background": "green" }
}
</script>

The client reads this block at startup via readInjectedConfig() by looking up document.getElementById('webssh2-config') and parsing its text content.

For backward compatibility, the gateway also injects the same configuration values into a conventional executable script block immediately after:

<script>window.webssh2Config = { /* same config */ };</script>

Deprecated: The window.webssh2Config inline-script method is deprecated and will be removed in a future major release. Integrators who currently set window.webssh2Config from their own inline scripts should migrate to reading the JSON data block (<script type="application/json" id="webssh2-config">). See billchurch/webssh2_client#125 for migration details.

WebSocket Protocol

The client and server communicate using Socket.IO events:

Client → Server Events

EventDescriptionPayload
authAuthentication request{ username, password, ... }
resizeTerminal resize{ cols, rows }
dataTerminal inputstring
execExecute command{ command, pty, ... }
disconnectClient disconnect-

Server → Client Events

EventDescriptionPayload
dataTerminal outputstring | ArrayBuffer (binary for shell, string for exec)
connectConnection established-
disconnectConnection lost{ reason }
errorError message{ message, type }
exec-dataExec output{ type, data }
exec-exitExec completion{ code, signal }

Architecture Components

1. Terminal Manager

Handles xterm.js instance and terminal rendering:

// Terminal initialization
const term = new Terminal({
  cursorBlink: true,
  scrollback: 10000,
  fontSize: 14,
  fontFamily: 'Menlo, Monaco, "Courier New", monospace',
  theme: {
    foreground: '#ffffff',
    background: '#000000'
  }
});

2. WebSocket Manager

Manages Socket.IO connection and message handling:

// Socket connection
const socket = io({
  path: config.socket.path,
  transports: ['websocket', 'polling']
});

// Event handling — shell data arrives as binary (ArrayBuffer),
// exec data arrives as string. xterm.js accepts both Uint8Array and string.
socket.on('data', (data) => {
  if (data instanceof ArrayBuffer) {
    term.write(new Uint8Array(data));
  } else {
    term.write(data);
  }
});

term.onData((data) => {
  socket.emit('data', data);
});

3. UI Components

Built with SolidJS for reactive updates:

  • Login Form: Credential input and validation
  • Terminal Container: Houses xterm.js instance
  • Menu Bar: Settings and actions
  • Status Bar: Connection and session info

4. State Management

Client state is managed using SolidJS stores:

const [state, setState] = createStore({
  connected: false,
  authenticated: false,
  settings: {
    fontSize: 14,
    theme: 'dark'
  }
});

Development

Building the Client

cd webssh2_client
npm install
npm run build

Development Mode

npm run dev

This starts a Vite dev server with hot module replacement on port 3000.

Linking for Development

Use npm link to connect client to server during development:

# In webssh2_client directory
npm link

# In webssh2 server directory
npm link webssh2_client

Customization

Theme Customization

Modify the terminal theme in client configuration:

{
  theme: {
    foreground: '#f8f8f2',
    background: '#282a36',
    cursor: '#f8f8f2',
    selection: '#44475a',
    black: '#000000',
    red: '#ff5555',
    green: '#50fa7b',
    yellow: '#f1fa8c',
    blue: '#6272a4',
    magenta: '#bd93f9',
    cyan: '#8be9fd',
    white: '#bfbfbf'
  }
}

Keyboard Shortcuts

Default keyboard shortcuts:

ShortcutAction
Ctrl+CCopy (when text selected)
Ctrl+VPaste
Ctrl+Shift+CCopy
Ctrl+Shift+VPaste
Ctrl++Increase font size
Ctrl+-Decrease font size
Ctrl+0Reset font size

Custom Addons

The client supports xterm.js addons:

import { FitAddon } from 'xterm-addon-fit';
import { WebLinksAddon } from 'xterm-addon-web-links';
import { SearchAddon } from 'xterm-addon-search';

const fitAddon = new FitAddon();
const webLinksAddon = new WebLinksAddon();
const searchAddon = new SearchAddon();

term.loadAddon(fitAddon);
term.loadAddon(webLinksAddon);
term.loadAddon(searchAddon);

Performance Optimization

Terminal Rendering

  • GPU acceleration enabled by default
  • Webgl renderer for improved performance
  • Lazy loading of terminal content
  • Virtual scrolling for large outputs

WebSocket Optimization

  • Binary frames for shell data — the server emits raw Buffer objects for shell output, which Socket.IO sends as binary WebSocket frames. This bypasses UTF-8 string conversion and JSON serialization on the server, and the client passes the resulting Uint8Array directly to xterm.js without decoding. String decoding is deferred to the session logger only when logging is active.
  • Compression enabled when supported
  • Reconnection logic with exponential backoff
  • Connection pooling for multiple sessions

Browser Compatibility

BrowserMinimum VersionNotes
Chrome88+Full support
Firefox85+Full support
Safari14+Full support
Edge88+Full support
Opera74+Full support

Mobile Support

The client includes responsive design for mobile devices:

  • Touch keyboard support
  • Gesture handling for scrolling
  • Viewport optimization
  • Mobile-friendly UI

Accessibility

Built-in accessibility features:

  • Screen reader support
  • Keyboard navigation
  • High contrast themes
  • Focus indicators
  • ARIA labels