free4chat:零注册、临时房间、全服务器化的语音聊天室
> 一句话版本: 打开网页、输入房间名、直接语音聊天。不需要注册、不需要下载、不保留聊天记录。关了浏览器,一切消失。全程跑在 Cloudflare 上,零服务器运维成本。
- 来源: https://github.com/i365dev/free4chat
- 线上服务: https://free4.chat
- 日期: 2026 年活跃开发,多次架构重构后稳定在 Cloudflare 版
- 作者: i365dev(也维护 MyInvestPilot — 系统化量化投资平台)
- 许可: MIT
- Stars: 1,100+
- 技术栈: Next.js 14/15 + Cloudflare RealtimeKit + Workers + KV
项目背景
这是一个极简的实时语音 + 文字聊天服务。核心理念:
> Open a room. Talk instantly. No sign-up. No history. Close the tab and it's gone.
和 Discord / Telegram 不同,free4chat 没有任何持久化逻辑。你不需要账号、不需要下载客户端、不需要信任任何服务器来保存你的聊天记录。
最有意思的部分:三次架构重构
这个项目的 README 首页就讲了它的架构演变史 —— 产品目标从来没变过,但技术栈换了三次。这种诚实的演进记录非常少见。
Phase 1: Go + Pion WebRTC(自托管)
- 语言:Go
- WebRTC 库:Pion
- TURN:coturn
- 问题:自托管基础设施太重。对个人项目来说,维护 WebRTC STUN/TURN 服务器、K8s 部署管道、日志监控...负担远超产品本身的价值。
Phase 2: Elixir + Membrane Framework
- 语言:Elixir(Erlang VM)
- WebRTC 框架:Membrane
- 评估结果:Membrane 后来加了文件传输支持,但仍然需要自己维护服务器集群。
- 问题:规模太小,不值得。
Phase 3: Cloudflare RealtimeKit + Workers(当前)
- 前端:Next.js 14/15 + Tailwind CSS
- 实时媒体:Cloudflare RealtimeKit(WebRTC 媒体平面)
- 部署:Cloudflare Worker(通过 opennextjs 打包)
- 存储:Cloudflare KV(仅 room name → meeting ID 映射,30 天 TTL)
- 结果:完全 serverless,免费层覆盖个人使用,零运维。
经验教训
这个演进路径很有启发性:
Go (太重) → Elixir (还要管服务器) → Cloudflare (刚刚好)
对于个人项目或小团队工具,"全托管 serverless" 越来越成为正确的默认选择 —— 不是因为技术能力不行,而是运维精力应该花在产品价值上,不是服务器上。
技术架构
目录结构
app/
├── src/
│ ├── common/
│ │ ├── consts.tsx # 常量和 ID
│ │ ├── types.tsx # UserInfo, Message, Color 接口
│ │ └── utils.ts # 工具函数
│ ├── hooks/
│ │ └── useChatRoom.ts # 核心 RTK hook(所有会议逻辑)
│ ├── components/
│ │ ├── RoomContent.tsx # 房间布局(参与者网格 + 聊天面板)
│ │ ├── UserCard.tsx # 单个参与者卡片(音视频 + 头像 + 静音)
│ │ ├── AudioVisualizer.tsx # 音频可视化
│ │ └── TextChatCard.tsx # 聊天侧边栏
│ └── pages/
│ ├── index.tsx # 首页/加入房间
│ ├── room.tsx # 动态导入 RoomContent(ssr: false)
│ └── api/
│ └── token.ts # POST /api/token(在 Worker 中运行)
├── wrangler.jsonc # KV binding: ROOMS_KV
└── open-next.config.ts
Cloudflare RealtimeKit 使用模式
项目使用 useRealtimeKitClient(低级 hook)而非高级 React hook。所有 RTK 状态通过 meeting 对象命令式管理:
const [meeting, initMeeting] = useRealtimeKitClient()
// 核心 API
meeting.self.name, .audioEnabled, .enableAudio(), .disableAudio()
meeting.participants.joined.toArray()
meeting.chat.messages, .sendTextMessage(), .sendImageMessage(), .sendFileMessage()
meeting.self.enableScreenShare(), .disableScreenShare()
认证流程
用户输入房间名和昵称
→ POST /api/token { room, name, type }
→ Cloudflare Worker 签发短生命周期 RTK token
→ 用 token 加入 WebRTC 会话
→ 后续通信全是 P2P 或 Cloudflare 媒体中继
Worker 的唯一职责就是签发 token —— 之后没有应用层日志。
隐私设计
这是 free4chat 的真正亮点。README 的 Privacy 部分写得非常清晰:
不存储(绝对安全):
- ❌ 无账户、无注册、无身份系统
- ❌ 消息只存在于浏览器内存中 —— 关掉标签页即消失
- ❌ 文件和图片通过 WebRTC 数据通道传输,从不写入任何数据库
- ❌ 语音通过 Cloudflare 媒体节点中继,但从不录制
少量持久化(安全无害):
- ✅ Room name → meeting ID 映射保存在 KV 中,30 天 TTL。不包含消息、用户、内容
- ✅ 昵称保存在浏览器 localStorage,仅用于自己的便利
- ✅ 可以随时清空
关于"本地优先":
应用完全在浏览器中运行。Worker 的唯一工作是签发短期认证 token 用于加入 WebRTC 会话 —— 之后所有通信是 P2P 或通过 Cloudflare 媒体平面,没有应用层日志。不存在一个能被法院传唤要求交出聊天历史的后端,因为根本没有聊天历史。
功能清单
| 功能 | 说明 |
|---|---|
| 🎙️ 语音聊天 | 实时 WebRTC 音频 |
| 💬 文字聊天 | 带 Emoji 支持 |
| 📎 文件传输 | WebRTC 数据通道,内联预览 |
| 🖥️ 屏幕共享 | RTK 原生支持 |
| 🔒 无需账户 | 输入昵称即刻加入 |
评分
| 维度 | 评分 | 说明 |
|---|---|---|
| 简洁性 | ★★★★★ | 产品设计极简,核心功能完整 |
| 隐私设计 | ★★★★★ | 隐私架构清晰,没有可以传唤的后端 |
| 架构演进 | ★★★★★ | 三次重构的 README 本身就有学习价值 |
| 代码质量 | ★★★★☆ | Next.js + RealtimeKit 模式清晰,有 AGENTS.md |
| 相似项目参考 | ★★★★☆ | 如果你想做一个类似的东西,这是最佳模板 |
| 与我们的关联 | ★★★☆☆ | Cloudflare Workers + RealtimeKit 架构参考,隐私设计思路 |
值得关注的细节
1. 架构演进的 README — 很多项目只展示当前架构,free4chat 把 Go → Elixir → Cloudflare 的失败和转型都写在首页。这种诚实和思考深度在开源项目中很少见。
2. Cloudflare RealtimeKit 的最佳实践 — 这是目前中文社区能找到的为数不多的 RealtimeKit 实际使用参考。AGENTS.md 里把 RTK SDK 的 API 模式、事件模型、权限检查都写得很清楚。
3. "三个架构,同一个产品" — 团队选择 stack 的时候常陷入"选哪个最好"的争论。free4chat 证明:产品目标比技术栈重要得多,而且 serverless WebRTC 方案对于个人项目来说已经是可行路径。
4. 作者背景 — i365dev 也做 MyInvestPilot(量化投资),说明这是一个有金融工程背景的开发者,但他的开源项目选了一个完全不相关的领域 —— 纯技术表达。
一句话总结
> 一个由三次架构重构磨出来的极简语音聊天室 —— 从 Go 自托管到 Elixir 再到 Cloudflare 零运维,最终证明对于个人项目来说,选一个能让你专注产品的方案,比选一个"最牛"的方案重要得多。