7ac9a73160
CI / Dashboard (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Test (push) Has been cancelled
CI / Test (PostgreSQL migrations) (push) Has been cancelled
CI / Build (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
415 lines
16 KiB
Markdown
415 lines
16 KiB
Markdown
<!-- WEHUB_ZH_README -->
|
||
> [!NOTE]
|
||
> 本文档由 WeHub 基于上游 README 翻译整理,属于社区翻译,非官方中文文档。
|
||
> [English](./README.en.md) · [原始项目](https://github.com/rmyndharis/OpenWA) · [上游 README](https://github.com/rmyndharis/OpenWA/blob/HEAD/README.md)
|
||
> 原作者、版权与许可证归属以原始项目及本仓库 LICENSE 文件为准。
|
||
|
||
<p align="center">
|
||
<img src="docs/logo/openwa_logo.webp" alt="OpenWA Logo" width="200"/>
|
||
</p>
|
||
|
||
<h1 align="center">OpenWA</h1>
|
||
<p align="center">
|
||
<strong>开源 WhatsApp API 网关</strong>
|
||
</p>
|
||
|
||
<p align="center">
|
||
<a href="#-features">特性</a> •
|
||
<a href="#-quick-start">快速开始</a> •
|
||
<a href="#-documentation">文档</a> •
|
||
<a href="#-api-examples">API</a> •
|
||
<a href="#-contributing">贡献</a>
|
||
</p>
|
||
|
||
<p align="center">
|
||
<a href="https://github.com/rmyndharis/OpenWA/actions/workflows/ci.yml"><img src="https://github.com/rmyndharis/OpenWA/actions/workflows/ci.yml/badge.svg?branch=main" alt="CI"/></a>
|
||
<img src="https://img.shields.io/github/package-json/v/rmyndharis/OpenWA?label=version&color=blue" alt="Version"/>
|
||
<img src="https://img.shields.io/badge/license-MIT-green.svg" alt="License"/>
|
||
<img src="https://img.shields.io/badge/node-22_LTS-brightgreen.svg" alt="Node"/>
|
||
<img src="https://img.shields.io/badge/NestJS-11.x-red.svg" alt="NestJS"/>
|
||
<img src="https://img.shields.io/badge/docker-ready-blue.svg" alt="Docker"/>
|
||
<img src="https://img.shields.io/badge/TypeScript-5.x-3178C6.svg" alt="TypeScript"/>
|
||
</p>
|
||
|
||
---
|
||
|
||
## ✨ 为什么选择 OpenWA?
|
||
|
||
**OpenWA** 是一款免费、开源的 WhatsApp API 网关(Gateway),面向需要完全掌控消息基础设施、且不愿被厂商锁定或遭遇隐藏付费墙的开发者。
|
||
|
||
基于**可插拔架构(Pluggable Architecture)**,OpenWA 允许你通过配置更换数据库引擎(SQLite/PostgreSQL)、存储后端(Local/S3)和缓存层(Memory/Redis),而无需修改应用代码中的任何一行。
|
||
|
||
| | |
|
||
| ----------------------------- | ------------------------------------------------------------ |
|
||
| 🔓 **100% 开源** | 无许可费用、无功能锁定、可访问完整源代码 |
|
||
| 🏗️ **可插拔架构** | 通过配置切换数据库、存储和缓存适配器 |
|
||
| 🖥️ **完整仪表盘** | 现代化的 React UI,用于管理会话、Webhook 和 API 密钥 |
|
||
| 🔹 **多会话就绪** | 在单个实例上并发运行多个 WhatsApp 会话 |
|
||
| 🐳 **原生 Docker 支持** | 开箱即用,可用于生产环境,零配置 |
|
||
| 🔗 **n8n 集成** | 用于工作流自动化的社区节点 |
|
||
| 🧩 **社区适配器** | 第三方集成(例如 ioBroker)— 参见 [文档](./docs/23-community-integrations.md) |
|
||
|
||
---
|
||
|
||
## 🎯 特性
|
||
|
||
### 核心特性
|
||
|
||
| 特性 | 状态 | 描述 |
|
||
| ------------- | ------ | ------------------------------------ |
|
||
| REST API | ✅ | 通过 HTTP 端点提供完整的 WhatsApp API |
|
||
| 多会话 | ✅ | 管理多个 WhatsApp 账户 |
|
||
| Webhook | ✅ | 实时事件,支持 HMAC 签名及可选的智能预分发过滤器 |
|
||
| Web 仪表盘 | ✅ | 可视化管理界面 |
|
||
| API 密钥认证 | ✅ | 安全的 API 身份验证 |
|
||
| Swagger 文档 | ✅ | 交互式 API 文档 |
|
||
|
||
### 消息
|
||
|
||
| 特性 | 状态 | 描述 |
|
||
| ----------------- | ------ | -------------------------------- |
|
||
| 文本消息 | ✅ | 发送/接收文本消息 |
|
||
| 媒体消息 | ✅ | 图片、视频、文档、音频 |
|
||
| 消息回应 | ✅ | 使用表情符号回应消息 |
|
||
| 批量消息 | ✅ | 向多个收件人发送 |
|
||
| 消息状态 | ✅ | 跟踪送达和已读回执 |
|
||
|
||
### 高级功能
|
||
|
||
| 特性 | 状态 | 描述 |
|
||
| ------------------- | ------ | ---------------------------------- |
|
||
| 群组 API | ✅ | 创建、管理群组并发送消息 |
|
||
| 频道/Newsletter | ✅ | 支持 WhatsApp 频道 |
|
||
| 标签管理 | ✅ | 使用标签整理聊天 |
|
||
| 代理支持 | ✅ | 按会话配置代理 |
|
||
| 速率限制 | ✅ | 可配置的请求限制 |
|
||
| CIDR 白名单 | ✅ | 基于 IP 的访问控制 |
|
||
| 审计日志 | ✅ | 跟踪所有 API 操作 |
|
||
|
||
### 基础设施
|
||
|
||
| 特性 | 状态 | 描述 |
|
||
| ---------------- | ------ | ------------------------------ |
|
||
| SQLite | ✅ | 零配置嵌入式数据库 |
|
||
| PostgreSQL | ✅ | 生产级数据库 |
|
||
| Redis 缓存 | ✅ | 可选的性能缓存 |
|
||
| S3/MinIO 存储 | ✅ | 可扩展的媒体存储 |
|
||
| Docker | ✅ | 一条命令完成部署 |
|
||
| 健康检查 | ✅ | 适用于 Kubernetes 的探针 |
|
||
| 数据迁移 | ✅ | 在后端之间导出/导入 |
|
||
|
||
---
|
||
|
||
## 🚀 快速开始
|
||
|
||
### 方案 A:Docker(推荐)
|
||
|
||
```bash
|
||
# Clone and start
|
||
git clone https://github.com/rmyndharis/OpenWA.git
|
||
cd OpenWA
|
||
docker compose -f docker-compose.dev.yml up -d
|
||
|
||
# Access (the dashboard is bundled into the API image and served on the same port)
|
||
# Dashboard: http://localhost:2785
|
||
# API: http://localhost:2785/api
|
||
# Swagger: http://localhost:2785/api/docs
|
||
```
|
||
|
||
> **使用 Podman 而非 Docker?**
|
||
> Podman 无 root 模式需要 socket 正在运行,并设置 `DOCKER_HOST`:
|
||
>
|
||
> ```bash
|
||
> systemctl --user start podman.socket
|
||
> systemctl --user enable podman.socket
|
||
> export DOCKER_HOST=unix:///run/user/$(id -u)/podman/podman.sock
|
||
> ```
|
||
>
|
||
> 将 `export` 这一行添加到你的 `~/.bashrc` 中,以使其永久生效。
|
||
|
||
### 方案 B:本地开发
|
||
|
||
```bash
|
||
# Clone repository
|
||
git clone https://github.com/rmyndharis/OpenWA.git
|
||
cd OpenWA
|
||
|
||
# Install dependencies (includes dashboard)
|
||
npm install
|
||
|
||
# Start API + Dashboard (config is auto-generated on first run)
|
||
npm run dev
|
||
|
||
# Access (in dev the dashboard runs on the Vite server with hot reload)
|
||
# Dashboard: http://localhost:2886
|
||
# API: http://localhost:2785/api
|
||
# Swagger: http://localhost:2785/api/docs
|
||
```
|
||
|
||
---
|
||
|
||
## 🔒 安全架构
|
||
|
||
### Docker Socket 代理
|
||
|
||
生产环境技术栈绝不会将 `/var/run/docker.sock` 直接暴露给应用容器。相反,一个专用的 `docker-proxy` 边车(sidecar,基于 [`tecnativa/docker-socket-proxy`](https://github.com/Tecnativa/docker-socket-proxy)))作为访问 Docker 守护进程的唯一网关:
|
||
|
||
```
|
||
openwa-api ──TCP 2375──▶ docker-proxy ──unix──▶ /var/run/docker.sock
|
||
```
|
||
|
||
仅启用容器编排所需的操作(`CONTAINERS`、`IMAGES`、`VOLUMES`、`INFO`、`PING`、`POST`、`DELETE`)。应用通过 `DOCKER_HOST=tcp://docker-proxy:2375` 环境变量连接,`DockerService` 会自动检测该变量。
|
||
|
||
---
|
||
|
||
## 🔒 安全架构
|
||
|
||
### 非 root 容器执行
|
||
|
||
生产镜像绝不会以 root 身份运行 Node.js 进程。启动时,容器遵循以下链路:
|
||
|
||
```
|
||
dumb-init (PID 1)
|
||
└─ docker-entrypoint.sh (root — fixes named-volume ownership via chown)
|
||
└─ gosu openwa node dist/main (drops to the openwa user)
|
||
```
|
||
|
||
- **dumb-init** 作为 PID 1,转发信号(SIGTERM 等)以实现优雅关闭。
|
||
- **docker-entrypoint.sh** 仅以 root 身份运行足够长的时间,以便 `chown` 命名卷挂载点,使 `openwa` 用户可以写入它们。
|
||
- **gosu** 执行基于 `exec` 的干净权限降级 — 不使用 `su` 或 `sudo` 包装器,因此 node 进程是 dumb-init 的直接子进程。
|
||
|
||
命名卷(例如 `openwa-data`)在每次启动时都会自动修正所有权,因此在创建卷后无需手动执行 `chown` 步骤。
|
||
|
||
---
|
||
|
||
## 🏭 生产部署
|
||
|
||
生产环境请使用主 `docker-compose.yml`,并可按需启用可选服务:
|
||
|
||
```bash
|
||
# Basic production (SQLite, local storage)
|
||
docker compose up -d
|
||
|
||
# With PostgreSQL database
|
||
docker compose --profile postgres up -d
|
||
|
||
# Full stack (PostgreSQL, Redis, MinIO)
|
||
docker compose --profile full up -d
|
||
```
|
||
|
||
| 配置方案(Profile) | 服务 |
|
||
| ---------- | --------------------- |
|
||
| `postgres` | PostgreSQL 数据库 |
|
||
| `redis` | Redis 缓存 |
|
||
| `minio` | S3 兼容存储 |
|
||
| `full` | 上述所有服务 |
|
||
|
||
> Dashboard 已打包进 API 镜像,由 NestJS 在 API 端口提供服务,因此无需 profile —— 只要 `openwa-api` 运行,它就始终可用。如需 TLS/公网暴露,请在前方放置你自己的反向代理(nginx、Caddy、云负载均衡器或 k8s Ingress);参见 `docs/12-troubleshooting-faq.md` 中的 nginx 示例。
|
||
|
||
> **开发环境 vs 生产环境**
|
||
>
|
||
> - 开发环境(`docker-compose.dev.yml`):SQLite、本地存储,API 提供打包的 dashboard
|
||
> - 生产环境(`docker-compose.yml`):可配置数据库,通过 profile 启用可选服务
|
||
>
|
||
> 官方 GHCR 镜像以多架构 manifest 形式发布:
|
||
> - `linux/amd64`
|
||
> - `linux/arm64`
|
||
|
||
## 🔌 端口
|
||
|
||
| 服务 | 端口 | 说明 |
|
||
| --------------- | --------------- | --------------------------------------------- |
|
||
| API & Dashboard | `2785` | REST API + 打包的 Web 仪表盘(同一端口) |
|
||
| Swagger | `2785/api/docs` | 交互式 API 文档 |
|
||
| Dashboard (dev) | `2886` | 带热重载的 Vite 开发服务器(`npm run dev`) |
|
||
|
||
---
|
||
|
||
## 📡 API 示例
|
||
|
||
### 创建会话
|
||
|
||
```bash
|
||
curl -X POST http://localhost:2785/api/sessions \
|
||
-H "Content-Type: application/json" \
|
||
-H "X-API-Key: YOUR_API_KEY" \
|
||
-d '{"name": "my-bot"}'
|
||
```
|
||
|
||
### 启动会话并获取二维码
|
||
|
||
```bash
|
||
# Start the session
|
||
curl -X POST http://localhost:2785/api/sessions/{sessionId}/start \
|
||
-H "X-API-Key: YOUR_API_KEY"
|
||
|
||
# Get QR code (scan with WhatsApp)
|
||
curl http://localhost:2785/api/sessions/{sessionId}/qr \
|
||
-H "X-API-Key: YOUR_API_KEY"
|
||
```
|
||
|
||
### 发送消息
|
||
|
||
```bash
|
||
curl -X POST http://localhost:2785/api/sessions/{sessionId}/messages/send-text \
|
||
-H "Content-Type: application/json" \
|
||
-H "X-API-Key: YOUR_API_KEY" \
|
||
-d '{
|
||
"chatId": "628123456789@c.us",
|
||
"text": "Hello from OpenWA!"
|
||
}'
|
||
```
|
||
|
||
### 配置 Webhook
|
||
|
||
```bash
|
||
curl -X POST http://localhost:2785/api/sessions/{sessionId}/webhooks \
|
||
-H "Content-Type: application/json" \
|
||
-H "X-API-Key: YOUR_API_KEY" \
|
||
-d '{
|
||
"url": "https://your-server.com/webhook",
|
||
"events": ["message.received", "session.status"],
|
||
"secret": "your-hmac-secret"
|
||
}'
|
||
```
|
||
|
||
> **智能过滤器(可选):** 添加 `filters` 对象,仅在条件匹配(AND)时触发 webhook,例如 `{ "conditions": [{ "field": "sender", "operator": "is", "value": ["1234567890@c.us"] }] }`。
|
||
> 字段:`sender` / `recipient` / `body` / `type` / `mentions` / `fromMe` / `hasMedia` / `isGroup`。不带过滤器的 webhook 行为与之前完全一致。完整 schema 请参阅 API 规范。
|
||
|
||
## 🤖 MCP Server(AI 智能体)
|
||
|
||
OpenWA 可通过 [Model Context Protocol](https://modelcontextprotocol.io)** so AI agents(Claude、Cursor 等)驱动 WhatsApp。默认**关闭**且为**附加功能** —— 所有 REST 路由保持原样不变。
|
||
|
||
将 `MCP_ENABLED=true` 设置为在现有服务器的 **`POST /mcp`** 上挂载无状态 Streamable-HTTP 传输(同一端口,无需额外进程)。它暴露约 39 个精选工具(会话、消息、联系人、基础群组操作、webhook 读取)—— 相比完整 API 是精简面,避免智能体不堪重负,并将破坏性操作排除在智能体路径之外。
|
||
|
||
```bash
|
||
MCP_ENABLED=true npm run start:prod # or set MCP_ENABLED in your .env / compose
|
||
```
|
||
|
||
将 MCP 客户端指向该端点(例如 Claude Code,在项目根目录放置 `.mcp.json`):
|
||
|
||
```json
|
||
{
|
||
"mcpServers": {
|
||
"openwa": {
|
||
"type": "http",
|
||
"url": "http://localhost:2785/mcp",
|
||
"headers": { "Authorization": "Bearer YOUR_API_KEY" }
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
密钥可通过 `Authorization: Bearer …` 或 `X-API-Key: …` 传递。每次工具调用均经过与 REST **相同的 API 密钥认证、角色和按会话作用域**。
|
||
|
||
**安全指南:**
|
||
|
||
- **为智能体签发专用的最小权限密钥** —— 非管理员、**按会话作用域**的密钥(最多 `OPERATOR` 角色)。明文密钥仅在创建时显示一次;如需轮换,请创建新密钥并删除旧密钥。
|
||
- 密钥**不得**携带 IP 允许列表(`allowedIps`)—— MCP 无法获取真实客户端 IP,此类密钥会被拒绝。
|
||
- 设置 **`MCP_READONLY=true`** 仅挂载只读工具(无发送/写入)。
|
||
- 设置 **`MCP_RATE_LIMIT_MAX`**(默认 `60`)以限制每个 API 密钥在每个时间窗口内的工具调用次数。
|
||
- 设置 **`MCP_RATE_LIMIT_WINDOW_MS`**(默认 `60000`)以控制滑动窗口大小(毫秒)。
|
||
- **不要在没有前置认证代理的情况下将 `/mcp` 暴露到公网。** 对于自托管、仅本地访问的部署,静态 API 密钥是合适的;公网暴露应使用 OAuth 2.1(尚未实现)。
|
||
|
||
---
|
||
|
||
## 🛠 技术栈
|
||
|
||
| 层级 | 技术 |
|
||
| ------------- | ----------------------- |
|
||
| **Runtime** | Node.js 22 LTS |
|
||
| **Framework** | NestJS 11.x |
|
||
| **Language** | TypeScript 5.x |
|
||
| **WA Engine** | whatsapp-web.js(默认)/ baileys — 通过 `ENGINE_TYPE` 设置 |
|
||
| **Database** | SQLite / PostgreSQL |
|
||
| **Cache** | Redis(可选) |
|
||
| **Storage** | Local / S3 / MinIO |
|
||
| **ORM** | TypeORM |
|
||
| **Container** | Docker + Docker Compose |
|
||
|
||
---
|
||
|
||
## 📁 项目结构
|
||
|
||
```
|
||
openwa/
|
||
├── src/
|
||
│ ├── main.ts # Application entry point
|
||
│ ├── app.module.ts # Root module
|
||
│ ├── config/ # Configuration
|
||
│ ├── common/ # Shared utilities
|
||
│ │ ├── cache/ # Redis caching
|
||
│ │ └── storage/ # File storage (Local/S3)
|
||
│ ├── core/ # Core systems
|
||
│ │ ├── hooks/ # Plugin hooks
|
||
│ │ └── plugins/ # Plugin system
|
||
│ ├── engine/ # WhatsApp engine abstraction
|
||
│ └── modules/
|
||
│ ├── session/ # Session management
|
||
│ ├── message/ # Message handling
|
||
│ ├── webhook/ # Webhook management
|
||
│ ├── group/ # Groups API
|
||
│ ├── contact/ # Contacts API
|
||
│ ├── auth/ # API key authentication
|
||
│ ├── infra/ # Infrastructure management
|
||
│ └── health/ # Health checks
|
||
├── dashboard/ # React web dashboard
|
||
├── docs/ # Documentation
|
||
├── docker-compose.yml
|
||
├── Dockerfile
|
||
└── package.json
|
||
```
|
||
|
||
---
|
||
|
||
## 📚 文档
|
||
|
||
完整文档位于 `docs/` 文件夹:
|
||
|
||
| 文档 | 说明 |
|
||
| ------------------------------------------------------- | ---------------------------- |
|
||
| [Project Overview](./docs/01-project-overview.md) | 简介与目标 |
|
||
| [Requirements](./docs/02-requirements-specification.md) | 功能规格说明 |
|
||
| [Architecture](./docs/03-system-architecture.md) | 系统设计 |
|
||
| [Security](./docs/04-security-design.md) | 安全实现 |
|
||
| [Database](./docs/05-database-design.md) | 数据模型与迁移 |
|
||
| [API Spec](./docs/06-api-specification.md) | 完整 API 参考 |
|
||
| [Development](./docs/08-development-guidelines.md) | 编码规范 |
|
||
| [Migration Guide](./docs/14-migration-guide.md) | 数据库与存储迁移 |
|
||
|
||
---
|
||
|
||
## 🤝 贡献
|
||
|
||
欢迎贡献!入门步骤如下:
|
||
|
||
1. **Fork** 本仓库
|
||
2. **创建** 你的功能分支(`git checkout -b feature/amazing-feature`)
|
||
3. **提交** 你的更改(`git commit -m 'Add amazing feature'`)
|
||
4. **推送** 到该分支(`git push origin feature/amazing-feature`)
|
||
5. **打开** Pull Request
|
||
|
||
请阅读我们的 [Development Guidelines](./docs/08-development-guidelines.md) 了解编码规范与最佳实践。
|
||
|
||
---
|
||
|
||
## 📄 许可证
|
||
|
||
本项目采用 **MIT License** 许可 —— 可免费用于个人和商业用途。
|
||
|
||
详见 [LICENSE](./LICENSE)。
|
||
|
||
---
|
||
|
||
<div align="center">
|
||
|
||
**OpenWA** – 免费、开源的 WhatsApp API 网关
|
||
|
||
[📖 文档](./docs/README.md) · [🔌 API 文档](http://localhost:2785/api/docs) · [🐛 报告 Bug](https://github.com/rmyndharis/OpenWA/issues) · [💡 功能建议](https://github.com/rmyndharis/OpenWA/issues)
|
||
|
||
<br/>
|
||
|
||
<sub>由 <a href="https://github.com/rmyndharis">Yudhi Armyndharis</a> 与 OpenWA 社区用 ❤️ 制作</sub>
|
||
|
||
</div>
|