跳转到内容

自建 Web Chat 三天上线:从想法到部署的全过程

📍 真实案例 2/5 · 上一篇:← 我家有一窝 Claude bot

一个浏览器窗口里有简洁的聊天界面,顶部带 PIN 锁标识

那是个普通的周二。洁柔在地铁上想跟家里的 bot 聊一句,但 Telegram 国内不稳定——半数时候连不上,连上了发消息也偶尔吞包。

她在 Notes 里写了一行:

“能不能搞个网页版?域名直接打开就用,不用装客户端、不用翻墙。”

我(小牛)接到这条需求后,3 天后 chat.你的域名.com 上线。

读完这一篇你会知道:怎么从一个 30 字的需求 → 一个真实跑在生产的网页 chat,而且3 天就能搞完。

网页聊天界面 + Telegram + Web Chat 两个 channel 并行示意

3 天后的样子:

  • URL:chat.你的域名.com(走 Cloudflare Tunnel,国内直连)
  • 6 位 PIN 守门——你自己设一个 PIN,够用
  • 跟 Telegram 平行——同样的 bot 集群,同样的人格,两个入口任选
  • 支持文件附件(上传图片、PDF、Excel 直接发给 bot)
  • 整段回复(bot 想清楚再一段送达,不是 ChatGPT 那种一字一字流——简单稳定)
  • 响应式(手机 / 平板 / 桌面都干净)

源码:已开源到 github.com/GeraldYa/claude-web-chat,你直接 fork 一份就能跑。

3 天时间线 1 蓝图 / Day 2 接通 / Day 3 上线

目标:浏览器打开能聊一句,bot 能回。其他一切先放。

我做的事:

  1. 挑技术栈(45 分钟)——前端纯 HTML + Vanilla JS(没用 React 因为不需要),后端 Bun 起 WebSocket gateway
  2. 写 server.ts(2 小时)——Bun 起 fetch 路由 + WebSocket 双向通道
  3. 写前端 chat.html(2 小时)——一个 input + 一个聊天框 + 一个 send 按钮
  4. 接通 Claude Code 后端(2 小时)——通过 claude-code-channels 插件协议,Web Chat 注册为一个 channel
  5. 本地跑通(1 小时)——浏览器打开 localhost:3100,发”你好”,bot 回”你好”

Day 1 结束:本地能聊。没样式、没鉴权、没部署。但核心通路打通了

Day 2:鉴权 + 体感打磨 + 文件上传(8 小时)

Section titled “Day 2:鉴权 + 体感打磨 + 文件上传(8 小时)”

目标:别人不能随便打开,体验跟 ChatGPT 那种平滑。

我做的事:

  1. 加 PIN 鉴权(1 小时)——6 位 PIN,服务端检查,Cookie 记 24 小时
  2. 优化交互体感(2 小时)——「正在思考」加载状态、reply 到达整段渲染、滚动定位、emoji 反应
  3. 加文件上传(2 小时)——multipart 拖拽上传,服务端存到 ~/.claude/channels/web-chat/uploads/
  4. 样式打磨(2 小时)——配色用 niuxue 主题暖橙,圆角 + 头像 + 间距细抠
  5. 响应式适配(1 小时)——手机 / 平板 / 桌面三档断点

Day 2 结束:本地体验干净、操作流畅,跟主流 chat 站接近(差距是没流式 token,这一档没做)。

Day 3:部署 + Cloudflare Tunnel + 公网(6 小时)

Section titled “Day 3:部署 + Cloudflare Tunnel + 公网(6 小时)”

目标:绑域名 chat.你的域名.com,国内直连不翻墙

我做的事:

  1. Docker 化(1 小时)——把 server.ts 打包成 image,扔进 NAS 的 claude-workspace 容器
  2. Cloudflare Tunnel 配域名(1.5 小时)——svc-tunnel 容器跑 cloudflared,绑 chat.你的域名.com → localhost:3100
  3. DNS 配置(30 分钟)——Cloudflare DNS 加 CNAME 记录,绑 tunnel
  4. HTTPS 自动(0 分钟)——Cloudflare 自动签证书,什么都不用做
  5. 端到端验证(2 小时)——在手机上 / 在公司网络 / 在咖啡馆 wifi,都能直接打开 chat.你的域名.com 进 PIN 用
  6. 开源到 GitHub(1 小时)——清理 secret、写 README、推上去

Day 3 结束:生产可用 + 开源仓库已发布

架构图 → WebSocket gateway → Claude Code AI brain,三层

组件选型为什么
框架没用框架——Vanilla HTML + JS整个项目 < 800 行代码,React 全家桶反而是包袱
样式手写 CSS,无 Tailwind一个文件搞定,改起来快
实时推送WebSocketbot 回复后 gateway 整段推给浏览器,渲染一次到位
上传原生 FormData + drag-drop不依赖任何库
组件选型为什么
运行时Bun(不是 Node)Bun 启动快、自带 TS 编译、内存少
路由手写 fetch 路由没用 Express——20 行手写更轻
AI 接口Claude Code Channels Plugin标准协议,跟 Telegram channel 用同一套
存储本地 JSON 文件个人项目不用上数据库
组件选型为什么
容器Docker (host network)跟 claude-workspace 共一个容器
公网穿透Cloudflare Tunnel不开端口、零防火墙配置
域名 / DNSCloudflare反正都在 Cloudflare 一站式
HTTPSCloudflare 自动不用手动跑 certbot

总成本:

  • 域名 你的域名.com:已经有的(每年 ~100 元)
  • Cloudflare Pages / Tunnel:0 元
  • 运行成本(电费):忽略不计
  • 模型 API:走 DeepSeek,跟现有 bot 一起算

绝对成本基本就是域名钱

PIN 守门 + 网页聊天入口示意

整个 3 天,我没有手写过一行代码——全是跟 Claude Code 说人话,它写。

举几个具体瞬间:

我说:

“我要做一个网页 chat,前端简单,后端要能接 Claude Code 的 channel 协议,体验要像主流 chat 站那样平滑。建议技术栈?要简单、3 天能上线。”

Claude 给了 3 个方案对比(React+Express / Vue+FastAPI / Vanilla+Bun),列了每个的复杂度跟交付时间。我们选 Vanilla+Bun——Claude 自己分析说”800 行内的项目,框架是负债”

瞬间 2:Day 1 下午,WebSocket 双向通道

Section titled “瞬间 2:Day 1 下午,WebSocket 双向通道”

我说:

“Gateway 跟浏览器之间用 WebSocket 推送 inbound message,outbound 走 HTTP POST。给我最小可跑骨架。”

Claude 写了 30 行——server 端开 /ws upgrade、客户端 new WebSocket(...) + onmessage 渲染气泡。复制粘贴跑通,后续优化都基于这套骨架。

我说:

“做 PIN 鉴权。要简单——用户输 6 位 PIN,正确给 cookie 24 小时,错的不给。别太复杂,不用 JWT 那种。”

Claude 写了一个 7 行的中间件——读 cookie、验 PIN、签名简单的 HMAC token。比我自己想得简洁多了

我说:

“我想绑 chat.你的域名.com 到这个 server。我已经有 你的域名.com 这个域名 in Cloudflare。该怎么搞?”

Claude 生成了一份完整的 config.yml(cloudflared 配置)、写好了 DNS 记录的 CNAME给了 docker-compose 启动命令。我抄过去 1 分钟搞定。

整个 Day 3 部署阶段——我做的事就是把 Claude 给的命令复制粘贴

❌ 坑 1:WebSocket 连接被中间代理踢

Section titled “❌ 坑 1:WebSocket 连接被中间代理踢”

Day 2 测试时,WebSocket 偶尔连一会就断——某些网络环境下 idle 连接会被代理回收。

修复:服务端开 15 秒心跳 ping,前端收到 ping 立即 pong,保活成功。Cloudflare Tunnel 转发 WebSocket 流量也需要在配置里把 no_tls_verifyconnect_timeout 调过。

📚 troubleshooting 这套也写进去了。

❌ 坑 2:文件上传遇到中文文件名乱码

Section titled “❌ 坑 2:文件上传遇到中文文件名乱码”

Day 2 测试中文文件名(简历.pdf)上传,服务端存进去变成了一堆乱码

原因:multipart 默认按 latin-1 解码 filename。

修复:服务端解析 multipart 时,显式按 UTF-8 解码 filename 字段。3 行代码搞定。

❌ 坑 3:Cloudflare Tunnel 第一次绑域名,DNS 走的是 wildcard

Section titled “❌ 坑 3:Cloudflare Tunnel 第一次绑域名,DNS 走的是 wildcard”

Day 3 绑 chat.你的域名.com 时,Cloudflare 显示**已经存在一条 .你的域名.com 的 wildcard 记录*——chat 被它覆盖了。

修复:把 wildcard 那条 DNS 改成”非代理”(灰云),tunnel 单独加 chat 这条 CNAME(橙云)。先具体后泛化

Day 3 准备 push 到 GitHub 时,Claude 提醒:.env 里有 DeepSeek API key,要不要先清?

我说要,它自动 grep 了所有 secret 关键词,生成了一份 .gitignore,并建议加 git pre-commit hook 永久防止 leak

这一脚没踩——但要是没 Claude 提醒,我可能就直接 push 了。

一个 GitHub-octocat 收到礼物,小社区围在旁边

已经开源:github.com/GeraldYa/claude-web-chat

clone 下来你需要改:

  • config.yml:你自己的 Cloudflare Tunnel UUID + 域名
  • .env:你的 PIN + bot 集成方式
  • chat.html:换你自己的色系 / Logo(可选)

门槛:

  • 你需要会基本的 Docker(docker-compose up)
  • 你需要有一个域名(任意 DNS 服务,Cloudflare 最省事)
  • 你需要有一个能上 Claude Code 的环境(NAS / VPS / 家里的旧电脑都行)

不需要会:

  • 前端框架 / 后端框架(没用)
  • 部署运维(Cloudflare Tunnel 帮你搞定)
  • HTTPS 证书(自动)
维度TelegramWeb Chat
入口装客户端 / 网页版直接打开网址
国内访问不稳定 / 需要工具完全稳定(Cloudflare 直连)
文件上传50MB 单文件限制自己定(50-200MB)
历史Telegram 服务器保存本地保存(隐私好)
多端手机 + 桌面任何浏览器
群组 / 频道✅ 原生支持❌ 不做(目前)
通知✅ 推送通知❌ 浏览器关了就没了

实际用法:

  • 在家 / 公司:Web Chat(打开浏览器就能用)
  • 在外面 / 通勤:Telegram(手机锁屏推送)
  • 协作 / 分享:Telegram(可以转发)

两个互补,不替代

最后说一个反直觉的事——这种”3 天上线”在 AI 时代之前是不可能的

  • 2024 之前,我至少要花 1-2 周:学新框架、查 WebSocket 文档、配 Cloudflare Tunnel、调样式 bug…
  • 2026 现在:Claude Code 在每一步替我做研究 + 写代码 + 排错,我做的是产品判断 + push 节奏

这才是 AI 工具的真正价值——不是替代你思考,是替代你做”已知怎么做但费时间”的事

普通人用 Claude Code 一周做出一个能用的小工具,是新常态,不是天才特权

接下来还有:

niuxue.org 是怎么搭起来的:本站自身案例(等站长大再开篇)

工时表助手 / E-ink Dashboard:一周两个 AI 落地小工具

MoldPage:把”找工作的痛”做成产品的两周

想第一时间收到,可以收藏 niuxue.org 主页。


你用 Claude Code 一周搞出来过什么?把项目链接发邮箱 [email protected],我们会精选放进「真实落地案例集」。

评论

不记名、不需要注册——不要邮箱,不要手机号,不要任何身份信息,填个昵称就能留言。放心说。

  • 加载中 …