<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>SSH on 大卷学长的博客</title><link>https://blog.liurb.org/tags/ssh/</link><description>Recent content in SSH on 大卷学长的博客</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><lastBuildDate>Tue, 27 Oct 2026 15:20:05 +0000</lastBuildDate><atom:link href="https://blog.liurb.org/tags/ssh/index.xml" rel="self" type="application/rss+xml"/><item><title>我的移动办公 vibe coding</title><link>https://blog.liurb.org/posts/2026/10/27/vibe-coding-mobile/</link><pubDate>Tue, 27 Oct 2026 15:20:05 +0000</pubDate><guid>https://blog.liurb.org/posts/2026/10/27/vibe-coding-mobile/</guid><description>&lt;img src="https://blog.liurb.org/images/posts/2026/vibe-coding-mobile_cover.png" alt="Featured image of post 我的移动办公 vibe coding" />&lt;h1 id="我的移动办公-vibe-coding">我的移动办公 vibe coding
&lt;/h1>&lt;p>现在大部分编码任务我都是丢给 Claude Code 或者 Codex 去做。一句话把需求说清楚，它自己读文件、改代码、跑测试、修报错，中间会停下来问几次，剩下的时间我基本只是等结果。人干的活变成了按几个确认键，加最后看一眼它到底改成了什么样。&lt;/p>
&lt;p>这件事改变的不只是效率。以前要干活必须坐在那台机器前面，现在只要能看到那个终端、能按那个 y/n 就行。位置没那么重要了，重要的是那个会话还活着。&lt;/p>
&lt;p>&lt;img src="https://blog-worker.liurb.org/api/2026/10/vibe-coding-mobile-flow-20261027-154053.png"
loading="lazy"
alt="手机经 Tailscale 连回电脑，接管 tmux 会话的链路示意"
>&lt;/p>
&lt;h2 id="手机上都在干什么">手机上都在干什么
&lt;/h2>&lt;p>出门前把任务挂上，通常是一句「把 user 模块的参数校验抽出来，测试跑绿了再告诉我」。然后关掉终端，人走开。地铁里掏出手机看一眼，它正停在一个 diff 确认上，点一下回车，继续往下跑。到站的时候事情已经做完了。&lt;/p>
&lt;p>晚上躺床上是另一种。睡前让它跑一遍全量测试，或者把一批 lint 报错清掉，手机放枕头边上，困了就不看了。第二天早上翻一下它昨晚做了什么，哪一步没跑通，补一句话让它重来。&lt;/p>
&lt;p>出差只带一台平板也是这套。机器留在家里开着，连回去，里面该跑的还在跑，接着刚才那条命令往下说就行。&lt;/p>
&lt;p>这三个场景对带宽的要求都不高，但有一条是共同的，人不在机器前面，而那个进程得一直活着。普通 SSH 恰恰做不到这一点，手机锁屏、切一次网、进一次隧道，连接断了，终端里的进程跟着收到 &lt;code>SIGHUP&lt;/code>，之前跑的那半小时一起没。&lt;/p>
&lt;h2 id="移动办公方案">移动办公方案
&lt;/h2>&lt;p>这套方案不用自己写代码，也不用买什么设备，装几个现成的软件就能跑起来。电脑上四样，&lt;code>tmux&lt;/code>、&lt;code>mosh&lt;/code>、&lt;code>openssh-server&lt;/code>、&lt;code>tailscale&lt;/code>。手机上装 Tailscale 的 App，再装一个能连 SSH 的终端 App。&lt;/p>
&lt;p>&lt;code>openssh-server&lt;/code> 让这台电脑可以被远程登录。SSH 是最老资格的远程终端协议，你能在一个终端里操作另一台机器，靠的都是它，mosh 的第一次认证也得走它，所以这个必须装着。&lt;/p>
&lt;p>&lt;code>tmux&lt;/code> 是个终端复用器，说白了就是让程序跑在后台，你把窗口关了它也不死。它把 shell 塞进一个服务端进程，你连上去的只是一个客户端，客户端掉了服务端照跑。手机上看到的画面和电脑上那条终端是同一条，不是另开一个。它只管进程存活，网络通不通跟它没关系。&lt;/p>
&lt;p>&lt;code>mosh&lt;/code> 是 mobile shell 的缩写，定位是 SSH 的移动网络版本。起手还是 SSH，认证完切到 UDP，之后自己维护状态和屏幕内容。断网再连上不是重新协商一整个会话，而是把中间缺的那几帧补回来。手机在 4G 和 WiFi 之间来回切，普通 SSH 基本每次都要重新握手，mosh 通常只是卡一下。代价是服务端要占住 UDP 60000 到 61000，这个后面防火墙得放行，很多人栽在这里。&lt;/p>
&lt;p>&lt;code>Tailscale&lt;/code> 是一个不需要公网 IP 的虚拟内网，底层跑的是 WireGuard。登录同一个账号的设备之间直接能通，每台机器拿一个 &lt;code>100.64/10&lt;/code> 段的地址，手机打开 App 就等于接进了同一个局域网。SSH 只监听在这张虚拟网卡上，公网扫不到 22 端口。以前那套 frp 加端口映射的方案可以收起来了。&lt;/p>
&lt;h2 id="用户名账号和休眠">用户名、账号和休眠
&lt;/h2>&lt;ul>
&lt;li>电脑的登录用户名，以及密码或者一把 SSH 公钥&lt;/li>
&lt;li>同一个 Tailscale 账号，手机和电脑必须是一个，个人版免费额度够用到没感觉&lt;/li>
&lt;li>关掉自动休眠。这一条比装什么都重要，电脑一睡，前面的配置全白费&lt;/li>
&lt;/ul>
&lt;h2 id="ubuntu-和-debian">Ubuntu 和 Debian
&lt;/h2>&lt;p>桌面版 Ubuntu 默认不带 SSH 服务，&lt;code>openssh-server&lt;/code> 要自己装。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">sudo apt update
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo apt install -y tmux mosh openssh-server
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo systemctl &lt;span class="nb">enable&lt;/span> --now ssh
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Tailscale 用官方脚本装最省事，它会自己认发行版。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">curl -fsSL https://tailscale.com/install.sh &lt;span class="p">|&lt;/span> sh
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo tailscale up
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>&lt;code>tailscale up&lt;/code> 会打出一个登录链接，复制到浏览器里登录，这台机器就进网了。然后看它的内网地址。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">tailscale ip -4
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>出来的 &lt;code>100.x.x.x&lt;/code> 记下来，手机连的就是它。开了 ufw 的话把这张虚拟网卡放行，不用去碰公网规则。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">sudo ufw allow in on tailscale0
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="centos-和-rocky-linux">CentOS 和 Rocky Linux
&lt;/h2>&lt;p>CentOS 7 和 8 都已经 EOL，仓库还挂着但不再更新，新机器建议直接上 Rocky Linux 9 或者 AlmaLinux 9。下面的命令在 CentOS 7、CentOS Stream、Rocky、Alma 上都能跑，区别只在 Tailscale 的仓库路径要按系统大版本换。&lt;/p>
&lt;p>mosh 不在标准源里，得先开 EPEL。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">sudo dnf install -y epel-release
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo dnf install -y tmux mosh openssh-server curl
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo systemctl &lt;span class="nb">enable&lt;/span> --now sshd
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>CentOS 7 上把 &lt;code>dnf&lt;/code> 换成 &lt;code>yum&lt;/code>，其余一样。最小化安装一般没带 &lt;code>curl&lt;/code>，所以上面顺手一起装了。&lt;/p>
&lt;p>Tailscale 走官方 yum 源，URL 里的路径按大版本选。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Rocky / Alma / CentOS Stream 9&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo dnf config-manager --add-repo https://pkgs.tailscale.com/stable/rhel/9/tailscale.repo
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo dnf install -y tailscale
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo systemctl &lt;span class="nb">enable&lt;/span> --now tailscaled
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo tailscale up
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>CentOS 7 用 &lt;code>https://pkgs.tailscale.com/stable/centos/7/tailscale.repo&lt;/code>，CentOS 8 用 &lt;code>centos/8&lt;/code>，只换路径。装完同样是 &lt;code>tailscale ip -4&lt;/code> 拿地址。&lt;/p>
&lt;p>真正跟 Ubuntu 不一样的是防火墙。firewalld 默认拦进来的包，mosh 的 UDP 段过不去，最省事的做法是把 &lt;code>tailscale0&lt;/code> 整张网卡丢进 trusted 区域，从这张网卡进来的流量不再过滤。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">sudo firewall-cmd --zone&lt;span class="o">=&lt;/span>trusted --add-interface&lt;span class="o">=&lt;/span>tailscale0 --permanent
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo firewall-cmd --reload
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>不想动 trusted 区域，就至少把 UDP 60000 到 61000 单独放行，具体到 &lt;code>--add-port=60000-61000/udp&lt;/code>。漏了这一步的表现很好认，客户端会打出 &lt;code>Nothing received from server on UDP port 60000&lt;/code>，然后悄悄退回普通 SSH，看着像连上了其实没用上 mosh。SELinux 一般不用动，别顺手把它关了。&lt;/p>
&lt;h2 id="macos">macOS
&lt;/h2>&lt;p>Homebrew 装两个包，&lt;code>openssh&lt;/code> 不用装，系统自带。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">brew install tmux mosh
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>SSH 服务默认是关的。系统设置 → 通用 → 共享 → 远程登录，打开开关，右边把允许访问的用户限定成你自己那个账号，别留「所有用户」。macOS 12 及以前这一步在系统偏好设置 → 共享 → 远程登录。&lt;/p>
&lt;p>Tailscale 在 macOS 上有两个完全不同的装法，别搞混。&lt;/p>
&lt;p>图形版走官网 dmg 或者 &lt;code>brew install --cask tailscale&lt;/code>，装完是菜单栏图标，登录后点菜单就能看到本机 &lt;code>100.x&lt;/code> 地址。它自带的命令行不在 &lt;code>PATH&lt;/code> 里，要用绝对路径调用 &lt;code>/Applications/Tailscale.app/Contents/MacOS/Tailscale status&lt;/code>。我图省事建了个软链过去。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">sudo ln -sf /Applications/Tailscale.app/Contents/MacOS/Tailscale /usr/local/bin/tailscale
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>命令行版是 &lt;code>brew install tailscale&lt;/code>，装的是 &lt;code>tailscaled&lt;/code>，按官方的说法用 &lt;code>sudo brew services start tailscale&lt;/code> 起服务，没有菜单栏图标。不想要菜单栏多一个东西就走这个，代价是偶尔要自己看一眼服务状态。&lt;/p>
&lt;p>macOS 上最容易卡住的不是防火墙，是 &lt;code>PATH&lt;/code>。Homebrew 在 Apple Silicon 上装到 &lt;code>/opt/homebrew&lt;/code>，sshd 给非登录 shell 的 &lt;code>PATH&lt;/code> 里没有这个目录，认证能过，&lt;code>mosh-server&lt;/code> 却起不来。&lt;/p>
&lt;blockquote>
&lt;p>手机上点 mosh 连接，终端报 &lt;code>mosh-server: not found&lt;/code>，就是这个问题。软链到 &lt;code>/usr/local/bin&lt;/code> 就行，那个目录在 sshd 默认 &lt;code>PATH&lt;/code> 里。&lt;/p>&lt;/blockquote>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">sudo ln -sf /opt/homebrew/bin/mosh-server /usr/local/bin/mosh-server
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Intel 的 Mac 上 brew 装在 &lt;code>/usr/local&lt;/code>，一般不会碰上这一条。&lt;/p>
&lt;p>还有休眠。笔记本合盖就睡，软件层拦不住，&lt;code>caffeinate&lt;/code> 只能管住「别自动睡」，管不了合盖那一下。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">caffeinate -dimsu &lt;span class="p">&amp;amp;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>真要长时间挂着任务，要么接一台外接显示器让机器进入合盖不睡的状态，要么就把盖子开着。这个没有更干净的办法。&lt;/p>
&lt;h2 id="windows">Windows
&lt;/h2>&lt;p>Windows 上没有原生的 &lt;code>tmux&lt;/code>，msys2 那套移植版常年有怪毛病，所以这条路是把 WSL2 开起来，&lt;code>tmux&lt;/code>、&lt;code>mosh&lt;/code> 和 Claude Code 全塞进那个 Ubuntu 里，Windows 只负责跑 Tailscale 和当宿主机。&lt;/p>
&lt;h3 id="装-wsl2-和-ubuntu">装 WSL2 和 Ubuntu
&lt;/h3>&lt;p>Windows 11 或者 Windows 10 的 2004 以后版本，一条命令就够，它会自己去打开虚拟化和需要的组件，装完重启。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="n">wsl&lt;/span> &lt;span class="p">-&lt;/span>&lt;span class="n">-install&lt;/span> &lt;span class="n">-d&lt;/span> &lt;span class="n">Ubuntu&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>第一次启动要设 Linux 用户名和密码，这个用户名后面手机登录要用，别顺手打个 &lt;code>root&lt;/code>。&lt;/p>
&lt;h3 id="在-wsl-里装那三样">在 WSL 里装那三样
&lt;/h3>&lt;p>进 Ubuntu 之后，跟前面 Ubuntu 那节一模一样。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">sudo apt update
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo apt install -y tmux mosh openssh-server
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">sudo systemctl &lt;span class="nb">enable&lt;/span> --now ssh
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>&lt;code>systemctl&lt;/code> 报 &lt;code>System has not been booted with systemd&lt;/code> 的话，是这套 WSL 没开 systemd。在 Windows 用户目录建 &lt;code>C:\Users\你的名字\.wslconfig&lt;/code>，写上&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-ini" data-lang="ini">&lt;span class="line">&lt;span class="cl">&lt;span class="k">[wsl2]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">systemd&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">true&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>然后 &lt;code>wsl --shutdown&lt;/code> 再进去。新装的环境一般已经默认开了，只有从旧系统迁过来的才会碰到。&lt;/p>
&lt;p>Claude Code 和 Codex 也装在这个 Ubuntu 里，别装在 Windows 那边。任务跑在 tmux 里，agent 的工作目录、依赖、Node 版本全在同一个环境，省得两边对不上账。&lt;/p>
&lt;h3 id="tailscale-和-wsl-的网">Tailscale 和 WSL 的网
&lt;/h3>&lt;p>Windows 版 Tailscale 从官网下 msi，或者&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="n">winget&lt;/span> &lt;span class="n">install&lt;/span> &lt;span class="n">tailscale&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">tailscale&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>装完登录同一个账号，托盘菜单里能看到本机的 &lt;code>100.x&lt;/code> 地址。麻烦的地方在后面，WSL2 默认躲在一层 NAT 后面，Windows 自己能访问它，从外面进来的包到不了。&lt;/p>
&lt;p>Windows 11 22H2 以后有个干净的解法，在 &lt;code>.wslconfig&lt;/code> 里打开镜像网络，WSL 直接共用 Windows 的网卡，Tailscale 那个 &lt;code>100.x&lt;/code> 地址在 WSL 里也能用。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-ini" data-lang="ini">&lt;span class="line">&lt;span class="cl">&lt;span class="k">[wsl2]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">systemd&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="na">networkingMode&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">mirrored&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>&lt;code>wsl --shutdown&lt;/code> 重进，在 WSL 里 &lt;code>ip addr&lt;/code> 看有没有 &lt;code>tailscale0&lt;/code>。看得到就齐了，手机连 &lt;code>100.x&lt;/code> 的 22 端口，mosh 的 UDP 段也跟着通。防火墙这一侧补一条规则，省得包被静默丢弃。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">New-NetFirewallRule&lt;/span> &lt;span class="n">-DisplayName&lt;/span> &lt;span class="s2">&amp;#34;mosh UDP&amp;#34;&lt;/span> &lt;span class="n">-Direction&lt;/span> &lt;span class="n">Inbound&lt;/span> &lt;span class="n">-Protocol&lt;/span> &lt;span class="n">UDP&lt;/span> &lt;span class="n">-LocalPort&lt;/span> &lt;span class="mf">60000&lt;/span>&lt;span class="p">-&lt;/span>&lt;span class="mf">61000&lt;/span> &lt;span class="n">-Action&lt;/span> &lt;span class="n">Allow&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Windows 10 没有镜像网络这个选项。常见的土办法是用 &lt;code>netsh interface portproxy&lt;/code> 把 22 端口转到 WSL 的内网地址，但 portproxy 只转 TCP，mosh 走的 UDP 转不过去，所以 Windows 10 上只能退一步用普通 SSH 加 tmux，会话照样不断，代价是切网要重连。在 WSL 里单独再装一份 Tailscale 也许能绕过去，这条路我没跑通，先不下结论。&lt;/p>
&lt;h3 id="防睡眠">防睡眠
&lt;/h3>&lt;p>Windows 默认也会睡，笔记本合盖更是直接睡。设置 → 系统 → 电源和电池，把「使设备进入睡眠状态」在插电时改成「从不」；合盖的行为在控制面板 → 电源选项 → 选择关闭盖子的功能里，改成「不采取任何操作」。&lt;/p>
&lt;h2 id="手机端">手机端
&lt;/h2>&lt;p>Tailscale app 装好，登录同一个账号，开着就行，直连还是走中继它自己判断。&lt;/p>
&lt;p>终端 App 挑一个。Android 上用 Termius 或者 JuiceSSH，Termius 的界面好看一些。iOS 上装 Blink Shell，它对 mosh 的支持比 Termius 完整，移动网络下的表现也稳。&lt;/p>
&lt;p>新建连接的时候填四个东西，Host 是刚才那个 &lt;code>100.x.x.x&lt;/code>，端口 22，用户名是电脑上的账号，认证先拿密码跑通，通了再换密钥。协议选 mosh，别用默认的 SSH，不然前面装的服务端白装。&lt;/p>
&lt;p>Claude Code 那个界面在手机上的主要问题是列宽。默认字号下它那几栏信息会折行折得很难看，换成等宽字体，字号压到 10 到 11，横屏使用，看起来就正常了。Termius 里把键盘常驻打开，不然每次点输入框都要弹一遍。&lt;/p>
&lt;!-- 配图：手机 Termius / Blink 横屏接上 tmux 后的 Claude Code 界面（截图） -->
&lt;h2 id="每天的用法">每天的用法
&lt;/h2>&lt;p>电脑上开会话，命令里的 &lt;code>-A&lt;/code> 表示会话已经存在就直接接上，不存在才新建，比每次先 &lt;code>tmux ls&lt;/code> 看一眼再决定 attach 要省事。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">tmux new -A -s claude1
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 在里面跑 claude 或 codex&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 脱离：先按 Ctrl+b，松开，再按 d&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>手机上连上之后，列一下再进去。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">tmux ls
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">tmux attach -t claude1
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;!-- 配图：电脑上 tmux ls 与 attach 的输出（截图） -->
&lt;p>手机端脱离一样是 &lt;code>Ctrl+b&lt;/code> 再按 &lt;code>d&lt;/code>，Blink 和 Termius 都支持把 &lt;code>Ctrl&lt;/code> 组合键映射到工具栏上，不用外接键盘也按得出来。&lt;/p>
&lt;p>用完不收拾的会话会一直挂着占内存，定期清一下。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">tmux kill-session -t claude1
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="容易卡住的地方">容易卡住的地方
&lt;/h2>&lt;p>&lt;code>tmux attach -s xxx&lt;/code> 会报 &lt;code>unknown flag -s&lt;/code>。&lt;code>-s&lt;/code> 是给 &lt;code>new-session&lt;/code> 起名字用的，指定 attach 的目标要用 &lt;code>-t&lt;/code>。这条错在中文教程里非常常见，照抄过来在 tmux 3.x 上直接报错。&lt;/p>
&lt;p>CentOS 上 mosh 连不通，先看 firewalld，再看 EPEL 装没装。表现是客户端打出 &lt;code>Nothing received from server on UDP port 60000&lt;/code> 然后退回 SSH，不报错不提示，很容易误判成连上了。&lt;/p>
&lt;p>macOS 上 &lt;code>mosh-server not found&lt;/code>，就是上面那条 &lt;code>PATH&lt;/code> 的问题，软链一下就好。&lt;/p>
&lt;p>Windows 上最迷惑的一种情况是 Windows 自己能连、手机连不上。多半是 WSL 还躲在 NAT 后面，&lt;code>.wslconfig&lt;/code> 里没开 &lt;code>networkingMode=mirrored&lt;/code>，&lt;code>100.x&lt;/code> 那个地址只在 Windows 那一层有效。先在 WSL 里 &lt;code>ip addr&lt;/code> 看有没有 &lt;code>tailscale0&lt;/code>，没有就是这件事。&lt;/p>
&lt;p>过一晚回来看会话没了，九成是电脑睡了或者重启了。tmux 会话不跨重启，这个是设计如此，不是配置错。&lt;/p>
&lt;p>手机连不上但两边 &lt;code>tailscale status&lt;/code> 都显示在线，去看电脑上的监听地址，&lt;code>ss -lntp | grep :22&lt;/code>。只监听 &lt;code>127.0.0.1&lt;/code> 的话手机永远连不上，得让它监听 &lt;code>0.0.0.0&lt;/code> 或者那个 &lt;code>100.x&lt;/code> 地址。&lt;/p>
&lt;h2 id="安全">安全
&lt;/h2>&lt;p>SSH 只走 tailnet，22 端口不做任何公网映射，这一条守住就避掉了绝大部分爆破。&lt;/p>
&lt;p>tailnet 内部用密码登录问题不大，但手机丢了等于全家丢了，所以还是建议换成密钥，然后关掉密码认证。Tailscale 后台的 ACL 能限定哪个账号连哪台机器，多人共用一个 tailnet 的时候值得配一下，这块我没有细调过，先记在这儿。&lt;/p>
&lt;h2 id="最后说几句">最后说几句
&lt;/h2>&lt;p>会写代码的人用这套，省掉的是「必须守在电脑前」那段时间。任务丢给它，出门，路上批两次确认，回来收结果。写卡住了下楼转一圈，回来它已经把测试跑完，红的地方还列了原因。&lt;/p>
&lt;p>不写代码的人其实更能用上。Claude Code、Codex 这类东西不要求你会语法，把要做的事说清楚就行，改一批文案、把几百个文件按规则改名、从几个表格里拼一份汇总，它自己动手，你只在它问「这样改行不行」的时候回一句。配上这套远程连接，手边那台平板就是工作台，不必是那台装着环境的电脑。少了「你得先学会装环境」这道门槛，移动办公才轮到那些本来不写代码的人。&lt;/p>
&lt;!--
配图清单（共 3 条，另加封面）
截图（自己拍，走 pub 压缩上传）：
1. vibe-coding-mobile-termius 手机 Termius 横屏接上 tmux 后的 Claude Code 界面 → 「手机端」段末
2. vibe-coding-mobile-cmds 电脑上 tmux ls 与 attach 的输出 → 「每天的用法」段
代码绘制（dj-blog-image-gen，落 out/，pub 后压到 1280 宽）：
3. vibe-coding-mobile-flow 已生成并插入，「手机上都在干什么」段之后
封面：
· vibe-coding-mobile_cover 已落 static/images/posts/2026/，frontmatter image 已指向
--></description></item></channel></rss>