# klink `klink` 是一个使用 Go 编写的终端 TUI SSH 节点和端口转发管理器。它保存结构化节点配置, 使用系统 OpenSSH 建立连接,并提供本地、远程和动态 SOCKS5 转发。 ## 当前能力 - 节点新增、编辑、复制、删除、搜索和标签 - IPv6 优先,网络不可达时回退 IPv4 - SSH Agent、私钥文件、系统凭据存储中的密码、ProxyJump 和 HostKey 策略 - Host key 指纹扫描、确认后写入或移除统一的 known_hosts - 可恢复的 tmux SSH 会话与 Tunnel 启动状态自愈 - 本地转发 `-L`、远程转发 `-R`、动态转发 `-D` - 隧道专用会话 `-N`、后台 worker、状态恢复和持续自动重连 - ktui 节点幂等同步、klink JSON 和 OpenSSH `ssh_config` 导入 - 版本化 JSON 导出 - TUI 宽屏双栏和窄屏单栏布局 - Nodes、Tunnels、SFTP、Settings 和 About 使用一致的单宽语义图标,无需 Nerd Font - 可持久化的主题、SSH、地址优先级和隧道默认设置 - TUI 配置导入、导出、重载和本机 SSH 环境诊断 - SFTP 本地/远程双栏文件浏览、文件与目录递归上传下载 - About 应用信息、Gitea Release 更新检查和应用内更新 ## 环境要求 - PATH 中可用的 OpenSSH `ssh` - macOS、Linux 和 Windows:支持前台和后台隧道 保存密码依赖操作系统凭据存储:macOS 使用 Keychain,Windows 使用 Credential Manager, Linux/BSD 使用 Secret Service(例如 GNOME Keyring 或 KWallet)。klink 不会把密码写入 `config.json`。 ## 安装 macOS 和 Linux: ```sh curl -fsSL https://gitea.bytevibe.dev/gary/klink/raw/branch/main/install.sh | sh ``` Windows PowerShell 5.1 或更高版本: ```powershell irm https://gitea.bytevibe.dev/gary/klink/raw/branch/main/install.ps1 | iex ``` 安装器会自动识别操作系统和 CPU 架构,从公开的 Gitea Release 下载最新版,并在安装前校验 `checksums.txt` 中的 SHA256。macOS/Linux 默认安装到可写的 `/usr/local/bin`,否则使用 `~/.local/bin`;Windows 默认安装到 `%LOCALAPPDATA%\Programs\klink\bin` 并加入用户 `PATH`。 安装指定版本或覆盖安装目录: ```sh curl -fsSL https://gitea.bytevibe.dev/gary/klink/raw/branch/main/install.sh | \ KLINK_VERSION=v0.1.0 KLINK_INSTALL_DIR="$HOME/.local/bin" sh ``` ```powershell $env:KLINK_VERSION="v0.1.0" $env:KLINK_INSTALL_DIR="$HOME\bin" irm https://gitea.bytevibe.dev/gary/klink/raw/branch/main/install.ps1 | iex ``` ## 构建 从源码构建需要 Go 1.25 或更高版本。 ```sh make build ./bin/klink version ``` 也可以直接运行: ```sh go run ./cmd/klink ``` ## 快速开始 添加节点: ```sh klink add Tokyo \ --ipv6 2001:db8::10 \ --ipv4 203.0.113.10 \ --user root \ --identity ~/.ssh/id_ed25519 \ --tags production,asia ``` 在 Nodes 页面新增或编辑节点时,`Authentication` 可以选择 `SSH Agent`、`Key file` 或 `Password`。选择密码后输入的内容会保存到系统凭据存储,表单和配置文件中都不会显示明文; 再次编辑时密码留空会保留现有凭据。命令行可用 `--auth agent|key|password` 选择认证方式, 密码本身需要在 TUI 节点编辑器中保存。 打开 TUI: ```sh klink ``` 连接或预览实际执行的 OpenSSH 命令: ```sh klink connect Tokyo klink connect Tokyo --dry-run klink connect Tokyo --ipv4 klink connect Tokyo --session ``` TUI 连接默认在系统安装了 `tmux` 时使用节点专属会话。SSH 中按 `Ctrl-b d` 可暂时分离并返回 klink,再次选择同一节点会恢复原会话;未安装 `tmux`、已经位于 tmux 内,或设置 `KLINK_NO_SESSION=1` 时自动使用普通 SSH 连接。 ```sh klink session list klink session attach Tokyo klink session kill Tokyo ``` 检查服务器当前提供的 host key 指纹,再接受或移除 known_hosts 记录: ```sh klink host-key inspect Tokyo --ipv6 klink host-key accept Tokyo --ipv6 --algorithm ssh-ed25519 klink host-key remove Tokyo --ipv6 ``` ## TUI 操作 | 按键 | 操作 | | --- | --- | | `Tab` / `Shift+Tab` | 切换下一个/上一个主页标签 | | `←` / `→` 或 `h` / `l` | 在当前页面切换焦点或调整选项 | | `↑` / `↓` 或 `j` / `k` | 移动选择 | | `Enter` | 连接当前节点 | | `/` | 搜索节点 | | `a` / `e` / `c` / `d` | 新增、编辑、复制、删除 | | `s` | 启动或停止当前隧道 | | `r` | 重启当前隧道 | | `Ctrl+S` | 保存编辑表单 | | 空格 | 在设置页和编辑器中调整当前选项 | | `Esc` | 取消或返回 | | `q` | 退出 | 支持鼠标单击标签、列表项和 SFTP 面板,使用滚轮移动指针所在的列表。双击节点、隧道、 设置项、SFTP 文件或弹窗列表项会执行对应操作;表单字段和弹窗按钮可以直接点击。 设置 `NO_COLOR=1` 可以禁用颜色。 ### About 页面 About 页面展示 klink Logo、版本、构建信息、运行平台、配置路径和项目地址。 使用 `↑/↓` 或 `j/k` 选择操作,按 `Enter` 检查更新或安装已经发现的新版本。 更新来自 [gitea.bytevibe.dev/gary/klink](https://gitea.bytevibe.dev/gary/klink) 的最新 Release; klink 只会安装与当前系统、架构匹配且通过 `checksums.txt` SHA256 校验的附件。安装完成后需要重新启动 klink。 Windows 无法覆盖正在运行的可执行文件,因此会先把新版本暂存到当前程序旁边;退出 klink 后, 后台 PowerShell 助手会完成替换,再次启动即使用新版本。若替换失败,错误会写入 `klink.exe.update-error.log`。 当前仓库尚未发布 Release 时,检查结果会显示“尚未发布”,不会被当作网络故障。 ### Settings 页面 在 Settings 页面使用 `↑/↓` 或 `j/k` 选择项目,使用 `←/→`、`h/l` 或空格修改, 操作项目按 `Enter` 执行。修改会立即保存。 可配置项目: - `system`、`dark`、`light` 主题和颜色开关 - 新节点默认使用 SSH Agent、HostKey 策略和连接超时 - IPv6 优先或 IPv4 优先的连接顺序 - 新隧道默认模式和自动重连 - 从 ktui 同步节点,或导入 klink JSON 和 OpenSSH `ssh_config` - 导出包含全局设置、节点和隧道的完整 JSON 备份 - 从磁盘重新加载当前配置 - 检查本机 `ssh` 路径、版本、`SSH_AUTH_SOCK` 和 Agent 身份状态 - 扫描所选节点的 host key 指纹,展示算法和 SHA256 指纹,并在用户确认后接受或移除记录 默认设置只影响之后新建的节点和隧道,不会静默改写已有项目。 严格校验和 `accept-new` 都显式使用同一个 known_hosts 文件,默认是 `~/.ssh/known_hosts`; 可通过 `KLINK_KNOWN_HOSTS` 指定其他路径。SSH、SFTP、隧道和 Settings 中的 Host Key 操作 都会使用这一路径。 ### SFTP 页面 SFTP 页面左侧浏览本地文件,右侧浏览所选节点的远程文件。宽度不足时只显示当前焦点面板, 使用 `←/→` 或 `h/l` 切换本地和远程面板。 按 `n` 打开节点选择框,使用 `↑/↓` 或 `j/k` 选择节点并按 `Enter` 连接;当前节点名称显示在远程面板标题中。 按 `g` 可输入路径并跳转当前面板,相对路径以当前目录为起点,本地和远端都支持 `~` 家目录写法。 上传或下载开始后会显示进度、实时速度和已传输大小。使用 `←/→` 或 `h/l` 选择“取消”或“隐藏”, 按 `Enter` 执行;`Esc` 可直接隐藏。隐藏不会中断传输,按 `t` 打开任务列表后可重新查看排队中、运行中、已完成、失败或已取消的任务。 传输按加入顺序串行执行;任务列表中选择失败或取消的任务后按 `r` 会使用 klink 管理的 partial 文件断点续传。 | 按键 | 操作 | | --- | --- | | `↑/↓` 或 `j/k` | 移动文件选择 | | `Tab` / `Shift+Tab` | 切换下一个/上一个主页标签 | | `←/→` 或 `h/l` | 聚焦本地/远程面板 | | `Enter` | 进入目录;选择文件时上传或下载 | | `Backspace` / `Esc` | 返回当前面板的上级目录 | | `u` | 上传左侧选中的文件或目录 | | `d` | 下载右侧选中的文件或目录 | | `f` | 在当前面板新建空文件 | | `m` | 在当前面板新建目录 | | `e` | 重命名当前文件或目录 | | `x` | 确认后递归删除当前文件或目录 | | `g` | 输入绝对或相对路径并跳转当前面板 | | `r` | 刷新两侧目录 | | `n` | 打开包含全部节点的选择框 | | `t` | 打开 SFTP 传输任务列表 | | 任务列表 `r` | 重试失败或已取消任务并断点续传 | 新建和重命名不会覆盖同名目标,删除目录前必须确认。文件夹会递归传输,目标已存在时必须确认后才会覆盖;文件先写入临时路径,完成后再重命名, 避免中断后留下看似完整的文件。启用断点续传的任务会保留带传输身份后缀的 `.klink-part-*` 文件; 下载任务同时保存只含传输身份、大小和 SHA256 的 sidecar 元数据。重试时会先校验本地 partial, 再让 SFTP 从远端对应偏移继续读取,不会重新传输已完成的前缀;成功后原子重命名为目标文件并清理元数据。 为避免密码提示破坏全屏界面,SFTP 使用非交互认证: 可以使用 SSH Agent(包括 Bitwarden SSH Agent)、无需交互输入口令的私钥,或节点中已保存的密码。 密码节点没有已保存凭据时,SFTP 会给出错误并要求先编辑节点。符号链接不会被传输。 文件操作完成后仅刷新受影响的面板;刷新中的列表会暂时显示加载状态,另一侧面板仍可继续浏览。 远端目录列表会在当前 klink 进程内按节点、连接地址和路径缓存。再次进入已访问目录或离开后返回 SFTP 页面时会直接使用缓存;远端标题会显示 `cached`。上传和远端增删改会自动失效相关缓存, 按 `r` 可忽略缓存并立即从服务器重新同步。缓存不会写入磁盘,退出 klink 后自动清除。 从 Nodes 页面或 `klink connect` 启动 SSH 时,klink 会在 OpenSSH 接管终端前显示 Logo 和感谢语。 ## 发布与应用内更新 推送 `v*` tag 会触发 `.gitea/workflows/release.yml`,使用 GoReleaser 构建 Linux、macOS、Windows 的 amd64/arm64 压缩包以及 `checksums.txt`。仓库 Actions Secret 中需要配置具有 Release 写权限的 `GITEA_TOKEN`。 ```sh git tag -a v0.1.0 -m "klink v0.1.0" git push origin v0.1.0 ``` 本地构建也可以注入版本信息: ```sh make build VERSION=0.1.0 COMMIT=local BUILD_DATE=2026-07-19 ``` 发布前建议执行 `make check`,并确认 Gitea Actions 中的 Release 工作流成功上传所有平台附件和 `checksums.txt`。首次发布完成后,上面的安装命令即可直接使用。 ## 端口转发 隧道专用模式开启自动重连后,会在网络故障或服务器重启后持续尝试恢复,退避时间从 1 秒 逐步增加并封顶为 32 秒;手动停止会立即取消等待。认证失败、Host Key 失败等不可恢复错误 仍会直接进入失败状态,避免无意义地重复认证。 本地数据库转发: ```sh klink tunnel add database \ --node Tokyo \ --type local \ --bind 127.0.0.1:5432 \ --target db.internal:5432 \ --reconnect ``` 远程转发: ```sh klink tunnel add webhook \ --node Tokyo \ --type remote \ --bind 127.0.0.1:8080 \ --target localhost:3000 ``` 动态 SOCKS5 代理: ```sh klink tunnel add socks-dev \ --node Tokyo \ --type dynamic \ --bind 127.0.0.1:1080 ``` 管理运行状态: ```sh klink tunnel list klink tunnel start database --dry-run klink tunnel start database --background klink tunnel stop database klink tunnel restart database ``` 一个配置可以包含多条转发规则: ```sh klink tunnel forward add database \ --type local \ --bind 127.0.0.1:6379 \ --target redis.internal:6379 klink tunnel forward remove database 2 ``` 本地和动态转发默认绑定 `127.0.0.1`。绑定 `0.0.0.0`、`::` 或其他非回环地址时, 启动命令会拒绝继续;确认风险后显式传入 `--allow-public`。远程公开监听还取决于 SSH 服务器的 `GatewayPorts` 配置。 后台隧道和 TUI SFTP 依赖非交互式认证,可以使用 SSH Agent、无需手工输入口令的私钥, 或节点中已保存到系统凭据存储的密码。运行日志和 PID 状态保存在配置目录的 `runtime/` 子目录中, 权限为当前用户私有。Windows 后台 worker 使用脱离控制台的进程、命名停止事件和 Job Object; 关闭 klink 不会中断 Tunnel,停止时会优雅取消 SSH,强制终止也会清理整个 SSH 子进程树。 ## 导入和导出 ### 从 ktui 同步 在 TUI 的 Settings 页面选择 `Sync from ktui` 并按 `Enter`,或者直接运行: ```sh klink sync ktui ``` klink 会执行: ```sh ktui export json ``` 然后根据 ktui UUID 同步节点名称、IPv4、IPv6、区域、分组和标签。已有节点会保留 klink 中的 SSH 用户、认证方式、密码凭据关联、密钥、端口、Host Key 策略、ProxyJump、连接记录和隧道引用; 只对首次出现的新节点应用当前默认 SSH 设置。重复执行同步不会创建副本。 如果旧版本导入的节点没有稳定 UUID,klink 只会在带有 `ktui-` ID 或 `Imported from ktui` 标记的节点中按名称或已有 IP 迁移匹配,不会覆盖同名的手工节点。ktui 中已经消失的节点不会 被自动删除,避免连带删除本地隧道或遗留凭据,需要时可在 Nodes 页面手工确认后删除。 也可以先保存 ktui 导出文件,再通过 `Import configuration` 或命令行同步: ```sh ktui export json -o ktui-nodes.json klink import ktui-nodes.json ``` 首次同步后在 Nodes 页面选择新节点并按 `e` 填写 SSH `User`,再选择 Agent、密钥或密码认证。 保存的密码只进入系统凭据存储,不会出现在 klink JSON、导出文件或进程参数中。 同步 ktui JSON 或导入 klink JSON: ```sh klink import nodes.json ``` 导入 OpenSSH 配置: ```sh klink import ~/.ssh/config --format ssh-config ``` 只有具体的 `Host` 别名会被转换为节点。`Host *`、通配规则和 Match 块不会展开成节点; 导入结果会逐项报告跳过内容和名称/ID 冲突。 导出包含全局设置、节点和隧道的版本化 JSON: ```sh klink export klink-backup.json klink export - ``` 导出只包含节点的认证方式和私钥路径,不包含系统凭据存储中的密码。将备份导入另一台设备后, 密码节点需要重新输入并保存密码。 ## 配置与安全 查看配置路径: ```sh klink config path ``` 可以用全局参数或环境变量指定其他配置: ```sh klink --config ./demo.json list KLINK_CONFIG=./demo.json klink list ``` - 配置文件以 `0600` 权限原子写入 - 密码和私钥内容不会写入配置;只保存私钥路径 - 默认使用严格 HostKey 校验 - `accept-new` 允许首次写入主机密钥 - `insecure` 会禁用 HostKey 校验,仅应在明确理解风险时使用 - OpenSSH 参数通过结构化参数数组执行,不经过 shell 插值 ## 许可证 klink 使用 [MIT License](LICENSE)。