手机 + Tailscale + pi-web 随时随地跑 AI Agent

让 Clash 内嵌 Tailscale 出站,Android 手机不用二选一,既能走代理,又能随时访问家里 Mac mini 上的 pi-web。
杭州
手机 + Tailscale + pi-web 随时随地跑 AI Agent

pi-web 是 pi coding agent 的浏览器界面,我把它跑在家里的 Mac mini 上,平时的项目文件、会话记录和 API key 都在那台机器上。出门在外的时候,想用手机打开它接着干活,而不是只能等回家。

家里的机器本来就组了一张 Tailscale 内网(下称 tailnet),Mac mini、NAS 都在里面。手机只要进了这张网,访问 pi-web 就没有问题。实际配置下来,在 Android 上折腾了几步,这里记录一下最终能用的方案。

让 Clash 同时扮演两个角色

最直接的想法是手机装个 Tailscale 官方 App。但 Android 同一时间只允许启用一个 VPN 应用,而我平时要用 Clash 走代理,两者都要占用这个位置,装上也必须二选一。

既然不能两个 App 各管一头,那就让一个 App 全包。Mihomo(Clash Meta 使用的内核)自带 tailscale 类型的出站,在配置里加一个节点即可:

proxies:
  - name: Tailscale
    type: tailscale
    hostname: android-clash
    state-dir: ./tailscale
    ephemeral: false
    udp: true
    accept-routes: true
    interface-name: wlan0
    ip-version: ipv4-prefer

这样 CMFA 一个 App 同时承担代理和 tailnet 接入,VPN 槽位只被占用一次。它和机场节点是并存的:平时照常选机场节点走代理,只有发往 tailnet 地址(100.64.0.0/10)的流量会被规则自动交给 Tailscale,不需要手动切换。

其中两个参数是必须的:

  • interface-name: wlan0 —— 不指定的话,Android 上内核识别不到默认路由,Tailscale 起不来,日志会刷 magicsock: Rebind IPv4 failed 和 couldn't find ip
  • ip-version: ipv4-prefer —— 手机所处的网络 IPv6 不一定可达,优先 IPv4 可以避开初始化时的卡顿

另外不要给它加 dialer-proxy。我一开始想让这条出站也走代理,加上之后就是前面那个报错,删掉才恢复正常。

补上域名解析

节点配好、Tailscale 也连上之后,用主机名访问还是失败,报 couldn't find ip: mac-mini。

原因是内嵌的 Tailscale 不会把 tailnet 的 MagicDNS 注入 Android 系统,系统不知道这些主机名该解析到哪里。在配置里手工建立对应关系即可:

hosts:
  mac-mini: 100.x.x.x

dns:
  use-hosts: true

把 tailnet 流量交给 Tailscale

域名能解析了,访问 100.x.x.x 仍然不通。这次是分流规则的问题:tailnet 的地址段没有被指给 Tailscale 出站,请求被后面的 GEOIP 或兜底规则接走了。

在 rules 最前面补一条:

rules:
  - IP-CIDR,100.64.0.0/10,Tailscale,no-resolve

100.64.0.0/10 是 Tailscale 使用的地址段,no-resolve 表示直接按 IP 匹配、不做域名解析。这条必须放在所有规则之前。

完整配置

把前面几处合起来,和 Tailscale 相关的部分是:

mixed-port: 7890
mode: rule
log-level: warning

hosts:
  mac-mini: 100.x.x.x

dns:
  enable: true
  ipv6: false
  enhanced-mode: fake-ip
  fake-ip-range: 198.18.0.1/16
  use-hosts: true
  nameserver:
    - 223.5.5.5
    - 119.29.29.29

proxies:
  - name: Tailscale
    type: tailscale
    hostname: android-clash
    state-dir: ./tailscale
    ephemeral: false
    udp: true
    accept-routes: true
    interface-name: wlan0
    ip-version: ipv4-prefer

proxy-groups:
  - name: 节点池
    type: select
    proxies:
      # 平时用的机场节点,Tailscale 不需要放进来

rules:
  - IP-CIDR,100.64.0.0/10,Tailscale,no-resolve
  - GEOIP,CN,DIRECT
  - MATCH,节点池

几个容易出错的地方:

  • 不要给 Tailscale 出站加 dialer-proxy
  • interface-name 和 ip-version 不能省
  • hosts 配合 use-hosts 用来补 MagicDNS
  • 100.64.0.0/10 那条规则必须在最前面
  • state-dir 不要随意清除,删掉后需要重新登录 tailnet

现在的效果

不需要做任何切换,手机照常用原来的机场节点上网;访问家里 tailnet 里的地址时,流量会自动走 Tailscale:

  • 打开 http://mac-mini:30141 使用 pi-web(pi-web 监听在所有网卡上),让家里的 Mac mini 接着处理任务
  • 手机上选一份本地 PDF 上传,家里的 agent 直接读取文件内容
  • 其它机器上的 Web 服务,通过它们在 tailnet 里的地址同样可以直接打开