RemoteCC:基于WebSocket的本地网络远程终端控制方案
1. 项目概述:用手机远程操控你的AI编程伙伴
如果你和我一样,经常在电脑前使用Claude Code进行编程,但又不希望被束缚在办公桌前,那么今天分享的这个开源项目RemoteCC,绝对能让你眼前一亮。简单来说,它让你能在手机上通过扫描二维码,实时连接并控制运行在你电脑上的Claude Code终端。想象一下,你启动一个耗时较长的代码生成或测试任务,然后就可以拿着手机走到客厅沙发、厨房甚至阳台,随时查看进度、输入指令或进行确认操作。这不仅仅是“远程桌面”的简化版,而是一个专为Claude Code这类交互式AI编码工具设计的、极简的本地网络控制方案。
它的核心价值在于解放物理空间,实现“Vibe Coding”——即不拘泥于固定工位,在更舒适、放松的环境下进行创造性工作。尤其适合那些需要长时间运行、或频繁进行“y/n”确认的AI编码会话。项目完全开源,遵循“本地优先”原则,无需任何API密钥、云服务或复杂配置,所有数据都在你的本地Wi-Fi网络中流转,安全且私密。接下来,我将从设计思路、环境搭建、核心实现到深度使用技巧,为你完整拆解这个项目,并分享我在部署和调试过程中的一手经验。
2. 核心设计思路与架构解析
2.1 为什么是“本地网络+WebSocket”方案?
在构思远程控制方案时,开发者面临几个关键选择:基于云服务中转、点对点直连、或是本地网络桥接。RemoteCC选择了最后者,并基于WebSocket实现,这背后有一系列务实的考量。
首先,完全本地化是首要原则。Claude Code的交互可能涉及代码片段、项目结构等敏感信息。通过云服务器中转会增加不必要的延迟、隐私风险和依赖(万一服务宕机)。而让手机和电脑处于同一Wi-Fi网络下,利用内网IP直接通信,延迟可以低至毫秒级,且数据不出家门,安全感十足。
其次,WebSocket协议是双向实时通信的绝佳选择。与传统的HTTP轮询相比,WebSocket在建立连接后,服务器可以主动向客户端(手机)推送数据(如终端输出),客户端也能随时发送数据(如用户输入),这完美契合了终端交互“一发一收”的实时性要求。相较于更底层的TCP Socket,WebSocket基于HTTP升级,更容易穿越一些家庭路由器的简单防火墙策略,且有许多成熟、稳定的服务端和客户端库(如Node.js的ws库和React Native的WebSocket API)。
最后,二维码配对巧妙地解决了内网IP和端口动态变化带来的连接难题。电脑启动服务时,会生成一个包含当前内网IP、端口和一次性令牌(Token)的二维码。手机扫码后,即可获取所有必要的连接信息,用户无需手动输入任何IP地址。这种“零配置”体验极大地降低了使用门槛。
注意:这种设计也决定了其主要使用场景是同一局域网内,比如家庭、办公室或咖啡馆的Wi-Fi。它并非为跨公网远程控制而设计,这也是其保持简单和安全性的一个主动取舍。
2.2 技术栈选型背后的逻辑
项目的技术栈非常精简且高效,每一部分都承担着明确的核心职责:
服务端 (Node.js +
node-pty)- Node.js: 作为服务端运行时,其非阻塞I/O模型非常适合处理大量并发的终端输入输出事件。npm生态也提供了项目所需的所有关键包。
node-pty: 这是整个项目的“心脏”。它是一个用于创建伪终端(PTY)的Node.js模块。简单来说,PTY是操作系统提供的一个“虚拟终端”,node-pty可以让我们在Node.js程序中像在真实终端里一样,启动一个子进程(如claude-code),并与之进行全双工通信(既能向其发送输入,也能捕获其输出)。没有它,就无法在后台可靠地运行一个交互式命令行程序。
客户端 (React Native Expo)
- React Native: 用于构建跨iOS和Android的原生移动应用。选择它是因为需要访问手机的摄像头(扫码)和实现流畅的UI交互。
- Expo: 这是一个React Native框架,它极大简化了开发、构建和部署流程。对于这样一个工具类项目,使用Expo可以避免处理复杂的原生代码配置,让开发者专注于应用逻辑。用户也只需在手机上安装一个通用的“Expo Go”应用即可运行开发版,无需单独编译安装。
通信层 (
ws+qrcode-terminal)ws: Node.js上轻量级、高性能的WebSocket服务器实现,稳定且资源占用少。qrcode-terminal: 一个在终端中生成二维码的库。它直接将连接信息编码成二维码并以字符画的形式打印出来,无需打开浏览器或依赖图形界面,保持了纯命令行工具的简洁性。
这个技术栈组合在保证核心功能强大的同时,将依赖和复杂度降到了最低,体现了“工具应该简单好用”的哲学。
3. 从零开始的完整部署与实操指南
3.1 环境准备与依赖安装
在开始之前,请确保你的环境满足以下要求。我将以macOS/Linux系统为例,Windows用户只需在命令提示符或PowerShell中执行相应命令,原理一致。
电脑端准备:
- Node.js 18+: 这是运行服务端的基础。打开终端,输入
node --version检查。如果未安装或版本过低,建议通过 nvm (Mac/Linux)或 nvm-windows 来安装和管理Node.js版本,这样可以灵活切换。 - Claude Code: 确保
claude-code命令行工具已正确安装并可在终端中直接运行。通常安装Anthropic官方客户端后会自动配置。 - Git: 用于克隆代码仓库。
手机端准备:
- 在苹果App Store或Google Play商店中搜索并安装Expo Go应用。这是运行我们项目移动端代码的“沙盒”环境。
实操步骤:获取项目代码并安装依赖
打开电脑终端,依次执行以下命令。这里我会解释每一步的作用,让你知其然更知其所以然。
# 1. 克隆远程仓库到本地。这会将GitHub上cducote/remoteCC项目的所有文件下载到你当前目录下的`remoteCC`文件夹中。 git clone https://github.com/cducote/remoteCC.git # 2. 进入项目根目录。这是后续所有操作的起点。 cd remoteCC # 3. 安装服务端依赖。进入`server`目录,`npm install`会读取`package.json`文件,自动下载并安装`ws`、`node-pty`、`qrcode-terminal`等所有必需的Node.js模块到`node_modules`文件夹。 cd server npm install # 安装过程可能会持续几十秒,取决于你的网络速度。 # 4. 安装移动端依赖。回到项目根目录,再进入`mobile`目录执行安装。这里安装的是React Native应用所需的依赖,包括Expo SDK、二维码扫描库、UI组件等。 cd ../mobile npm install踩坑记录:网络与权限问题
- 网络超时:如果
npm install速度慢或失败,可以尝试切换npm源到国内镜像,例如使用npm config set registry https://registry.npmmirror.com。对于移动端依赖,有时需要科学上网环境才能顺利下载某些包。- 权限错误:在Linux/macOS上,如果遇到权限错误(EACCES),切勿使用
sudo npm install,这可能导致后续全局依赖混乱。正确的做法是修复npm的全局安装目录权限,或者使用Node版本管理器(nvm),它默认将包安装在用户目录下,无需sudo。
3.2 启动服务与连接实战
环境就绪后,我们来启动服务并完成首次连接。这个过程分为启动服务器和启动移动端两部分。
第一步:启动RemoteCC服务器
在终端中,确保位于remoteCC/server目录下,然后运行:
npm start这个命令实际上执行的是node src/index.js。你会立刻看到终端里开始打印日志,并很快出现一个由字符组成的二维码,以及一行连接信息,例如:
Server running on: ws://192.168.1.100:3456 Scan the QR code with the RemoteCC mobile app.同时,服务器会在后台启动一个claude-code进程。请保持这个终端窗口打开,它是服务的核心。
第二步:启动移动端应用并连接
打开另一个终端窗口(或标签页),导航到移动端目录:
cd path/to/remoteCC/mobile启动Expo开发服务器:
npm start执行后,你会看到一个Expo的Metro打包器界面在终端打开,同时也会显示一个Expo自身的二维码。注意,这个二维码是用于在手机上加载整个React Native应用代码的,不是用来连接我们刚才启动的RemoteCC服务器的。
在手机上操作:
- 打开手机上的Expo Go应用。
- 使用Expo Go的扫码功能,扫描终端里显示的Expo二维码。稍等片刻,你的手机屏幕上就会加载并显示出RemoteCC的移动端应用界面,通常首先是一个二维码扫描界面。
关键连接步骤:
- 在手机App的扫描界面,用它去扫描第一个终端窗口(运行
npm start的那个)里显示的RemoteCC服务器二维码。 - 扫描成功后,应用会自动尝试通过WebSocket连接到
ws://192.168.1.100:3456这个地址。如果一切顺利,手机屏幕会跳转到一个终端模拟器界面,并且你电脑上claude-code的输出会开始实时滚动显示在手机屏幕上!
- 在手机App的扫描界面,用它去扫描第一个终端窗口(运行
连接成功验证:此时,你在手机输入框里打字并发送,内容会传送到电脑端的claude-code进程,就像在电脑终端里直接输入一样。你可以尝试输入ls或pwd等命令,观察输出是否同步到手机。
3.3 常见启动问题与排查技巧
即使步骤正确,首次运行也可能会遇到问题。下面是我在测试中遇到的典型情况及其解决方法。
| 问题现象 | 可能原因 | 排查步骤与解决方案 |
|---|---|---|
| 手机扫描Expo二维码后,应用白屏或加载失败 | 1. 电脑和手机不在同一网络。 2. 电脑防火墙/安全软件阻止了Expo的默认端口(通常为19000)。 3. Node.js或npm版本不兼容。 | 1.确认网络:确保手机和电脑连接的是同一个Wi-Fi。可以尝试让电脑开手机热点,或者手机开热点给电脑连,这是最可靠的“同一网络”方式。 2.检查防火墙:临时关闭电脑的防火墙(公共网络慎用),或为Expo开发端口(19000, 19001等)添加入站规则。 3.查看终端错误:在运行 npm start的移动端目录终端里,通常会有红色的错误堆栈信息,根据提示解决依赖或语法错误。 |
| 扫描RemoteCC服务器二维码后,提示“连接失败” | 1. 服务器未成功启动或已崩溃。 2. 手机无法访问电脑的内网IP和端口(3456)。 3. 二维码中的IP地址是 127.0.0.1或localhost。 | 1.检查服务器状态:回到服务器终端,看是否有错误日志,确认claude-code进程是否被成功创建。2.验证IP和端口:在手机浏览器(同一Wi-Fi下)尝试访问 http://[电脑IP]:3456(这是一个WebSocket服务,浏览器会报错,但如果是“WebSocket连接错误”而非“无法连接”,说明端口可达)。如果完全无法访问,需检查路由器是否开启了AP隔离,或电脑防火墙是否放行了3456端口。3.修正绑定IP:如果服务器启动时显示的IP是 127.0.0.1,说明它只绑定到了本地回环地址,手机无法访问。需要修改服务器代码,使其绑定到0.0.0.0(所有网络接口)。在server/src/server.js中,查找new WebSocket.Server({ port }),可能需要改为new WebSocket.Server({ host: '0.0.0.0', port }),具体取决于ws库的版本和配置方式。 |
连接成功,但手机屏幕无输出,或claude-code未启动 | 1.claude-code命令在服务器环境PATH中不存在。2. node-pty模块在某些系统上需要编译,可能失败。 | 1.验证Claude Code:在服务器终端(非RemoteCC服务)直接输入claude-code,看能否正常启动。如果不能,需要正确安装Anthropic客户端。2.检查 node-pty安装:在server目录下,查看npm install时的日志,看是否有关于node-pty编译的警告或错误。在macOS上可能需要Xcode命令行工具,在Linux上可能需要python、make、g++等编译工具链。根据错误提示安装相应依赖后,删除node_modules文件夹并重新运行npm install。 |
实操心得:网络诊断小技巧当遇到连接问题时,一个快速诊断的方法是使用
ping和nc(netcat) 命令。在电脑终端,用ifconfig(macOS/Linux) 或ipconfig(Windows) 找到电脑的内网IP(如192.168.1.100)。然后在手机上,如果有终端工具(如Termux for Android),可以ping 192.168.1.100看是否通。接着,在电脑上临时用nc -l 3456监听3456端口,在手机上用nc [电脑IP] 3456尝试建立TCP连接。如果能通,说明网络和端口是可达的,问题可能出在WebSocket服务本身。
4. 核心功能深度使用与定制化
4.1 不仅仅是Claude Code:运行任意命令
RemoteCC的默认行为是启动claude-code,但其架构设计让它能够轻松运行任何命令行程序。这是通过向启动命令传递参数来实现的。
使用方法:在启动服务器时,在npm start后面加上--,然后跟上你想要运行的命令。
# 在 remoteCC/server 目录下 # 示例1:运行一个Python HTTP服务器,并监控其输出 npm start -- python -m http.server 8000 # 示例2:运行一个长时间的构建过程,如Webpack npm start -- npm run build # 示例3:运行一个交互式的Node.js脚本 npm start -- node my-interactive-script.js # 示例4:甚至可以直接启动一个Bash/Zsh shell(注意安全风险) npm start -- bash原理剖析:查看server/src/index.js文件,你会发现启动命令的解析逻辑。npm start最终调用node src/index.js,而process.argv这个数组保存了所有命令行参数。index.js中会检查process.argv中--之后的部分,如果存在,则将其拼接起来作为要执行的命令;如果不存在,则默认使用claude-code。这个被解析出来的命令字符串,最终会传递给node-pty的spawn方法,从而创建对应的子进程。
重要安全提示:由于此功能可以执行任意命令,请务必确保你的RemoteCC服务只在受信任的本地网络环境中运行,避免被恶意连接后执行危险操作。项目本身有一次性Token机制,提供了基础防护,但谨慎总是好的。
4.2 移动端交互优化:快捷按钮与体验提升
项目的移动端App设计了几组“Quick Actions”按钮,这是提升移动端输入体验的关键。在手机小屏幕上频繁输入长命令或特殊按键是非常低效的,这些按钮将常用操作一键化。
- y/n: 直接向终端发送字符
y或n加回车。这在Claude Code或其他CLI工具频繁询问“是否继续?”时极其有用。 - Ctrl+C: 发送中断信号 (
\x03)。用于终止当前运行中的命令,是命令行操作中最常用的快捷键之一。 - Tab: 发送制表符 (
\t)。用于代码补全,在与Claude Code交互时,可以尝试让它补全路径或代码。 - Clear: 发送
clear命令加回车。用于清空手机端的终端屏幕(注意,这只是清空客户端显示,不影响服务器端的实际终端会话)。 - Up/Down: 发送上/下箭头键的转义序列。用于翻阅命令历史。
自定义快捷按钮:如果你想增加更多快捷按钮(例如ls -la,git status,或者你常用的工作流命令),可以修改移动端代码。文件位于mobile/src/screens/TerminalScreen.js。找到定义按钮数组的部分(通常是一个quickActions常量),按照现有格式添加新的按钮对象,指定其显示文本和发送的命令字符串即可。修改后需要重启移动端的Expo开发服务器 (npm start)。
4.3 服务配置进阶:端口与终端尺寸
更改服务端口:默认情况下,RemoteCC服务器使用3456端口。如果该端口已被占用,或者你出于某种原因想更改它,可以使用--port参数。
npm start -- --port 8080启动后,二维码中的连接地址就会变成ws://192.168.1.100:8080。移动端App在扫码时会自动读取这个新端口进行连接。
理解终端尺寸限制:在移动端App的终端界面,你会发现输出文本的换行是固定的,可能看起来有点窄。这是因为项目目前将PTY的尺寸固定设置为80列x30行(这是早期终端常见的尺寸),以兼容大多数移动端显示。这个尺寸定义在服务端的代码中(server/src/server.js里创建PTY时的cols和rows参数)。
为何不动态调整?动态调整终端尺寸(即根据手机屏幕旋转或大小变化,实时通知PTY调整行列数)是一个更复杂的功能,涉及WebSocket双向通信协议的扩展。当前固定尺寸是一个简化实现,保证了基础功能的稳定。这也是项目“Future Enhancements”列表中“Terminal size negotiation”一项想要解决的问题。
5. 项目源码导读与二次开发建议
如果你不满足于基本使用,想了解其内部机制,甚至进行二次开发,这里提供一个简单的源码导读。
5.1 服务端核心流程剖析
服务端的核心逻辑集中在server/src/server.js。
- WebSocket服务器创建:使用
ws库创建一个WebSocket服务器,监听指定端口。 - 连接处理与认证:当有客户端(手机)连接时,会检查URL中携带的Token是否与服务器生成的Token匹配。这是一种简单的会话认证,确保只有扫码的设备才能连接。
- PTY进程创建:一旦认证通过,服务器使用
node-pty.spawn方法创建一个伪终端进程,并执行目标命令(如claude-code)。 - 数据管道桥接:
- PTY -> 客户端:监听PTY进程的
data事件。每当PTY有输出(包括程序打印的文字、颜色码等),就将这些数据通过WebSocket发送给所有已连接的客户端。 - 客户端 -> PTY:监听WebSocket的
message事件。当收到客户端发来的消息(用户输入或快捷命令),就将这些数据写入PTY进程的输入流 (pty.write)。
- PTY -> 客户端:监听PTY进程的
- 生命周期管理:处理客户端断开连接、PTY进程退出等事件,进行资源清理。
5.2 移动端应用结构解析
移动端应用采用经典的React Native + Expo结构,核心交互在两个屏幕之间。
- QRScannerScreen:二维码扫描屏幕。使用Expo的
expo-barcode-scanner库访问摄像头,扫描成功后,解析二维码中的WebSocket服务器地址(WS URL),然后导航到TerminalScreen并传递该地址。 - TerminalScreen:终端模拟器屏幕。
- 连接管理(
services/websocket.js):使用React Native的WebSocket API连接到服务器地址。处理连接打开、接收消息、发送消息、连接关闭等事件。 - 输出渲染:将接收到的原始终端数据(包含ANSI转义序列,如颜色、光标移动)渲染到
Text组件中。目前项目对ANSI码的处理比较基础,复杂格式可能显示异常。 - 输入处理:一个
TextInput用于输入命令,点击发送按钮或键盘提交时,通过WebSocket发送。同时,快捷按钮绑定到预设的命令字符串发送。
- 连接管理(
5.3 潜在的二次开发方向
基于现有架构,你可以尝试以下增强:
- 美化终端输出:集成一个强大的React Native ANSI转义序列渲染库,如
react-native-ansi,让终端输出支持颜色、粗体、下划线等样式,甚至实现语法高亮。 - 实现会话管理:修改服务端,支持同时运行多个独立的PTY会话(如多个
claude-code实例)。移动端可以增加一个会话列表,选择连接不同的会话。 - 添加通知功能:在服务端检测到终端输出中出现特定关键词(如“error”、“finished”、“Press Y/N”)时,通过移动端的推送服务(如Expo Notifications)向手机发送通知,即使用户退出了App也能知晓。
- 支持SSH隧道(高级):通过一个简单的中介服务器或使用内网穿透工具(如ngrok,但需注意安全),实现跨互联网的远程连接。这需要修改连接建立逻辑,并引入更严格的身份验证。
这个项目代码结构清晰,注释良好,是一个学习Node.js后端服务、WebSocket实时通信、React Native移动开发以及终端编程的绝佳实践案例。
