无需开放任何端口,在任意浏览器里访问你的电脑文件。
桌面端主动向外连接中继服务器——无需端口转发、无需 VPN、无需公网 IP。 访客输入 8 位 PIN 码即可共享文件,会话随用随吊销。
RemoteBridge 采用中继服务器架构:运行在你电脑上的 Electron 桌面应用(Host 端)主动向公网中继服务器建立 WebSocket 出站连接;网页客户端连接到同一中继,中继按会话 ID 将消息在两端之间转发。
Web 浏览器 ──────► 中继服务器 ◄────── 桌面 Host(你的电脑)
(任意设备) (云端 VPS) (Electron 应用)
你的电脑始终不对外监听任何端口,NAT 和防火墙天然穿透。
- 远程办公 —— 在家访问公司电脑文件,无需 VPN 客户端
- 大文件传递 —— 共享 PIN 码让对方直接取走文件,不经过第三方云存储
- 家庭服务器远程访问 —— 从任意浏览器访问家中 NAS/服务器,无需路由器端口映射
- 开发协作 —— 测试/设计师直接预览构建产物,无需 SSH 权限
- 小团队协作 —— 无需 Active Directory 或共享驱动器,按需生成 PIN 码,用完吊销
- 教育/实验室 —— 远程获取工作站文件,无需将 RDP/SSH 暴露在公网
| 特性 | 说明 |
|---|---|
| 🔌 零配置连接 | 桌面端仅发起出站连接,无需端口转发、VPN、动态 DNS |
| 🔑 PIN 码配对 | 8 位短效 PIN 码(默认 5 分钟,可配置至 24 小时),浏览器输入即连;HMAC 索引查找 O(1) 认证 |
| 🖥️ 内置本地 Relay | 桌面端内置一键启动/停止的 Relay 服务器,无需单独部署 |
| 特性 | 说明 |
|---|---|
| 📁 文件浏览与下载 | 白名单目录浏览,HTTP Range 断点续传,256 KB 二进制帧流式传输 |
| 📤 流式文件上传 | 浏览器 → Host 端二进制分块流式传输(File.stream + 自描述帧),原子写入,并发配额 5 / 单文件 100 MB |
| 👁️ 浏览器内预览 | 图片、PDF、文本文件预览,PDF 在沙盒 iframe 中打开;大文件(>50 MB)自动分片加载前 1 MB |
| ⚡ V2 传输引擎 | 有状态传输生命周期(取消/背压/完整性校验),端到端背压反馈至磁盘读取;运行时 WS 消息 schema 校验 |
| 特性 | 说明 |
|---|---|
| 🔒 会话管理 | 桌面端即时吊销任意客户端会话,旧 token 即刻失效 |
| 🛡️ 主动内容隔离 | HTML/SVG 等主动内容强制下载附件,永不内联执行;PathGuard V2(最长匹配/审计日志/Windows 规范化/TOCTOU 缓解) |
| 🔗 不透明资源句柄 | 文件路径不再出现在 URL 中,Relay 签发带 TTL 的 opaque resourceId |
| 特性 | 说明 |
|---|---|
| 💬 实时消息 | 持久化消息历史,WebSocket 不可用时自动回退 REST |
| 📊 安全审计 | 所有文件访问(允许/拒绝)记录到审计日志,Web 端可查看 |
| 🔄 自动更新 | 桌面端启动时检查 GitHub Releases 新版本 |
| 🐳 完全自托管 | Docker Compose 一条命令部署,Caddy 自动 TLS |
| 🛡️ 生产级安全 | httpOnly Cookie 令牌、CSP、非 root 容器、资源限制、安全响应头 |
# 克隆仓库
git clone https://github.com/Aswellle/RemoteBridge.git
cd RemoteBridge
# 生成 JWT 密钥
openssl rand -base64 48 # 第一个 → JWT_SECRET
openssl rand -base64 48 # 第二个 → JWT_REFRESH_SECRET
# 编辑 .env,填入密钥和域名
cp .env.example .env
# 启动全部服务
docker compose up -d启动后访问 https://<你的域名>,Caddy 自动申请 Let's Encrypt 证书。
包含三个服务:
server—— 中继服务器(SQLite 持久化,非 root 运行,资源受限)web—— Next.js 客户端(独立构建,健康检查)caddy—— TLS 反向代理(自动 HTTPS,完整安全响应头)
# 一键初始化
git clone https://github.com/Aswellle/RemoteBridge.git
cd RemoteBridge
bash scripts/setup.sh
# 配置服务端环境变量
cp apps/server/.env.example apps/server/.env
# 编辑 .env,填入 JWT_SECRET、JWT_REFRESH_SECRET、ALLOWED_ORIGINS
# 启动所有服务(热更新)
pnpm dev
# 中继服务器 → http://localhost:3002
# 网页客户端 → http://localhost:3000
# 桌面应用 → Electron 窗口单独启动各服务:
pnpm --filter @remotebridge/server dev # 仅中继服务器
pnpm --filter @remotebridge/web dev # 仅网页客户端
pnpm --filter @remotebridge/desktop dev # 仅桌面 Host桌面端 Native 模块说明
better-sqlite3必须针对 Electron ABI 编译。如果桌面应用崩溃并提示NODE_MODULE_VERSION不匹配:# Windows .\scripts\dev-desktop.ps1# macOS / Linux cd apps/desktop && npx @electron/rebuild -f -w better-sqlite3 && cd ../..
从 Releases 下载最新安装包。安装后打开「设置 → 本地中继服务器」,点击「启动」即可在本地运行 Relay,无需单独部署云服务。
# 在 .env 中设置域名和密钥,然后:
docker compose up -d生产环境加固:
- 所有容器以非 root 用户(uid 1001)运行
- 资源限制:server ≤1 CPU / 512 MB,web ≤0.5 CPU / 256 MB
- 日志轮转:
max-size: 10m,max-file: 3~5 no-new-privileges:true阻止容器提权depends_on使用condition: service_healthy,服务就绪后才接受流量- Caddy 补全 HSTS、X-Content-Type-Options、X-Frame-Options、Referrer-Policy、Permissions-Policy 安全头
bash scripts/deploy-server.sh # tsc 编译 → systemd 运行systemd 单元文件:deploy/systemd/remotebridge-server.service
健康检查:GET /health 返回中继状态、数据库写入探针结果及各表行数。
从 Releases 下载,或本地构建:
pnpm --filter @remotebridge/desktop package:win # Windows NSIS 安装包
pnpm --filter @remotebridge/desktop package:mac # macOS DMG (arm64)
pnpm --filter @remotebridge/desktop package:linux # Linux AppImage🖥️ 桌面 Host(Electron 29)
- 主进程:Electron 29 · Node 20
- 本地文件服务器:Fastify · 每传输 AbortController 取消
- 数据存储:better-sqlite3
🔗 中继服务器
- HTTP/WS 服务:Fastify ·
@fastify/websocket - 数据持久化:better-sqlite3 · Drizzle ORM
- 传输引擎:V2 Transfer Engine 状态机(取消/背压/完整性校验)
🌐 网页客户端
- 框架:Next.js 15 App Router · Tailwind CSS
- 状态管理:6 个专注 Zustand Store(transfer/session/file/preview/message)
📦 共享协议层
- 协议类型:TypeScript 接口 · 运行时消息校验器 · 路径安全校验
- 传输模块:V2 Transfer Engine(TransferRecord / BaseTransferManager)· 不透明资源句柄
🛠️ 工程化
- 构建:pnpm workspaces · Turborepo · electron-vite
- 测试:Vitest · happy-dom
- 实例身份:启动时生成 UUID,/health 端点暴露
instance_id
当前约束:
- 单实例部署:一个 Relay 服务处理所有 WS 连接和文件代理
- 实例身份:通过
RB_INSTANCE_ID环境变量指定,或启动时自动生成 UUID /health响应包含instance_id,用于负载均衡器区分实例- 水平扩展需 Redis 化房间状态(未来工作,当前无计划)
反向代理配置(单实例 + Caddy/Nginx):
# Nginx 示例:WebSocket 长连接 + 文件代理
location /ws {
proxy_pass http://127.0.0.1:3002;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 3600s;
}
location /api/v1/proxy {
proxy_pass http://127.0.0.1:3002;
proxy_buffering off;
proxy_read_timeout 300s;
}| 文档 | 说明 |
|---|---|
| 生产环境部署与使用指南 | Docker 部署、Caddy 配置、运维速查、故障排查 |
| 使用说明书 | 用户操作手册 |
| CHANGELOG | 版本变更记录 |
| AGENTS.md | 项目开发指南(AI 辅助开发) |
| ADR | 架构决策记录 |
- 路径校验:每次文件操作前,路径经过用户配置的白名单和系统敏感目录黑名单双重校验;PathGuard V2 最长路径匹配支持嵌套允许目录,符号链接解析后校验,防止目录穿越;Windows 路径大小写不敏感规范化;TOCTOU 竞争缓解
- PIN 码认证:bcrypt 哈希存储 + HMAC 部分索引实现 O(1) 连接查找,替代 O(n) 全表扫描
- 下载令牌:一次性 UUID,绑定请求方
clientId,30 分钟过期 - 不透明资源句柄:文件路径不再出现在 URL 中,Relay 签发带 TTL 的一次性
resourceId,彻底消除 URL 中的路径泄露风险 - JWT 分离:访问令牌(2 h)与刷新令牌(30 d)使用独立签名密钥;刷新令牌携带
use: 'refresh'声明,WebSocket 连接时拒绝 - httpOnly Cookie:网页客户端令牌存储在
HttpOnly; SameSite=StrictCookie 中,JavaScript 不可读,防御 XSS 凭据窃取 - Electron 沙盒:渲染进程
sandbox: true+ 严格 CSP;PDF 预览使用无allow-same-origin的沙盒 iframe - 生产加固:
trustProxy: true(反向代理后限流按真实 IP 计数)、1 MB 请求体上限、非 root 容器、资源限制、安全响应头 - V2 传输安全:有状态传输生命周期(取消/背压/完整性校验),端到端背压反馈至磁盘读取;严格 Range 语义(416 拒绝不可满足范围);运行时 WS 消息 schema 校验;协议校验器保留全部附加字段防止路由信息丢失
- 主动内容隔离:HTML/SVG 等主动内容强制下载附件,永不内联执行;主机文件服务端 CSP sandbox + X-Content-Type-Options + Referrer-Policy
四个包均有 Vitest 测试套件。服务端套件自动在 :3099 启动中继,无需手动准备:
pnpm --filter @remotebridge/shared test
pnpm --filter @remotebridge/server test # 自动启动中继于 :3099
pnpm --filter @remotebridge/desktop test
pnpm --filter @remotebridge/web test每次推送和 Pull Request 触发完整 CI(构建 → 类型检查 → Lint → 测试),由 .github/workflows/ci.yml 定义。
推送版本 tag 触发发布流水线:
git tag v2.0.0
git push origin v2.0.0- Fork 并克隆仓库
- 执行
bash scripts/setup.sh安装依赖 - 修改代码 —— 编辑 shared 包后需重新构建(
pnpm --filter @remotebridge/shared build) - 确保测试通过:
pnpm --filter @remotebridge/server test && pnpm --filter @remotebridge/web test - 向
main分支提交 Pull Request
如果 RemoteBridge 对你有帮助,欢迎给我们一个 ⭐️ Star!
你的每一次支持,都是我们持续改进的动力。
