tunlite docs文档
A lightweight, cross-platform SSH tunnel manager. Define named tunnels once; a tiny zero-dependency daemon keeps them connected, restarts them at login, and helps set up passwordless access. Every command supports --json and stable exit codes.
轻量、跨平台的 SSH 隧道管理器。一次定义命名隧道,由一个零依赖的小守护进程保持连接、开机自启、帮你打通免密。每个命令都支持 --json 和稳定退出码。
Install安装
Prerequisite: Node ≥ 18 and the system ssh it wraps, both on your PATH. Pick one — no global npm required.前提:Node ≥ 18 和它封装的系统 ssh,都在 PATH 上。任选其一 —— 不依赖全局 npm。
npx tunlite install
curl -fsSL https://raw.githubusercontent.com/yuanyuanzijin/tunlite/master/bootstrap.sh | sh
irm https://raw.githubusercontent.com/yuanyuanzijin/tunlite/master/bootstrap.ps1 | iex
tunlite install copies the runtime to a fixed directory and writes a launcher that pins node's absolute path (switching nvm/fnm won't break it). Run interactively, it also offers to register login autostart and install the agent skill. A short tun alias is added too (skipped with a notice if the name is already taken).tunlite install 把运行时拷到固定目录,并写一个钉死 node 绝对路径的 launcher(切换 nvm/fnm 也不受影响)。交互运行时还会问你是否注册开机自启、安装 agent skill。也会顺带写一个短别名 tun(若已被占用则跳过并提示)。
.cmd launcher, PATH setup) works but is less battle-tested — please report rough edges.Windows 支持目前为 beta。 macOS 和 Linux 是主力、有 CI 覆盖的平台;Windows(任务计划自启、.cmd launcher、PATH 设置)能用,但验证较少 —— 遇到问题欢迎反馈。Quick start快速开始
One forward per add (a tunnel can carry several — see Forwards). --local is your machine's side, --remote is the server's side; the subcommand decides who listens.每个 add 一个转发(一条隧道可带多个,见转发模型)。--local 是你机器侧,--remote 是服务器侧;子命令决定谁监听。
# reach the server's :80 on your local :8080 $ tunlite add local web-8080 --to user@server --remote 80 --local 8080 # local SOCKS5 proxy (default :1080) $ tunlite add dynamic px-1080 --to user@server # expose your local :3000 as server:9000 $ tunlite add remote rev-9000 --to user@server --local 3000 --remote 9000 $ tunlite up # enable + start all, bring up the daemon $ tunlite status # aligned table of every tunnel $ tunlite logs web-8080 -f # follow logs $ tunlite doctor # why it won't connect (ssh/key/port/daemon)
When the target isn't passwordless yet, running tunlite up in a terminal prompts for the password once and installs your key. Or do it explicitly: tunlite check user@server (exit 0 = already works) and tunlite setup-key user@server.目标还没免密时,在终端跑 tunlite up 会让你输一次密码并装好公钥。也可显式执行:tunlite check user@server(退出 0 = 已通)、tunlite setup-key user@server。
Autostart (optional): tunlite install service registers the daemon to start at login — it also starts everything right away, so it replaces up when you want tunnels up persistently.开机自启(可选):tunlite install service 把守护进程注册成登录自启 —— 它当场也会把一切启动起来,所以想让隧道持久常驻时它替代 up,两者不用都做。
Update升级
$ tunlite update # upgrade to the latest $ tunlite update v0.9.0 # install / roll back to a tag $ tunlite update --check # compare vs latest, no change $ tunlite update --no-restart # swap files only
update upgrades to the latest release tag: it fetches that tag's tarball and re-anchors in place (no npm, no git), then restarts the daemon — so the installed version is always a real published release. It only self-updates an anchored install; from a git checkout it points you to git pull, and from an npm i -g install to npm i -g tunlite@latest.update 升级到最新的 release tag:拉那个 tag 的 tarball 就地重新锚定(不走 npm、不走 git)再重启 daemon —— 所以装上的永远是一个真实已发布的版本。它只自更新锚定安装;在 git 检出里提示你用 git pull,在 npm i -g 安装里提示你用 npm i -g tunlite@latest。
Uninstall卸载
$ tunlite uninstall # stop daemon + remove everything (confirms first) $ tunlite uninstall --force # skip the confirmation $ tunlite uninstall --purge # also remove config and logs $ tunlite uninstall service # remove autostart only
Interactive uninstall asks for confirmation and warns if any tunnels are currently up. --force (or --json for scripts/agents) skips the prompt.交互式 uninstall 会先确认,并在有隧道正在运行时提示。--force(脚本/agent 用 --json)可跳过确认。
How it works工作原理
Three roles, each with one job — think remote, engine, guard.三个角色,各司一职 —— 可以理解成遥控器、引擎、保安。
CLI tunlite …
The commands you type. Edits config.json, talks to the daemon, then exits.你敲的命令。改 config.json、和 daemon 通信,敲完即退。
daemon daemon run
A long-lived process. Keeps every tunnel connected, reconnects on drop, serves status & logs.一个常驻进程。把每条隧道连着、断了重连、对外提供 status 和日志。
service install service
A launchd / systemd / Task Scheduler entry. Keeps the daemon alive across boots and crashes.launchd / systemd / 任务计划里的一条注册项。开机拉起、挂了重启,保活 daemon。
you ── tunlite <cmd> (CLI) ──┬─ write config.json (add/rm/up/down)
├─ NDJSON IPC → daemon (status/logs/restart)
└─ one-shot ssh (check/setup-key)
OS service ── runs ──▶ tunlite daemon run ──spawn──▶ ssh -N (-L/-R/-D)
▲ created by `install service` │ supervise + reconnect (backoff)
└ keeps the daemon alive ▼
config.json ◀── reconcile on (re)start
config.json is the single source of truth. The OS service keeps the daemon alive; the daemon keeps every tunnel alive and reconciles against the config on every start. The daemon starts only on tunlite up (on demand) or tunlite install service (at login) — other commands won't start it; if it's down they exit 5 and tell you how.config.json 是唯一事实来源。OS service 保活 daemon,daemon 保活每条隧道,每次启动还会与配置对账。daemon 只在 tunlite up(按需)或 tunlite install service(开机)时启动 —— 其它命令不会启动它;它没在跑时会退出 5 并告诉你怎么启动。
Forwards转发模型
Each add defines one forward; a tunnel can carry several over one connection — manage them with tunlite forward list|add|rm <tunnel>.每个 add 定义一个转发;一条隧道可在一条连接上承载多个 —— 用 tunlite forward list|add|rm <tunnel> 管理。
local— reach a remote service from your machine (--remoterequired).local—— 在本地够到远端服务(--remote必填)。remote— expose a local service on the server (--localrequired).remote—— 把本地服务暴露到服务器(--local必填)。dynamic— a local SOCKS5 proxy (default port1080).dynamic—— 本地 SOCKS5 代理(默认端口1080)。
--local always means your machine's side and --remote the server's side; the subcommand decides who listens. Addresses are [host:]port: the listening side's host is the bind address (default 127.0.0.1, use 0.0.0.0 to expose); the target side's host is the host to connect to (default localhost).--local 永远指你机器侧、--remote 永远指服务器侧;子命令决定谁监听。地址写 [host:]port:监听那侧的 host 是绑定地址(默认 127.0.0.1,写 0.0.0.0 对外),目标那侧的 host 是要连的主机(默认 localhost)。
The SSH port rides in the target — --to user@host:2222 (defaults to 22; must be an integer 1–65535 or it's a usage error). IPv6 literals with a port need brackets: user@[::1]:2222.SSH 端口写进目标里 —— --to user@host:2222(默认 22;必须是 1–65535 的整数,否则报用法错)。IPv6 字面量带端口要加方括号:user@[::1]:2222。
Commands命令
| Command命令 | What it does作用 |
|---|---|
| add local|remote|dynamic <name> --to user@host | Define a tunnel (one forward; add more with forward).定义一条隧道(先一个转发;用 forward 加更多)。 |
| set <name> [--to …] [-i key] [--jump …] | Change a tunnel's host / key / jump / options / tags.改隧道的 host / 密钥 / jump / 选项 / 标签。 |
| rename <old> <new> | Rename, handing off the live connection.重命名,平滑交接活动连接。 |
| rm <name> · list [--tag T] | Delete (and stop) a tunnel · list defined tunnels.删除(并停掉)隧道 · 列出已定义隧道。 |
| forward list|add|rm <tunnel> | Manage a tunnel's forwards (it can carry several).管理某隧道的转发(可带多个)。 |
| up · down · restart [name|--tag T] | Control (no name/tag = all; --tag = every tunnel with that label).控制(不带名字/标签 = 全部;--tag = 带该标签的所有隧道)。 |
| status [name|--tag T] | Structured status (no name = aligned table; with name = detail).结构化状态(无名 = 对齐表格;有名 = 详情)。 |
| monitor [--interval s] [--tag T] | Full-screen live dashboard.全屏实时面板。 |
| logs <name> [-f] [-n N] | View / follow logs.查看 / 跟随日志。 |
| doctor [name] | One-shot health check: why it won't connect.一键体检:为什么连不上。 |
| check · setup-key <user@host> | Probe passwordless / install your public key.免密探测 / 安装你的公钥。 |
| webhook [set|on|off|events|test] | Drop alerts: view / set / toggle / pick events / test.掉线告警:查看 / 设置 / 开关 / 挑事件 / 测试。 |
| export · import <file> [--force] | Export config (no keys) · merge tunnels back.导出配置(不含密钥)· 合并导入隧道。 |
| update [version] | Update (or pin a tag) and restart the daemon.升级(或锁定标签)并重启 daemon。 |
| install [service|skill|completion] | Anchor runtime; add autostart / skill / completion.锚定运行时;加自启 / skill / 补全。 |
| uninstall [target] [--purge] [--force] | Uninstall (no target = everything; confirms first, --force skips; --purge drops config/state).卸载(不带目标 = 全部;先确认、--force 跳过;--purge 连配置/状态一起删)。 |
| daemon run|start|stop|status | Daemon lifecycle (run = foreground, for the service).daemon 生命周期(run = 前台,供服务调用)。 |
Naming convention: <purpose>-<port>, all-lowercase, hyphen-separated — e.g. tmux-prod-19999, db-staging-5432. That way status/logs read self-explanatory.命名规范:<用途>-<端口>、全小写、连字符分隔 —— 例如 tmux-prod-19999、db-staging-5432。这样 status/logs 一眼自解释。
Jump hosts跳板机
Reach a target through one or more bastions with --jump [user@]host[:port][,…] (ssh -J / ProxyJump) on add, set, check, and setup-key. It's stored per-tunnel and used for the auth probe too.用 --jump [user@]host[:port][,…](ssh -J / ProxyJump)经一个或多个堡垒机到达目标,add / set / check / setup-key 都支持。它按隧道保存,免密探测也走它。
$ tunlite add local db-5432 --to user@db --remote 5432 --jump user@bastion $ tunlite set web-8080 --jump user@b1,user@b2 # chain multiple hops
Live monitor实时面板
tunlite monitor (alias mon) opens a top-style full-screen dashboard: daemon status and tunnel counts up top, a colour-coded tunnel table below.tunlite monitor(别名 mon)打开 top 风格的全屏面板:顶部 daemon 状态与隧道计数,下面是上色的隧道表。
↑/k↓/jselect,sstart,xstop,rrestart (y/Nconfirm).↑/k↓/j选择,s启动,x停止,r重启(y/N确认)。?help,qquit,--interval <seconds>sets the refresh rate (default 1s).?帮助,q退出,--interval <秒>调刷新间隔(默认 1s)。
Requires an interactive terminal; in scripts use tunlite status --json.需要交互式终端;脚本里用 tunlite status --json。
Exit codes & --json退出码与 --json
Add --json to any command for machine-readable output. Branch on the exit code rather than parsing prose:任意命令加 --json 得到机器可读输出。按退出码分支,而不是解析人话:
state values: idle, starting, connected, retrying, needs-auth, failed, stopped, disabled, daemon-stopped. Treat connected as success; retrying is normal during a transient outage.state 取值:idle、starting、connected、retrying、needs-auth、failed、stopped、disabled、daemon-stopped。connected 即成功;retrying 是短暂断网时的正常状态。
Webhooks告警 webhook
When a tunnel drops, the daemon POSTs an alert to a webhook you configure, formatted per channel (currently generic + WeCom wecom). The channel is detected from the URL, or set with --channel. Pure Node built-in http/https — no new dependencies.隧道掉线时,daemon 往你配的 webhook POST 一条告警,按渠道排版(目前 generic + 企业微信 wecom)。渠道从 URL 自动识别,或用 --channel 指定。纯 Node 内置 http/https,无新依赖。
$ tunlite webhook # show current config $ tunlite webhook set <url> # set + enable (channel auto) $ tunlite webhook events down,recovered # change events $ tunlite webhook off # disable (keeps the URL) $ tunlite webhook test # POST a test event
Events are edge-triggered (a reconnect storm fires once), in two scopes:事件按状态边沿触发(重连风暴只报一次),分两类:
- tunnel:
up,down,recovered,needs-auth,failed,stopped.隧道级:up、down、recovered、needs-auth、failed、stopped。 - daemon:
daemon-up,daemon-down,daemon-crash.daemon 级:daemon-up、daemon-down、daemon-crash。
webhook events accepts names, the groups tunnel/daemon, all, or none. Default: down, recovered, needs-auth, failed, daemon-crash. Payload: {scope, tunnel, host, event, state, lastError, restarts, ts, machine, version}.webhook events 接受名称、组 tunnel/daemon、all、none。默认:down, recovered, needs-auth, failed, daemon-crash。载荷:{scope, tunnel, host, event, state, lastError, restarts, ts, machine, version}。
Import / export导入导出
$ tunlite export > backup.json # dump config (no secrets) $ tunlite import backup.json # merge tunnels $ tunlite import backup.json --force # overwrite same-name
import merges tunnels only — it never changes your local settings/alerts. A missing file exits 3; a malformed file exits 1 and leaves the current config untouched.import 只合并隧道 —— 不会动你本地的 settings/告警。文件不存在退出 3;文件损坏退出 1,且不改动当前配置。
Shell completionShell 补全
$ tunlite install completion # auto-detect the shell $ tunlite install completion zsh # or name it: bash/zsh/fish $ tunlite uninstall completion # disable
Once on, it completes subcommands; for up/down/restart/status/logs/rm/rename it also completes defined tunnel names, for both tunlite and the short tun. Reopen the shell or exec zsh to take effect.开启后补全子命令;对 up/down/restart/status/logs/rm/rename 还会补全已定义的隧道名,tunlite 和短别名 tun 都能补。重开 shell 或 exec zsh 生效。
For agents给 Agent 用
Agents are a first-class user. Every command takes --json and returns a stable exit code, so an agent acts on results without scraping prose. The bundled ssh-tunnel skill — installed with tunlite install skill and shipped in the npm package — tells an agent exactly how to drive tunlite: --json, branching on exit codes, and how to handle needs-auth.agent 是一等用户。每个命令都接受 --json 并返回稳定退出码,agent 拿到结果就能直接判断,不用解析人话。内置的 ssh-tunnel skill —— 用 tunlite install skill 安装、随 npm 包一起发布 —— 告诉 agent 怎么驱动 tunlite:--json、按退出码分支、处理 needs-auth。
Config paths配置路径
- Config:
$XDG_CONFIG_HOME/tunlite/config.json·%APPDATA%\tunlite\config.json配置:$XDG_CONFIG_HOME/tunlite/config.json·%APPDATA%\tunlite\config.json - State/logs:
$XDG_STATE_HOME/tunlite·%LOCALAPPDATA%\tunlite状态/日志:$XDG_STATE_HOME/tunlite·%LOCALAPPDATA%\tunlite - Use
TUNLITE_HOMEto put everything under one root (handy for testing).用TUNLITE_HOME把所有东西归到一个根目录下(测试很方便)。
Versioning版本管理
Follows SemVer (vMAJOR.MINOR.PATCH). Release notes are in the CHANGELOG; the source lives on GitHub. Licensed MIT.遵循 SemVer(vMAJOR.MINOR.PATCH)。发布说明见 CHANGELOG;源码在 GitHub。MIT 许可证。