Skip to main content

dsh-web-ui/packages/dsh-ssh

5.1kStars311Forks49Issues5Watchers

Adds SSH host management, command execution, web terminal, SFTP file transfer, local port forwarding, cluster concurrent execution, and 6 Agent tools to the dsh Web GUI. Host configurations are stored centrally on the local machine.

Evidence5/5methodologySourceInstallMaintenanceDSH versionSecurity scan
Machine-auditedInstall commandRepo verifieddsh-plugin topicLicenseREADMEAI wiki

ⓘ This plugin is a sub-package of the zhu1090093659/dsh-web-ui monorepo — stars and activity count the whole repository.

Language
TypeScript
License
Apache-2.0
Branch
dev
deepseek-harnessdshdsh-pluginweb-ui

Install

cmdweb profile
$ dsh plugin --profile web add @linxin666/dsh-ssh

Run the command above in your terminal to install this plugin via the dsh CLI. You can switch Profile in the top-right corner. New to dsh? Read the beginner tutorial

Install via your agent

Install the DeepSeek Harness plugin zhu1090093659/dsh-web-ui/packages/dsh-ssh for me: review the repository at https://github.com/zhu1090093659/dsh-web first, then run the install command and verify the plugin loads successfully.

Paste this instruction to the DSH Web GUI assistant — it will install and verify for you.

One-Line Pitch

Adds a complete set of SSH operations capabilities to the dsh Web GUI: centrally manage multiple remote hosts from the web end (CRUD, search, connection testing, one-click import from ~/.ssh/config), reuse persistent ssh2 connection pools in the host process to execute commands, run Web terminals, transfer SFTP files, open local port forwarding tunnels, and run the same command concurrently across multiple hosts; also provides 6 tools for Agents to share the same host configuration.

Core Features

  • Host CRUD, search, connection testing; support for environment/tag-based grouping with collapse and batch testing within groups; support for key/password authentication, passphrase-protected keys, ProxyJump multi-hop bastion hosts
  • One-click import from ~/.ssh/config: parse Host/HostName/User/Port/IdentityFile/ProxyJump fields, existing aliases are automatically skipped (wildcard mode / skip if HostName missing)
  • Persistent ssh2 connection pool: each host reuses one long-lived connection (no reconnection each time), auto-disconnect after 30 minutes idle, auto-reconnect on disconnect (max 3 times)
  • Command execution: single host exec with timeout (default 60s, can override), stdout/stderr separation, 2MB truncation protection per output
  • Web terminal (xterm.js + WebSocket PTY, backpressure auto-pause/resume), SFTP file transfer (upload via NDJSON progress stream, download returns binary stream), local port forwarding tunnel (only listens on 127.0.0.1 for accessing remote databases/internal services), cluster concurrent execution (default concurrency 8, can filter by alias/environment/tag)
  • Agent tools ssh_list / ssh_exec / ssh_upload / ssh_download / ssh_tunnel / ssh_cluster, GUI and Agent share the same host configuration

Technical Implementation

  • Languages: TypeScript (host half src/index.ts) + TypeScript + React 18 + CSS Modules (browser half src/client/)
  • Key Dependencies: ssh2 ^1.17.0 (persistent ssh2 connection pool + SFTP), @xterm/xterm ^6.0.0 + @xterm/addon-fit ^0.11.0 (browser terminal), ws ^8.18.0 (WebSocket PTY)
  • Architecture Pattern: Dual-half cordis bundle. src/index.ts is the host half (SshEngine connection pool + /api/dsh-ssh/* routes + 6 Agent tools + system prompt announcement), src/client/index.ts is the browser half (sidebar entry + host management/terminal/transfer/tunnel panels + locale registration). Bundle declaration in packages/dsh-ssh/cordis.patch.yml:10-12 (insert id ssh), browser side injects 3 official @deepseek-ai/dsh-client-* via dsh.client.inject (client-runtime / client-connection / client-ui-settings) + platform: web. Connection pool default parameters: 30 min idle, 15s handshake timeout, 15s keepalive interval, 2MB output limit, cluster concurrency 8, SFTP concurrency 8 (packages/dsh-ssh/src/engine/connection-pool.ts:30-38)
  • Entry Files: packages/dsh-ssh/src/index.ts (host apply, applyImpl), packages/dsh-ssh/src/client/index.ts (browser apply, apply(ctx)); bundle declaration packages/dsh-ssh/cordis.patch.yml:1-12, browser dependencies packages/dsh-ssh/package.json:32-40

Use Cases

  • Developers who need to manage multiple SSH servers (dev/test/prod mixed) daily: want to centrally browse hosts, execute commands, transfer files, open tunnels to access remote databases/internal services in the dsh Web GUI, saving the need to switch between multiple tools;
  • Developers who want Agents to directly execute remote operations tasks: pre-configure hosts in the GUI (manually or import from ~/.ssh/config), then Agents can use ssh_list / ssh_exec / ssh_upload / ssh_download / ssh_tunnel / ssh_cluster to call the same host configuration;
  • Users who already have ~/.ssh/config: use "Import ssh_config" to sync all existing SSH aliases to the plugin with one click, no need to re-enter host/port/user/identityFile.

Prerequisites & Compatibility

DependencyMin VersionDescription
DSH Host0.1.0-rc.8+ recommendedpackage.json not declared in dsh.engines; devDependencies locked to @deepseek-ai/dsh-* ^0.1.0-rc.8
Node.js^22.19.0 or >=24.0.0package.json engines.node
PlatformCross-platformhost half runs Node.js, client half runs in browser; ssh2 is pure JS library, no OS restrictions
Native ModulesNone (runtime)ssh2 doesn't need native bindings; upload/download uses ssh2's built-in SFTP
React^18.2.0peerDependency, injected by host at runtime
SSH ServerAny standard OpenSSHhost half acts as ssh2 client, doesn't depend on server version

Installation

dsh plugin --profile web add github:zhu1090093659/dsh-web-ui/packages/dsh-ssh

Configuration

This plugin provides 3 switches/inputs in the "SSH" area of the dsh settings panel:

ConfigTypeDescriptionDefault
enabledtoggleMaster switch for the plugin; when closed, /api/dsh-ssh/* routes are not registered, Agent tools are not registered, and Agent is not announced totrue
announceToAgenttoggleWhether to announce this plugin to the Agent in the system prompt (when closed, Agent won't see SSH tools)true
terminalFontFamilystringWeb terminal font (written to xterm fontFamily); leave empty to use CSS chain (--dsh-ssh-terminal-font → official --ds-font-family-code token → built-in monospace stack). To render powerline / Nerd Font icons, fill in Nerd Font stack (e.g., "SauceCodePro Nerd Font", monospace). Takes effect in real-time for already open terminals""

There are also several hardcoded constants in the engine that are not exposed to the GUI (packages/dsh-ssh/src/engine/connection-pool.ts:30-38): 30 min idle timeout, 15s handshake timeout, 15s keepalive interval, 2MB output limit, 60s default exec timeout, 8 default cluster concurrency, 8 SFTP concurrency; single upload request body limit 4 GiB (packages/dsh-ssh/src/routes.ts:27-28). To adjust, modify source code and rebuild.

FAQ

Q: The SSH entry doesn't appear in the sidebar after installation. What should I do?

A: Restart dsh web. Bundle activation is done once at host startup; refreshing the browser is not enough. After restart, the "SSH" entry appears in the sidebar; Agent prompts will also automatically include the plugin description (controlled by announceToAgent switch). See restart procedure at packages/dsh-ssh/README.zh.md:47, packages/dsh-ssh/README.md:47.

Q: How are passwords stored? Is it secure?

A: Passwords / passphrases are stored in plain text in ~/.dsh/dsh-ssh.json, with file permission 0600, directory 0700, atomic writes (tmp + rename). This is the same trust model as ssh-skill - since ~/.ssh/config often stores passwords in comments as well, this plugin doesn't add extra encryption (to avoid new risks from key management). File path and permissions at packages/dsh-ssh/src/store.ts:18-20,347-355.

Q: Can others in the LAN access my SSH console?

A: No. All /api/dsh-ssh/* routes only trust loopback connections from localhost (socket address must match IPv4 127/8 / ::1 / IPv4-mapped ::ffff:127/8, and require same-origin Host header + sec-fetch-site / Origin verification), LAN neighbors get direct 403. WebSocket terminal upgrades also go through the same loopback fence; local port forwarding tunnels only listen on 127.0.0.1, not exposed to LAN. See details at packages/dsh-ssh/src/routes.ts:101-111, packages/dsh-ssh/src/loopback.ts:44-62.

Q: Can the Agent execute commands on hosts I haven't configured?

A: No. The Agent can only operate on host aliases already configured in the GUI or imported from ~/.ssh/config. If an alias is not configured, tool calls like ssh_exec / ssh_upload will directly error out without making up hosts. This convention is also written in the system prompt "Restrictions" section (packages/dsh-ssh/src/index.ts:67) and packages/dsh-ssh/README.md:27.

Q: Will remote output be desensitized? Like for commands like env?

A: No. The stdout/stderr from exec / cluster is returned as-is (no secret replacement), commands like env may bring back remote environment variables with keys into the conversation history. This is the same semantics as ssh-skill - execution consumes real remote resources, Agent usage requires user confirmation beforehand. Semantics at packages/dsh-ssh/src/index.ts:67, packages/dsh-ssh/README.md:29.

Q: How do I download files? Can I download entire directories?

A: Both GUI and ssh_download tool can only download single files: first select a file in the remote file browser in the "Transfer" panel, then go through /api/dsh-ssh/download (returns binary stream, browser saves). Upload supports local directory recursion (walks and sends files one by one); batch directory download is not yet supported. Limitations at packages/dsh-ssh/README.md:69, packages/dsh-ssh/src/tools.ts:194-198.

Q: Can I use aliases from ~/.ssh/config for bastion hosts?

A: No. Every hop in a ProxyJump chain must be a host alias already configured in this plugin (cannot cross-plugin reference aliases from ~/.ssh/config); when importing, if a hop is not in the plugin's host table, it will error and skip during creation. Limitation at packages/dsh-ssh/README.md:71, packages/dsh-ssh/src/protocol.ts:30-32.

Q: Will auto-replay replay my commands?

A: Yes. exec will auto-reconnect on disconnect (keepaliveCountMax=3), and after connection reset the command will be resent; non-idempotent commands (like rm, append-write files) will have side effects, please use idempotent commands or confirm beforehand. See details at packages/dsh-ssh/src/engine/connection-pool.ts:72, packages/dsh-ssh/README.md:70.

Getting Started Difficulty

Beginner — install with one command, restart dsh web and the SSH entry appears; hosts can be manually filled in the GUI or imported from ~/.ssh/config with one click, no config files or command line needed. However, since it involves remote hosts, keys, and bastion hosts, it is recommended to try one or two exec commands / tunnels first before batch usage.

Known Issues & Limitations

  • Upload remote target path must be absolute path, relative paths are rejected (packages/dsh-ssh/README.md:68, packages/dsh-ssh/src/tools.ts:158-162)
  • Download only supports single files; upload supports local directory recursion (walks and sends files one by one), directory batch download not implemented (packages/dsh-ssh/README.md:69)
  • exec auto-reconnect on disconnect (keepaliveCountMax=3) will resend the same command, non-idempotent commands need to be aware of side effects (packages/dsh-ssh/src/engine/connection-pool.ts:72, packages/dsh-ssh/README.md:70)
  • Every hop in a ProxyJump chain must be a host alias configured in this plugin, cannot cross-plugin reference ~/.ssh/config aliases (packages/dsh-ssh/README.md:71)
  • Resume (断点续传) not yet implemented; single upload request body limit 4 GiB (packages/dsh-ssh/src/routes.ts:27-28)
  • Agent tool transfer paths are local paths on the host machine (same semantics as ssh-skill) — ssh_upload / ssh_download directly read/write any path on the machine with host process permissions, not through bash sandbox, please note this permission surface (packages/dsh-ssh/README.md:28, packages/dsh-ssh/src/index.ts:67)
  • Host configuration ~/.dsh/dsh-ssh.json stores passwords and passphrases in plain text, file 0600, directory 0700, no encryption (packages/dsh-ssh/src/store.ts:347-355, packages/dsh-ssh/README.md:24)
  • exec / cluster remote output returned as-is (not desensitized), commands like env may bring back remote environment keys (packages/dsh-ssh/src/index.ts:67, packages/dsh-ssh/README.md:29)
  • Local port forwarding tunnels only listen on 127.0.0.1, external network cannot access; this is fence design not a configurable option (packages/dsh-ssh/src/loopback.ts:44-62)
  • Host aliases only allow letters, numbers, dots ., hyphens -, underscores _ (first character cannot be separator); non-conforming aliases will error and skip during creation/import (packages/dsh-ssh/src/store.ts:62-68,296-303)
  • When config file is corrupted, it will be renamed to .corrupt-<timestamp> backup, then start with empty table, not silently overwritten (packages/dsh-ssh/src/store.ts:334-342)

Read the usage guide →

Install steps, key points, FAQ and compatibility for this plugin — auto-derived from indexed fields.

Listing badge

Listed on deepseek-plugin.org
[![Listed on deepseek-plugin.org](https://img.shields.io/badge/listed_on-deepseek--plugin.org-007EC6)](https://deepseek-plugin.org/plugins/zhu1090093659/dsh-web-ui/packages/dsh-ssh)

Paste this markdown into your GitHub README to link back to this listing. The badge only states the listing — not a security endorsement.

← Back to plugin directory