我想让代理工具安静一点:Orbit Windows 的取舍
这篇文章的目录
我对一个代理管理器的期待,其实越来越简单了:配置按我写的运行,需要时能看清状态,关掉窗口以后也不用惦记它。
听起来没几件事,放到日常使用里却会冒出不少问号。点右上角的关闭,到底是收起界面还是停止内核?重新打开,会不会多启动一个进程?导入的 YAML 经过客户端处理之后,还和原来一样吗?出了问题,应该看界面日志还是去找另一个目录?
我做 Orbit,就是想把这些问题逐个交代清楚。它是 Windows 上的 Mihomo 管理器:Flutter 负责界面,Rust 后台负责内核进程、托盘、登录启动和更新。分流和代理能力仍来自官方 Mihomo。
这篇文章按 Windows 0.3.0 的源码与发行说明整理,面向 Windows 10 / 11 x64。下载入口在 Forgejo Releases。
先把配置的决定权留给 YAML
我不太希望自己维护的配置到了管理器里,又变成另一套需要重新理解的东西。所以 Orbit 的起点,是保留原始 YAML。
本地文件和 HTTP(S) 链接都可以作为配置来源。导入时会校验内容,再把原始字节存下来;端口、TUN、DNS 和分流规则仍由这份 YAML 决定。界面可以管理、搜索和编辑配置,但不会额外生成一份替代配置,也不会自动替我设置 Windows 系统代理。
这个边界会直接影响使用方式。比如我在首页看到的 Mixed、SOCKS 和 HTTP 端口,是从当前配置读出来的,并不是 Orbit 约定大家都要使用的默认值。需要 TUN 时,也要按配置和系统环境满足对应的权限要求,不能因为界面里有一个“启动”按钮,就假定所有事情都已经准备好了。
在代码里,这件事集中在 Rust 的 store.rs:校验、保存配置以及记录元数据。把保存动作和界面分开,后续调整页面时就不必顺手碰配置的运行语义。这种看起来有些保守的分工,恰好是我想要的。
关闭窗口,不应该让后台含糊起来
Orbit 最核心的取舍,是把“窗口还在不在”和“内核要不要继续运行”拆成两件事。
Flutter 窗口只在我需要操作时出现。普通关闭会结束界面,Rust 后台和已经运行的内核可以继续留着;托盘提供启停内核和重新打开界面的入口。真正要结束整套程序时,用托盘或设置里的“退出 Orbit”。
再次打开界面时,程序会连接当前软件目录、同一用户和同一权限级别的后台,而不是顺手再开一份内核。前后台通过 Windows Named Pipe 通信,Rust 维护状态,再把快照和事件交给界面展示。
Flutter 界面 │ Named Pipe:命令、状态与日志 ▼Rust 后台 ── 系统托盘 / 登录启动 / 更新 │ ▼官方 Mihomo 内核 ← 用户 YAML我更看重这种分离带来的确定性。窗口是一个控制入口,后台才承担生命周期。它也解释了为什么登录启动运行的是 Rust 后台:是否继续恢复内核,还要看已保存的恢复设置和上次运行状态,而不是简单地把“开机启动”理解成“每次都强行联网”。
首页只回答几件要紧的事
做界面时,我没有把所有可配置项都塞到首页。概览优先回答:内核在运行吗,运行了多久,现在用的是哪份配置,端口是什么。

图:Orbit Windows 的实际运行截图。左下角应用版本为 v0.2.19,内核为 Mihomo v1.19.32;配置名、端口和运行时长是截屏当时的状态。本文功能说明仍以 Windows 0.3.0 源码为准。
这套布局用低饱和的灰蓝色拉开层次,把更明显的颜色留给当前状态和主要操作。源码中的 OrbitTheme 统一了明暗主题、字号、圆角和动画时长;Windows 的字体优先使用 Segoe UI,再为中文设置回退。
我喜欢这种克制,因为代理工具通常只是工作过程中的一个配角。打开时能快速找到要做的事,处理完关掉,就可以继续原来的工作。
日志也遵循同样的思路:界面里能查看和筛选,后台文件落在软件目录的 logs/ 中。界面不在时发生的事情,仍然有地方可找。遇到启动失败,先确认 YAML 和权限,再沿日志定位,比反复点启停更有用。
应用更新和内核更新分开走
Orbit 本身的更新,和 Mihomo 内核的更新,是两条不同的路径。
应用更新从 Orbit 的 Forgejo 发行页 获取 Windows x64 安装版或便携版;内核更新独立检查 Mihomo 官方稳定发行,并保留失败回滚流程。这样我不必为了升级界面就把内核版本捆在一起,也不会把应用仓库的版本号误认为内核版本。
我没有把“能检查到更新”写成“任何环境都能无感升级”。网络、文件占用、安装方式和权限都可能影响结果。当前 Windows 分发包还没有 Authenticode 签名,系统可能显示相应提示;是否运行,应结合仓库来源和发行校验信息自行判断。
这一部分的维护成本并不比画页面低。发布脚本会核对 Flutter、Rust 与界面的版本一致性,同时保留历史发行,避免后来构建的同名文件覆盖先前版本。对个人项目来说,能解释清楚用户手里的包从哪里来,是值得花时间的事。
安装版和便携版,照顾两种习惯
0.3.0 同时提供 Setup 和 Portable,两者使用相同的前后台与官方内核。
我会把它们理解成两种管理软件的习惯:希望开始菜单和卸载入口都安排好的,选安装版;习惯把工具放在一个可写目录里、自己整理版本的,选便携版。
安装版默认按当前用户安装到 %LOCALAPPDATA%\Programs\Orbit。便携版需要完整解压,再运行 app\Orbit.exe。配置、设置、运行数据、日志和备份都留在软件根目录下的对应文件夹里。
便携也有明确边界:移动目录或切换常用版本之后,要在目标版本重新设置登录启动路径。安装版则应该沿原安装位置升级,不能把它当成随意移动的便携文件夹。卸载默认保留个人数据,具体选项可以看安装说明。
第一次使用,我建议先做完这个很短的流程:
- 从发行页选择适合自己的包,按对应方式安装或完整解压。
- 导入自己能理解、来源可信的 Mihomo YAML,确认端口和 TUN 等设置。
- 主动启动内核,检查概览与日志,再验证需要使用的网络路径。
- 分别试一次关闭窗口和“退出 Orbit”,熟悉两者的区别。
我想保留下来的,是可预期
Orbit 目前没有试图接管所有网络相关的决定。系统代理、分流规则和配置策略都有各自的边界。我希望管理器的价值,是把已有能力组织得清楚,让日常操作少一点猜测。
做这个项目时,我越来越在意的也是那些不太适合放在宣传图上的细节:后台是否还是原来那一个,失败后有没有保留线索,升级会不会覆盖旧文件,关闭按钮的行为是否和预期一致。
如果这些细节也刚好是你在意的,可以去 Orbit 仓库 看看。手机端的另一套取舍,我放在了《Orbit for Android:让 YAML 和后台各守边界》里。
源码阅读入口:配置存储、后台生命周期、界面主题。2026 年 10 月 25 日更新了实际运行截图,保留原始画面与版本信息,仅作 WebP 格式压缩。