肇鑫的日常博客

肇鑫 / Owen Zhao

独立开发者,主要开发 iOS、watchOS、macOS 应用。

目前在维护 SleepTap、Rooster Time,以及 Markdown Writer 相关工具。

最新文章

DSH手机访问,Tailsacale + dsh-mobile插件

技术

我想让手机在外面也能指挥家里那台 Mac 上的 dsh。不是远程桌面那种指挥,是打开手机,看到会话列表,发一句话,看它跑。

问题很快就来了:家里有公网 IP,但从外面连不进来。我查了一下自己的出口,是 175 开头的一个地址,看着就是可以直接拨回来的那种,实际上连不上——家里的路由器默认不接受入站连接,我没有给它做端口映射。而且这个地址是动态的,光猫重启、运营商续租都会变,把它写死进任何配置里,过几天就失效了。

真要顺着这条路走,得在路由器上开端口映射,再挂一个动态 DNS 服务,把会变的地址绑成一个固定名字。这条路是通的,我也认真考虑过,最后还是没走:把一个端口开到公网上,等于让互联网上所有扫描器都能来敲我的门,我不太能接受那种“谁都能访问”的状态。

AI建议我使用Tailscale。我没同意,后来证明我的想法是错的。这是因为我以前使用过Tailscale,那时候的经验限制了我。

我当年是这么干的

那时候我对 Tailscale 的理解就是一条 VPN。于是按它最标准的用法来:手机、VPS、家里的电脑,三台都装客户端。家里没有任何对外开放的入口,VPS 顺便当个落脚点。

但是在安卓上遇到了问题。系统只有一个 VPN 槽位。Tailscale 占了它,我手机上就上不了外网了——能连家里,是连 Google、连 GitHub 全都断。Tailscale 给了一条到内网的路,但它不负责帮你翻墙。

那怎么办?我当时的解法是把 VPS 设成TailScale的出口节点(exit node),让手机的流量先绕到 VPS,再从 VPS 出去。听起来很合理:反正 VPS 是国外的,顺便当个梯子用。

能用,但慢。慢到我宁愿不用。原因也不难想:流量先加密到 VPS,绕一圈再出去,而 VPS 本身是个小机器,线路也一般。这不是 Tailscale 的错,是我把两种完全不同的需求——“连回家里”和“上外网”——硬塞进了同一条隧道里。

后来干脆就不用了。因为Codex这种直接就能使用手机访问了。

这次才想明白:它不该是一条全局 VPN

这次是AI帮我自动配置的,它配置了一条单独的规则,只有特定的访问才会通过规则走Tailscale。这个是最近的代理应有都有能力,之前我使用的时候代理都还不支持TailScale,所以我使用的官方的客户端。

技术上靠的是 mihomo。它在 1.19.25 版本支持了 type: tailscale 的出站,意思是我可以在 Clash 配置里写一个 tailscale 类型的节点,跟机场节点并列排在一起。FlClash 仍然是手机上唯一的 VPN,翻墙流量照旧走机场,只有去家里那台 Mac 的流量才被这个节点接手。

两个需求分开了,谁也不挤谁。这才是这次的真正收获:不是“省下了一台 VPS”,而是发现 Tailscale 可以按规则用。我以前的用法是“开一条隧道接管全部流量”,现在的用法是“在某些地址上,多一条回家的路”。

配置起来就三段:一个 tailscale 类型的出站,一个 select 组,两条规则。多一条规则,多一条路,仅此而已。

不过它不随 FlClash 启动就开始连接。按官方文档的说法,任何类型的节点都只在第一次有流量命中时才建立连接,所以头几次访问超时是正常的,不是配错了。

让它以为我还站在家里

真正有意思的是最后一步,子网路由。

移动网关只监听 10.0.0.114:3443,自签证书也只签了这一个地址。如果让手机直接去访问 Tailscale 分给它的 100.x 地址,证书对不上,配对得重做一遍。

所以我没动网关,而是在 Mac 上宣告了一条 10.0.0.0/24 的路由,再到后台批准。这样一来,手机拨的还是 10.0.0.114,包却走的是 tailnet。它以为自己在家里。地址没变,证书没变,配对记录也没变。

这条路也是可逆的。哪天不想给整个网段开门,把宣告改成 10.0.0.114/32,后台重新勾一次,就只放开这一台。

到底是不是直连

装完我盯着连接状态看了两轮。

在家,Wi-Fi 开着,curAddr 是 10.0.0.6,手机在局域网里的地址。关掉 Wi-Fi 换成移动数据,同一个节点,curAddr 变成 175.x.x.x,运营商给我分的公网地址。

两行字,一个是局域网直连,一个是公网打洞直连,都不是中继。这一点很重要。当年那套三台机器的方案给我留下的印象就是“能连上,但慢”,慢的原因几乎都出在中继或者绕行上。真直连的话,延迟就是你两端网络的自然延迟,中间没有多一跳。

顺带澄清一个误会

我装完一开始以为,安全是靠那个自签证书保证的——手机上装了 CA 证书才能连上,听起来像是“装了证书才有权限”。这可能吗?不是。证书只干一件事:让手机相信这个 HTTPS 是这台电脑的,链路能加密、不被中间人冒充。它不负责授权。

真正拦人的是配对。网关对所有未配对的请求一律返回 401,配对码是 256 位随机串,只在电脑本机的回环接口上生成,两分钟过期,用过即废,还有频率限制,电脑那边存的也只是令牌的哈希。缺一个都不行:只有证书没有令牌,拿到地址的人就能控制你的电脑;只有令牌没有证书,令牌会被同一个网络里的人嗅探走。

所以这套东西的门禁其实是够的,这一点我很确定。但“认证够不够”和“我愿不愿意把这扇门放到公网上”是两件事。一台能执行 shell 的机器,长期挂在一个被全世界的扫描器反复敲打的端口后面,我睡得不安稳。Tailscale 这条路,公网上根本没有我开放的端口,也就没有这些事。

那 VPS 现在还要不要

按这次的用法,不需要了。它不再承担“让手机出网”的职责——那是机场节点的事;它也没成为中继,因为两端打洞成功,直接直连。

只有一种情况我会重新考虑:打洞失败,流量长期走 DERP 中继,而中继节点基本在国外,慢到没法用。那时候才值得起一台国内的小机器自建中继。到那一步,VPS 的角色是提速备件,不再是必需品。

总结

这几年我一直以为 Tailscale 是一条 VPN,包住所有流量。按那个理解搭出来的方案,必然要牺牲别的东西——要么牺牲手机的翻墙,要么牺牲速度,要么再加一台 VPS 去补。我当年选了加 VPS,然后被速度劝退。

这次真正想通的是:它可以是规则里的一条旁路。手机上还是那套代理,只有去家里那台 Mac 的地址,才拐上这条路。翻墙归翻墙,回家归回家,两件事本来就该分开走。

我没有租 VPS,也没有开端口映射。配置加起来不到二十行,全部收益就是:在外面打开手机,能看见家里那台 Mac 上的会话列表。

Mac远程桌面登录,账户始终无法直接登录问题的解决

技术

我经常用 Mac 的“屏幕共享”连接另一台 Mac mini。以前点一下就能进去,最近却不行了。每次连接都会先弹出一个窗口,说远端的 zhaoxin 正在使用显示器,让我选择“请求许可查看显示器”,或者“以 aiUser 身份登录”。默认选中的是请求许可。点连接以后,就一直转圈。

这就很奇怪。两台电脑上我用的都是 zhaoxin,为什么连接自己的电脑,还要等对面有人批准?Mac mini 又不一定有人坐在前面,等下去也不会有人点“允许”。我只能点 Back,重新输入 zhaoxin 的密码,才能进去。进去之后,还需要再次输入一遍密码才能进入桌面。

我一开始怀疑,是 Finder 把文件共享的登录身份搞混了。Finder 那边显示的是我的 Apple Account 邮箱,可是“屏幕共享”的连接详情里,用户名明明写着 zhaoxin。后来我又去看两台电脑的用户列表:本机没有 aiUser,远端 Mac mini 上却有。更有意思的是,选“以 aiUser 身份登录”居然也能进去。也就是说,aiUser 不是一个凭空冒出来的用户名,真正进不去的只有默认那个“请求许可”。

我又检查了远端的屏幕共享设置。允许访问的用户里有 zhaoxin,所以权限本身没问题。试过在输入密码时勾选“记住密码”,下一次仍然要输入。之前我还以为这只是密码没有保存好,现在看起来,事情没那么简单。

最后,我在 Mac mini 上删除了不再需要的 aiUser。删除之前发现,这个账户还开着“查找我的 Mac”。我先把相关功能关掉,再删除账户。结果重新连接时,那个让我选择“请求许可”或 aiUser 的窗口消失了,系统直接让我输入 zhaoxin 的密码。这次勾选“记住密码”后,再连接就直接进入,连密码也不用输了。故障排除。

总结

我怀疑 aiUser 开启“查找我的 Mac”后,在系统里有了某种更高的关联地位,影响了屏幕共享默认选择的连接方式。不过我同时关闭了“查找”并删除了账户,没有单独测试哪一步起了作用,所以不能把这个推测当成确定的原因。能够确定的是:远端多出这个账户时,屏幕共享总把我带到一个无法完成的请求许可流程;清理掉它之后,zhaoxin 的直接登录和记住密码都恢复了正常。

ChatGPT防慢指南

技术

经常有人说ChatGPT很慢,即便是提速了之后还是慢。我看到有人发的测试图,然后自己也测试一下,发现我这次测出来的速度并不慢。刚刚,我遇到了Reconnection 5/5的问题

stream disconnected before completion: IO error: Broken pipe (os error 32)

以往我就是等它继续了。但是今天我突发奇想,新建一个对话,然后让Codex分析,这次故障的原因。Codex分析说,这个对话原本使用的是WebSockets,然后再5次重试之后,换成了http的访问方式。但是在我这里,http的访问是很慢的。因此,我担心一旦回退到http的方式,之后的对话都会继续使用http。

我使用了多种方式进行测试。首先是新建一个对话,然后让Codex分析,Codex说这个新对话还是使用的WebSockets,然后我继续刚刚出错的对话,Codex说这个继续使用了http。于是我退出Codex,重新开,然后继续刚刚出错的那个对话。结果那个对话虽然一开始恢复使用WebSockets了,但是它立刻连续失败了5次,然后又回退到http。我问Codex这种情况怎么办。Codex让我新建一个session,然后重新说明任务。这次终于好了。

总结

当长任务遇到WebSokets失败之后,最好的办法就是新开一个对话,然后重新描述任务。否则就会回退到http,这会导致对话变得很慢,根源是

WebSocket 在长任务中可以复用连接和近期响应状态,减少每次继续请求的开销;HTTP 回退会失去这项优势。

Codex上下文的前世今生,要不要调整上下文你看这一篇就够了

技术

今天,Tibo在X上给出了Codex设置1M上下文的方法。我尝试了,也的确成功了。但是我又改回去默认的258K。关于上下文这个事,以下的事情是你需要了解的。

在gpt-5.6系列发布之前,Codex的上下文一直是258K。这是用户可用的部分,隐藏了系统占用的。但是gpt-5.6发布之后,这个上下文一度增加到了384K。不过很快,有人发现5.6的额度消耗过快。这是因为原本调整为384K之后,应该是384K上下文之内都应该按照默认收费,如果额外设置,超出了,才应该按照2x收费。可是实际上,OpenAI的服务器却是按照超过258K就开始2x收费,OpenAI发现了这个bug,于是回滚到258K的上下文,并且承诺,说一旦修复了。就会恢复。

可最终OpenAI并没有兑现这个承诺。258K就是目前的最终的默认上下文。唯一改变的,是以前只有使用API的用户可以设置为1M上下文,现在任何订阅的用户也可以设置了。但是一旦超过默认的258K,全部的输入都会按照2x收费,全部的输出都会按照1.5x收费。注意:是超过默认的258K,全部都会按照2x和1.5x收费,而不是超出的部分。而订阅用户,如果手动设置为更大的上下文,则会感到额度消耗得更快了。

这也是为什么我最终还是选择回退到默认的设置,毕竟省钱才是王道。

如果你想测试

可以将tibo的原文贴给AI,然后AI遵照设置,设置完成之后,需要退出重开一下Codex。取消也是同样的,需要重启Codex才能执行。

Screenshot 2026-08-17 at 9.54.55 AM

我也是使用GitHub自动化的人了

技术

我有两台Mac mini,1台m1,一台m4都是16GB的。之前我为了节省资源,ollama都是跑在m1那台,而我日常使用的是m4的这台。这就导致了一个问题。就是我开发的Chrome扩展X Recommender Plus在调用局域网里的Ollama的时候,会被拒绝服务。这是因为,Ollama默认情况下,只针对本机的所有请求开发了服务,如果是局域网的请求,就会验证头。

因此,要解决这个问题,我就得自己修改代码,然后本地编译。方法不难,仅需要修改一行代码。但是修改之后的只有我自己能用。今天,我突发奇想,问问AI,问它可不可以在GitHub上fork一下ollama,然后完成我本地操作的步骤,最后发布。AI说可以,然后就开始跑。

前几次都收到run failed的邮件。之后AI停了,告诉我成功了。但是我发现release里并没有成果。我问AI,AI说因为我选择的全平台,所以编译要很久,这个可把我给吓到了。因为我知道GitHub的action是有免费额度限制的。于是我赶忙问AI,那这样的话,咱们的免费额度够跑几次的啊?结果AI告诉我,我们fork的public的,而我们自己的也是public,所以action用多少都是免费的。这样我就安心了。

这个是GitHub的地址:https://github.com/owenzhao/ollama

使用X Recommener Plus的诸位可以根据需要选择。其他人有需要也可以选择。这个好处主要是两点:

  1. macOS的版本默认支持苹果的mlx。
  2. 局域网安装的ollama,任何应用或者插件都可以调用,不会被拒绝。

从大家指责微信使用SQLite想到的

技术

最近大家因为微信的存储有问题,从而上升到微信是否应该使用SQLite还是应该制造轮子。但其实焦点一直就错了。微信使用了SQLite,不代表它就没有制造轮子。还好我的年纪大,记忆也还不错,搜索了一下,找了证据。wcdb,这个就是微信开源的SQLite工具,至今还在维护。所以,说它没造轮子是不正确的。

这件事,其实让我想到的是其他的事情。随着AI辅助编程的出现,编程技能越来越被普通人所忽视,甚至上升到了不是程序员,编程反而更有优势这种奇谈怪论,逻辑是说非程序员不会收到懂编程的束缚,可以天马行空,所以更容易成功。这叫好比说不懂物理的人,可以不受到物理定律的束缚,所以可以天马行空,轻松超越光速。这可能吗?

不过AI的确把编程的门槛降低了。但是如果你的应用不是为了自用,而是为了卖掉。那就不是只自己满意就可以了。而是要知道用户想的是什么。用户的想法,在我看来,则是信誉的问题,同样的应用,如果是来至更值得信赖的来源,比如知名的开发,知名的大公司,那肯定比不知名的开发者或者不知名的小公司的产品更加容易成功。而开发者,则需要用时间和产品来证明,自己是值得信赖的。

发现了一个App Store Connect的一个bug

技术

Xcode Cloud如果归档设置了无,然后后续设置为TestFlight。这样打包的应用是不能发布到商店的。但是现在App Store Connect的分发页却允许选择这个的打包的应用,不过问题来了,选完之后,点保存,会直接出现感叹号,没有办法保存,也就没法审核。

正确的方式,是归档时设置为App Store Connect,然后后续选择TestFlight。然后保存,重新打包就可以了。

手动处理macOS睡眠后又迅速被唤醒的问题

技术

最近遇到了一个问题,我的Mac mini m4在睡眠之后,很快就会再次唤醒。有时刚刚睡眠就唤醒,有时睡眠不到1分钟就会唤醒。

现在已经是AI的时代了。我于是就询问AI怎么处理。AI给我了几个命令,让我看输出,我说没输出,它有给我另外一组命令,我将输出复制给它。AI说是我的蓝牙键盘造成的,睡眠之后它还在发出信号。我按照它的提示,将键盘从蓝牙改成有线,结果忽好忽坏,效果不如意。

AI还提了一个很可笑的建议,它让我把系统的蓝牙关了,然后再睡眠。这还真是一个头疼医头的建议,因为我的键盘鼠标都是蓝牙的,禁用了,就开不了了。

不过我也的确同意大概率是蓝牙的问题,可问题是我有三个蓝牙设备。苹果触控板、蓝牙键盘、蓝牙鼠标。我还是很相信苹果的,所以先把触控板排除了。然后我关了键盘,发现还是会唤醒。看来大概率就是蓝牙鼠标了。我关了鼠标,只留键盘和触控板。这下没问题了。试了几次,始终都没问题。

我在回想,是不是鼠标的固件升级造成的,因为鼠标的固件更新还挺频繁的。我打开了蓝牙鼠标的web驱动页,不过我还是犹豫了。

我又想了想,可能鼠标移动导致的。因为这两天我看在线视频的时候,选择全屏模式时,经常会遇到进度条忽隐忽现的问题。这个问题就是鼠标放在那里没人碰,也还在抖动。高灵敏的鼠标很容易遇到这个问题。而这个问题大概率是因为鼠标垫脏了的缘故。

我用湿纸巾清洁了鼠标垫。故障排除。

总结

AI提供的不一定对。只能作为参考。所以手动古法处理还是必要的。

如果是Windows,其实直接禁用鼠标移动唤醒就可以了,只保留案件唤醒。但是macOS没有类似的功能,所以只能采用其它的方式。