一直想搞一个自己的聊天室,不是那种大而全的 IM 系统,就是一个轻量、好看、能跑起来的实时聊天应用。翻了一圈 GitHub,要么太重要么太丑,干脆自己写了一个。
项目地址:https://github.com/EuphonXD/webchat
它能干什么
先说功能,不然你没兴趣往下看:
- 用户注册登录,JWT 认证
- 创建聊天室,支持密码保护
- 一对一私聊
- 实时消息推送,基于 WebSocket
- 输入状态提示(对方正在输入...)
- 在线用户显示
- 自定义 Emoji 表情,支持上传和分组
- 每个聊天室可以设置独立的背景图
- 暗色主题,移动端适配
界面是深色系的,紫色强调色,不算惊艳但至少不丑。
技术栈
没什么花哨的东西,都是久经考验的组合:
- 后端:Node.js + Express + Socket.IO
- 前端:React 18 + Vite + Tailwind CSS
- 数据库:SQLite(用的 better-sqlite3,WAL 模式)
- 认证:JWT + bcryptjs
为什么选 SQLite?因为这是个自托管项目,不想让用户还得装个 MySQL/PostgreSQL。SQLite 单文件搞定,性能对小团队来说绰绰有余。
部署
这是重点。整个项目用 Docker Compose 一把梭,从 clone 到跑起来大概两三分钟。
环境准备
你需要一台 Linux 服务器(虚拟机也行),装好 Docker 和 Docker Compose。Ubuntu/Debian 的话:
# 安装 Docker
curl -fsSL https://get.docker.com | sh
# 检查 Docker Compose 是否可用
docker compose version
如果 docker compose 命令不存在,装一下:
sudo apt install docker-compose-plugin
克隆项目
git clone https://github.com/EuphonXD/webchat.git
cd webchat
配置环境变量
项目里有个 docker-compose.yml,默认配置其实就能跑。但有一项建议改一下:
services:
webchat:
build: .
container_name: webchat
restart: unless-stopped
ports:
- "23777:23777"
volumes:
- webchat-data:/app/data
environment:
- JWT_SECRET=换成你自己的密钥
- PORT=23777
- NODE_ENV=production
volumes:
webchat-data:
driver: local
JWT_SECRET 随便填一串随机字符串就行,别用默认的。端口号 23777 也可以改成你喜欢的。
一键启动
docker compose up -d
第一次启动会比较慢,因为要 build 镜像——下载 Node.js 基础镜像、安装依赖、编译前端。喝杯咖啡等一两分钟就好。
看到容器状态变成 Up 就行了:
docker compose ps
# 应该看到 webchat 容器在运行
访问
浏览器打开 http://你的IP:23777,注册一个账号就能开始用了。
第一次进去是空的,创建一个聊天室,把链接分享给朋友,大家注册后就能一起聊了。
不想用 Docker?
也行,手动跑:
# 安装依赖
npm install
cd client && npm install && npm run build && cd ..
# 启动
node server.js
需要 Node.js 18+。前端构建完会输出到 client/dist,后端会自动托管静态文件。
生产环境建议
反向代理 + HTTPS
裸跑 HTTP 在公网上不安全。推荐用 Nginx 反代并配 SSL:
server {
listen 443 ssl;
server_name chat.example.com;
ssl_certificate /path/to/fullchain.pem;
ssl_certificate_key /path/to/privkey.pem;
location / {
proxy_pass http://127.0.0.1:23777;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# WebSocket 支持,这行不能少
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
重点是那几行 WebSocket 的配置,漏了的话消息实时推送就废了。
SSL 证书可以用 Let's Encrypt 免费申请,宝塔面板或者 certbot 都行。
域名
有域名的话配个 DNS A 记录指向你的服务器 IP,然后 Nginx 的 server_name 改成你的域名就行了。
数据备份
聊天数据都在 Docker volume 里(webchat-data),备份的话:
# 导出
docker run --rm -v webchat-data:/data -v $(pwd):/backup alpine tar czf /backup/webchat-data.tar.gz -C /data .
# 恢复
docker run --rm -v webchat-data:/data -v $(pwd):/backup alpine tar xzf /backup/webchat-data.tar.gz -C /data
SQLite 的 webchat.db 文件在 volume 的 /app/data/ 目录下,直接拷贝出来也行。
项目结构
简单过一下代码结构,方便你想魔改的时候知道去哪找:
webchat/
├── server.js # 入口,Express + Socket.IO 初始化
├── src/
│ ├── db.js # SQLite 数据库 + 所有查询
│ ├── socket.js # WebSocket 事件处理
│ ├── middleware/
│ │ └── auth.js # JWT 认证中间件
│ └── routes/
│ ├── auth.js # 注册/登录/个人资料
│ ├── rooms.js # 聊天室 CRUD
│ ├── messages.js # 消息获取
│ └── emoji.js # 表情 + 背景图
├── client/ # React 前端
│ ├── src/
│ │ ├── App.jsx # 路由配置
│ │ ├── pages/ # Login、Chat 页面
│ │ ├── components/ # 各种 UI 组件
│ │ └── contexts/ # Auth、Socket 状态管理
│ └── package.json
├── docker-compose.yml
├── Dockerfile
└── data/ # SQLite 数据库(自动创建)
踩过的坑
写这个项目的时候遇到了几个值得注意的问题:
- WebSocket 在 Nginx 反代后断连:一定要加
Upgrade和Connection的 header,不然 Socket.IO 会降级成轮询,延迟感人。 - SQLite 并发写入:开了 WAL 模式后好了很多,但别把它当 MySQL 用,高并发写入场景不适合。
- 前端 build 后的静态文件托管:Vite build 产出在
client/dist,需要在 Express 里配置express.static和 SPA fallback。
最后
这个项目不追求大而全,就是一个够用的聊天室。如果你想改着玩、或者需要一个简单的内部沟通工具,可以试试。
有问题或者建议,欢迎到 GitHub 提 Issue。