Contents

SSH Tunnel:用图形界面管理多条 SSH 隧道

一、前言

SSH 端口转发的命令不算难,难的是日常维护。隧道一多,命令记不住、终端不敢关、断了要手动重连、哪个还活着全靠记忆。这个工具就是来收拾这些事的。

写一条转发命令是几秒钟的事:

1
ssh -N -L 3306:db.internal:3306 -i ~/.ssh/id_rsa user@jump.example.com

但用起来就不是几秒钟的事了。手上同时开着五六条隧道的时候,问题会一个接一个冒出来——参数记不住要翻笔记,每条隧道都得占一个终端窗口,终端一关隧道就没了,网络抖一下断线还得手动敲一遍重连,至于哪条还活着、哪条已经挂了,基本靠猜。

我把自己这套流程做成了一个桌面工具:SSH Tunnel,基于 Wails v2 + Vue 3,用图形界面管理多条 SSH 隧道。

二、解决什么问题

针对上面那几个痛点,工具的做法是这样的。

命令不用记了。 隧道保存成配置,点一下启停。已经写好的 ssh -L ... 命令可以直接粘贴进来,工具会解析成配置项,不用重新填一遍表单。

终端可以关了。 隧道跑在应用自己的进程里,配合系统托盘常驻,关掉主窗口隧道照样跑。macOS 上还能把 Dock 图标藏起来,完全当菜单栏应用用。

断线不用手动重连。 内置自动重连,最小退避、最大退避、心跳间隔都能配。

状态看得见。 每条隧道的状态实时同步,托盘图标会随整体状态变色:有隧道在跑是蓝色,全部停止自动变灰。

三、主要功能

1. 多隧道管理

每条隧道独立启停,状态实时同步,支持一键全部启用 / 全部关闭。

2. 三种转发模式

-L 本地转发、-R 远程转发、-D 动态转发都支持。

动态转发这里做了一点额外的事:同一个监听端口上同时兼容 SOCKS5 和 HTTP 代理,按首字节自动识别协议。HTTP 模式下支持 CONNECT 隧道(可以走 HTTPS 或任意 TCP),也支持普通请求转发,并复用 keep-alive 连接。

3. 代理中转

到 SSH 服务器的这一段连接,可以再经由 HTTP / HTTPS / SOCKS5 代理建立,支持代理认证。适用于跳板机本身也要走代理才能访问的场景,连接测试同样走这条链路。

4. 自动重连

断线后自动重试,退避策略可配置。默认最小退避 1000 ms、最大退避 30000 ms,心跳间隔 30 秒(填 0 关闭)。

5. 系统托盘

托盘菜单里可以直接启停隧道、全部启用、全部关闭、显示窗口、退出程序。每条隧道用符号标识状态:

符号 含义
● 运行中
◐ 连接中
⚠ 错误
○ 已停止

6. 导入与导出

三种方式,覆盖迁移和备份的场景:

  • 从 SSH 命令导入 —— 粘贴 ssh -L 8080:localhost:80 -i ~/.ssh/id_rsa user@host,自动解析成隧道配置
  • 导出为 SSH 命令 —— 任意隧道一键导出成等效的 ssh 命令行,方便直接粘到终端里用
  • JSON 导入导出 —— 支持合并和覆盖两种模式,换机器或者备份配置都用得上

四、界面预览

1. 隧道列表

主界面列出所有隧道配置,包含运行状态、转发规则和错误信息。

/images/post/2026101002/tunnel-list.png

2. 新建与编辑隧道

配置 SSH 连接信息、认证方式(密钥或密码)、端口转发规则和高级选项。保存前可以先用「测试连接」验证 SSH 连通性,这一步只测连接,不会真的启动转发。

/images/post/2026101002/tunnel-edit.png

3. 导入与导出

三个页签对应三种方式:从 SSH 命令导入、JSON 导入导出、导出 SSH 命令。

/images/post/2026101002/import-export.png

4. 设置

开机自启、窗口行为、Dock 显示这些全局配置都在这里。配置文件路径也会显示出来,可以直接打开所在目录。

/images/post/2026101002/settings.png

5. 系统托盘

托盘菜单里直接操作隧道,图标颜色反映整体运行状态。

/images/post/2026101002/tray-menu.png

五、下载与安装

1. 直接下载

到 Releases 页面按平台取对应文件:

平台 架构 文件
macOS Apple Silicon ssh-tunnel-v0.0.1-darwin-arm64.zip
macOS Intel ssh-tunnel-v0.0.1-darwin-amd64.zip
macOS 通用(Intel + ARM) ssh-tunnel-v0.0.1-darwin-universal.zip
Windows x64 ssh-tunnel-v0.0.1-windows-amd64.exe(含安装包)
Windows x86 ssh-tunnel-v0.0.1-windows-386.exe(免安装)
Linux x64 ssh-tunnel-v0.0.1-linux-amd64

Windows x64 有 NSIS 安装包,其余是免安装的单文件。Linux 只提供 x64,因为 Wails v2 不支持 Linux 386。

2. 从源码构建

需要 Go 1.21+、Node.js 16+ 和 Wails CLI v2:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# 安装 Wails CLI
go install github.com/wailsapp/wails/v2/cmd/wails@latest

# 克隆并安装前端依赖
git clone https://github.com/midaug/ssh-tunnel.git
cd ssh-tunnel
cd frontend && npm install && cd ..

# 开发模式(热重载,可在 http://localhost:34115 调试)
wails dev

# 构建当前平台
wails build -clean

# 交叉编译
wails build -platform darwin/universal -clean
wails build -platform windows/amd64 -clean

构建产物输出到 build/bin/。

六、技术实现

层 技术
框架 Wails v2(Go + WebView)
后端 Go,golang.org/x/crypto/ssh,golang.org/x/net/proxy
前端 Vue 3 + TypeScript + Pinia + Vue Router
系统托盘 fyne.io/systray
macOS Dock 控制 cgo 调用 NSApp.setActivationPolicy
开机自启 macOS LaunchAgent / Windows 注册表 / Linux .desktop

选 Wails 而不是 Electron,主要是看中产物体积和内存占用——它用系统自带的 WebView 渲染前端,不用打包一整个 Chromium。构建出来的 macOS ARM 版本压缩后不到 4 MB。

隧道运行时分成三块:manager.go 管多隧道的启停和状态汇总,tunnel.go 管单条隧道的生命周期和自动重连,三种转发模式各自实现在 forward_local.go / forward_remote.go / forward_dynamic.go 里。proxy.go 负责经 HTTP/HTTPS/SOCKS5 代理拨号到 SSH 服务器,隧道拨号和连接测试共用这条路径。

七、平台支持与系统要求

平台 最低版本 备注
macOS 10.13 High Sierra 支持菜单栏模式、隐藏 Dock 图标
Windows 10 / Server 2016 需要 WebView2 Runtime(Win10/11 通常已内置)
Linux — 仅 x64

Linux 没有 386 版本,Windows 7 也不支持——Wails v2 依赖 WebView2(Edge 内核),而且 Go 1.21+ 本身已经移除了 Win7 支持。

配置文件按平台放在用户配置目录下:

平台 路径
macOS ~/Library/Application Support/ssh-tunnel/config.json
Windows %AppData%\ssh-tunnel\config.json
Linux ~/.config/ssh-tunnel/config.json

八、小结

这个工具解决的是我自己的实际问题:隧道多了之后,命令行和终端窗口的方式确实不太够用。如果你也经常要同时维持几条 SSH 隧道,可以试试。

项目还在早期(v0.0.1),有问题或者想要的功能,欢迎到 GitHub 上提 issue。

顺带一提,SSH 端口转发本身的用法,之前写过一篇 SSH Tunnel 端口转发详解,三种转发模式的参数和场景在那里讲得比较细,可以对照着看。