Skip to content

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

TunnelCapsule Swift Platform License Release

中文 | English image

中文

TunnelCapsule 是一个面向日常使用场景的 macOS 菜单栏 SSH 本地端口转发工具。

它不是单纯把 ssh -L 命令做成一个壳,而是把多隧道管理、菜单栏状态、Keychain 凭据保存、IPv4/IPv6 地址处理、自动重连、日志排障、代理开关和流量统计这些真实使用时会遇到的问题,整理成一个可以长期放在菜单栏里的原生应用。

你可以把它理解为:

  • 底层负责 SSH 连接、端口转发和连接生命周期管理
  • 上层负责规则管理、菜单栏交互、配置持久化、日志与错误翻译
  • 最终提供一个更适合 macOS 日常驻留使用的隧道管理工具

项目核心目标:

  • 提供一个真正可长期使用的菜单栏 SSH 隧道工具,而不是一次性的命令行包装
  • 优先处理 IPv4 / IPv6、本地绑定地址、密钥认证、自动重连这些稳定性问题
  • 用原生 macOS UI 降低多条隧道管理和日常切换的使用成本
  • 给开发和排障场景提供足够详细的日志与错误信息

功能特性

  • 纯菜单栏应用,默认无 Dock 图标
  • 内置中文 / English 双语界面
  • 支持同时管理多条 SSH 本地端口转发规则
  • 支持密码认证和私钥认证,敏感信息写入 Keychain
  • 支持 IPv4 / IPv6 SSH 地址与本地绑定地址
  • 支持常用本地绑定地址快速选择,也支持自定义输入
  • SSH 服务器 与 远程目标主机 保持一致,只需要切换远程端口
  • 支持每条规则单独启用 / 关闭本地代理
  • 支持自动重连、KeepAlive、连接超时配置
  • 支持累计流量统计和手动清零
  • 支持配置导入 / 导出
  • 隧道编辑窗口支持 Test Connection
  • 内置详细错误翻译,便于识别端口错误、认证失败、连接被拒绝等问题
  • 配置窗口内置日志面板,便于开发者调试
  • 状态栏图标具备连接状态动效与颜色区分
  • 对部分原生 SSH 协商失败的旧服务端自动降级到系统 /usr/bin/ssh

快速开始

1) 环境要求

  • macOS 14+
  • Xcode Command Line Tools
  • Swift 5.9+

安装命令行工具:

xcode-select --install

2) 拉取并本地运行

git clone git@github.com:liigoo/ssh-tunnel-bar.git
cd ssh-tunnel-bar
swift build
make run

3) 常用命令

# 调试构建
swift build
# 或
make build

# 运行
make run

# 构建 Release .app
make release

# 安装到 /Applications
make install

# 生成 DMG
make dmg

# 清理构建产物
make clean

4) 签名与公证

如果你要分发 .app,可以使用 Makefile 中的签名和公证目标:

make sign IDENTITY='Developer ID Application: Your Name (TEAMID)'

make notarize \
  IDENTITY='Developer ID Application: Your Name (TEAMID)' \
  APPLE_ID='you@example.com' \
  TEAM_ID='TEAMID' \
  APP_PASSWORD='xxxx-xxxx-xxxx-xxxx'

使用说明

  1. 启动应用后,从菜单栏图标打开主菜单。
  2. 选择 Add New Tunnel... 或编辑已有隧道。
  3. 填写 SSH 服务器、用户名、认证方式和本地监听信息。
  4. 配置远程目标端口。
  5. 如有需要,先点击 Test Connection 验证 SSH 连接。
  6. 保存后,可直接从菜单栏连接、断开、编辑、复制或删除隧道。
  7. 在配置窗口左下角切到 日志,可以查看滚动日志与底层错误详情。

配置说明

配置文件默认保存在:

~/Library/Application Support/TunnelCapsule/tunnels.json

日志文件默认保存在:

~/Library/Application Support/TunnelCapsule/Logs/tunnelcapsule.log

敏感信息存储方式:

  • SSH 密码保存在登录 Keychain
  • 私钥口令保存在登录 Keychain
  • 其他隧道参数以 JSON 持久化保存

IPv6 与连接说明

  • SSH 服务器地址支持 example.com、192.168.1.10、2001:db8::1、[2001:db8::1]
  • 本地绑定地址支持 127.0.0.1、0.0.0.0、::1、:: 以及自定义 IPv4 / IPv6 地址
  • 远程目标主机会自动跟随 SSH 服务器地址,只允许修改远程端口
  • 如果某些旧 SSH 服务端和原生 Swift SSH 栈协商失败,应用会自动尝试系统 ssh 降级路径
  • 文本输入框支持标准 macOS 编辑快捷键,包括 Cmd+V

项目架构

Sources/TunnelCapsule/
├── App/
│   ├── AppDelegate.swift
│   └── StatusBarController.swift
├── Config/
│   ├── AppLog.swift
│   ├── AppPreferences.swift
│   ├── ConfigStore.swift
│   ├── ErrorTranslator.swift
│   └── KeychainHelper.swift
├── Tunnel/
│   ├── ExternalSSHTunnel.swift
│   ├── LocalPortForwarder.swift
│   ├── SSHConnection.swift
│   ├── TunnelConfiguration.swift
│   ├── TunnelManager.swift
│   └── TunnelState.swift
└── Views/
    ├── PreferencesView.swift
    └── TunnelConfigWindowController.swift

目录职责:

  • App/:应用入口、菜单栏图标和菜单交互
  • Config/:配置读写、日志、Keychain、错误翻译、全局偏好
  • Tunnel/:SSH 连接、端口转发、状态管理、系统 ssh 降级兼容
  • Views/:隧道编辑窗口、日志面板、偏好设置界面
  • Resources/:图标、Info.plist、本地化文案、隐私声明

使用到的开源项目

  • Citadel - Swift SSH 客户端库
  • SwiftNIO - 通过 Citadel 间接使用的网络基础设施
  • macOS Keychain / UserNotifications / SwiftUI / AppKit - 系统能力支持

更新日志

v1.2.4 (2026-05-11)

  • 修复:点击日志按钮后界面卡死的问题。根因是日志视图每秒在主线程同步读取整个日志文件(2MB+),改为从文件尾部反向读取最后 500 行,UI 恢复流畅

v1.2.3 (2026-05-11)

  • 修复:浏览器访问本地代理端口时崩溃的问题(NIOSSH SSHChildChannel.handleOutboundChannelWindowAdjust 中 EXC_BAD_INSTRUCTION)。根因是 TCP 连接断开后 SSHToTCPForwarder 继续向已关闭的 channel 写入数据,导致 NIOSSH 内部窗口管理状态被破坏

v1.2.2

  • 添加 Apache 2.0 许可证
  • 重写双语 README 结构

v1.2.1

  • 简化 App 图标设计
  • 优化状态栏图标形态

v1.2.0

  • 添加自定义 App 和状态栏图标
  • 修复隧道编辑器中粘贴快捷键问题
  • 添加对 Dropbear 服务器的系统 SSH 降级支持
  • 完善隧道诊断与编辑器功能

致谢

感谢 Swift、SwiftNIO、Citadel 以及 macOS 原生框架生态提供的基础能力。

这个项目的重点不是”再包一层 SSH 命令”,而是把桌面端长期使用时真正需要的隧道管理体验打磨出来,包括:规则管理、状态反馈、IPv6 处理、错误翻译、日志排障和菜单栏常驻交互。

许可证

本项目使用 Apache License 2.0。


English

TunnelCapsule is a macOS menu-bar SSH local port forwarding utility built for real daily use.

It is not just a thin wrapper around ssh -L. Instead, it turns multi-tunnel management, menu-bar controls, Keychain credential storage, IPv4/IPv6 handling, auto reconnect, diagnostics, local proxy toggles, and traffic counters into a native app that can stay in the macOS menu bar all day.

In practice:

  • the lower layer handles SSH connections, local port forwarding, and connection lifecycle
  • the upper layer handles tunnel configuration, menu-bar interaction, persistence, logs, and human-readable errors
  • the result is a macOS-native tunnel manager suited for long-running everyday workflows

Core goals:

  • provide a menu-bar SSH tunnel tool that is practical for long-term use, not a one-shot shell wrapper
  • prioritize stability around IPv4 / IPv6, bind addresses, key authentication, and auto reconnect
  • reduce the operational overhead of managing and switching between multiple tunnels with native macOS UI
  • offer detailed logs and translated error messages for troubleshooting and development use

Features

  • menu-bar-only app with no Dock icon
  • built-in Chinese / English UI
  • multiple SSH local port-forwarding tunnel profiles
  • password and private-key authentication with Keychain storage
  • IPv4 / IPv6 support for SSH endpoints and local bind addresses
  • quick presets for common bind addresses plus custom input
  • SSH Server and Remote Target Host stay aligned, so only the remote target port is edited
  • per-tunnel local proxy enable / disable
  • auto reconnect, keepalive, and connection timeout settings
  • cumulative traffic counters with manual reset
  • configuration import / export
  • built-in Test Connection in the tunnel editor
  • detailed translated errors for auth failures, wrong ports, refused connections, DNS failures, and similar issues
  • integrated log panel inside the configuration window for debugging
  • animated status bar icon with state-specific colors
  • automatic fallback to system /usr/bin/ssh for certain legacy servers when native SSH negotiation fails

Quick Start

1) Requirements

  • macOS 14+
  • Xcode Command Line Tools
  • Swift 5.9+

Install command line tools:

xcode-select --install

2) Clone and run locally

git clone git@github.com:liigoo/ssh-tunnel-bar.git
cd ssh-tunnel-bar
swift build
make run

3) Common commands

# debug build
swift build
# or
make build

# run
make run

# build release .app
make release

# install to /Applications
make install

# build DMG
make dmg

# clean build outputs
make clean

4) Signing and notarization

If you want to distribute the .app, use the Makefile targets for signing and notarization:

make sign IDENTITY='Developer ID Application: Your Name (TEAMID)'

make notarize \
  IDENTITY='Developer ID Application: Your Name (TEAMID)' \
  APPLE_ID='you@example.com' \
  TEAM_ID='TEAMID' \
  APP_PASSWORD='xxxx-xxxx-xxxx-xxxx'

Usage

  1. Launch the app and open the main menu from the menu bar icon.
  2. Choose Add New Tunnel... or edit an existing tunnel.
  3. Fill in the SSH server, username, authentication method, and local listen settings.
  4. Configure the remote target port.
  5. Use Test Connection first if you want to validate SSH access.
  6. Save the tunnel, then connect, disconnect, edit, duplicate, or delete it from the menu bar.
  7. Switch to Logs in the lower-left area of the configuration window to inspect runtime logs and low-level errors.

Configuration

Default tunnel config location:

~/Library/Application Support/TunnelCapsule/tunnels.json

Default log file location:

~/Library/Application Support/TunnelCapsule/Logs/tunnelcapsule.log

Sensitive data storage:

  • SSH passwords are stored in the login Keychain
  • private-key passphrases are stored in the login Keychain
  • non-sensitive tunnel settings are persisted as JSON

IPv6 And Connectivity Notes

  • SSH server fields accept example.com, 192.168.1.10, 2001:db8::1, and [2001:db8::1]
  • local bind addresses support 127.0.0.1, 0.0.0.0, ::1, ::, and custom IPv4 / IPv6 input
  • the remote target host automatically follows the SSH server host, so only the remote port is configurable
  • if a legacy SSH server fails to negotiate with the native Swift SSH stack, the app can fall back to the system ssh path automatically
  • text inputs support standard macOS editing shortcuts, including Cmd+V

Project Structure

Sources/TunnelCapsule/
├── App/
│   ├── AppDelegate.swift
│   └── StatusBarController.swift
├── Config/
│   ├── AppLog.swift
│   ├── AppPreferences.swift
│   ├── ConfigStore.swift
│   ├── ErrorTranslator.swift
│   └── KeychainHelper.swift
├── Tunnel/
│   ├── ExternalSSHTunnel.swift
│   ├── LocalPortForwarder.swift
│   ├── SSHConnection.swift
│   ├── TunnelConfiguration.swift
│   ├── TunnelManager.swift
│   └── TunnelState.swift
└── Views/
    ├── PreferencesView.swift
    └── TunnelConfigWindowController.swift

Directory responsibilities:

  • App/: app entry point, menu-bar icon, and menu interaction
  • Config/: persistence, logs, Keychain, translated errors, and app preferences
  • Tunnel/: SSH connection, port forwarding, state coordination, and system ssh fallback
  • Views/: tunnel editor, log panel, and preferences UI
  • Resources/: icons, Info.plist, localizations, and privacy declaration

Open Source Dependencies

  • Citadel - Swift SSH client library
  • SwiftNIO - networking foundation used indirectly through Citadel
  • macOS Keychain / UserNotifications / SwiftUI / AppKit - platform capabilities used by the app

Changelog

v1.2.4 (2026-05-11)

  • Fix: UI freeze when clicking the Logs button. Root cause: the log view read the entire log file (2MB+) synchronously on the main thread every second. Now reads only the last 500 lines via backward file seeking, keeping the UI responsive.

v1.2.3 (2026-05-11)

  • Fix: crash when accessing local proxy port from a browser (EXC_BAD_INSTRUCTION in NIOSSH SSHChildChannel.handleOutboundChannelWindowAdjust). Root cause: SSHToTCPForwarder kept writing to a closed TCP channel after the browser disconnected, corrupting NIOSSH's internal window management state.

v1.2.2

  • Add Apache 2.0 license
  • Rewrite bilingual README structure

v1.2.1

  • Simplify app icon artwork
  • Refine status bar icon shapes

v1.2.0

  • Add custom app and status bar icons
  • Fix paste shortcuts in tunnel editor
  • Add system SSH fallback for Dropbear servers
  • Improve tunnel diagnostics and editor

Acknowledgements

Thanks to Swift, SwiftNIO, Citadel, and the macOS native framework ecosystem for the building blocks behind this project.

The point of this app is not to merely wrap an SSH command. The real value is to make desktop tunnel management usable over time: profile management, status feedback, IPv6 handling, translated errors, diagnostics, and menu-bar-native interaction.

License

Released under the Apache License 2.0.

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages