diff --git a/.dockerignore b/.dockerignore index d3a7f73..a7ea49c 100644 --- a/.dockerignore +++ b/.dockerignore @@ -15,5 +15,7 @@ temp # 本地私有配置与运行态文件不进入镜像,避免把真实密钥或登录态烘焙到镜像层。 .env +.env.* config.yaml wechat_ipad/config.toml +wechat_ipad/providers/*/runtime_state.toml diff --git a/.env.docker.example b/.env.docker.example index 7f2a485..7354ea9 100644 --- a/.env.docker.example +++ b/.env.docker.example @@ -21,8 +21,18 @@ WECHAT_SERVER_URL=http://host.docker.internal:8059/ WECHAT_SERVER_IP=host.docker.internal WECHAT_SERVER_PORT=8059 WECHAT_SERVER_TYPE=legacy_855 +# 当 WECHAT_SERVER_TYPE=server_864 时必须提供。 +WECHAT_SERVER_KEY= WECHAT_WXID= WECHAT_DEVICE_NAME= WECHAT_DEVICE_ID= # 留空时会默认写到 `wechat_ipad/providers//runtime_state.toml`。 WECHAT_STATE_FILE= + +# Dashboard / 开源仓库安全项 +ABOT_DASHBOARD_USERNAME=admin +ABOT_DASHBOARD_PASSWORD=ChangeThisPassword_2026! +# 建议填入一串随机长字符串,用于 Flask Session 签名。 +ABOT_DASHBOARD_SECRET_KEY= +# 如需启用 TrendRadar webhook,再显式配置;不建议继续使用示例值。 +ABOT_TRENDRADAR_WEBHOOK_TOKEN=please_change_this_token diff --git a/Dockerfile b/Dockerfile index 7cf1e9f..6da71f1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -49,9 +49,14 @@ ENV ABOT_ENVIRONMENT=production \ WECHAT_SERVER_URL=http://127.0.0.1:8059/ \ WECHAT_SERVER_IP=127.0.0.1 \ WECHAT_SERVER_PORT=8059 \ + WECHAT_SERVER_KEY= \ WECHAT_WXID= \ WECHAT_DEVICE_NAME=ABOTPad \ WECHAT_DEVICE_ID= \ + ABOT_DASHBOARD_USERNAME=admin \ + ABOT_DASHBOARD_PASSWORD=ChangeThisPassword_2026! \ + ABOT_DASHBOARD_SECRET_KEY= \ + ABOT_TRENDRADAR_WEBHOOK_TOKEN=please_change_this_token \ DASHBOARD_HOST=0.0.0.0 \ DASHBOARD_PORT=8888 diff --git a/README.MD b/README.MD index b683d7f..21d4750 100644 --- a/README.MD +++ b/README.MD @@ -1,28 +1,31 @@ # ABOT -ABOT 是一个基于插件体系构建的微信机器人项目,包含消息处理主链路、管理后台、MySQL/Redis 存储、定时任务与多类 AI / 内容插件能力。当前仓库更适合有一定 Python 与部署基础的维护者进行二次开发、私有部署与功能扩展。 +ABOT 是一个面向长期维护的微信机器人项目,包含消息接入、插件体系、管理后台、MySQL / Redis 存储、定时任务以及 AI 扩展能力。 +当前仓库已经完成一轮面向开源发布的工程整理,适合用于二次开发、私有部署和多版本 `wechat_ipad server` 接入演进。 -## 项目定位 +## 项目特点 -- 面向“可持续迭代的机器人平台”,不是一次性脚本 -- 核心能力包括消息接入、插件化处理、后台管理、数据归档与 AI 扩展 -- 当前默认假设你具备 MySQL、Redis、Docker、环境变量配置的基础经验 +- 插件化机器人主链路,便于按业务拆分能力 +- 自带 Dashboard 管理后台,支持状态查看、插件管理、消息与联系人相关页面 +- 支持 `legacy_855` 与 `server_864` 两类 `wechat_ipad server` 适配入口 +- 配置统一走 `.env + config.yaml`,登录态运行时状态落到 provider 独立目录 +- 提供 Docker / Docker Compose 基础部署骨架,便于快速上线验证 -## 当前主要能力 +## 当前能力范围 -- 微信消息接入与机器人主循环 -- 插件加载、启停、热更新与后台管理 -- MySQL + Redis 双存储 -- AI 自动回复、消息总结、成员画像等能力 -- 签到、积分、排行榜、内容推送、媒体处理等业务插件 +- 微信消息接入与实时处理 +- 插件加载、启停、热更新治理 +- MySQL + Redis 数据存储 +- 联系人、群信息、消息归档、统计与部分运营分析页面 +- AI 自动回复、消息总结、成员画像、内容推送等扩展能力 ## 快速开始 ### 方式一:Docker Compose -适合第一次快速跑通部署骨架。 +适合第一次快速跑通完整部署骨架。 -1. 复制 Docker 环境变量示例 +1. 复制 Docker 环境变量模板 ```bash cp .env.docker.example .env @@ -34,7 +37,16 @@ Windows PowerShell: Copy-Item .env.docker.example .env ``` -2. 按实际环境修改 `.env` 中的数据库密码、`WECHAT_SERVER_URL`、`WECHAT_SERVER_TYPE` 等参数 +2. 至少修改以下变量 + +- `ABOT_DB_PASSWORD` +- `WECHAT_SERVER_URL` +- `WECHAT_SERVER_IP` +- `WECHAT_SERVER_PORT` +- `WECHAT_SERVER_TYPE` +- `WECHAT_SERVER_KEY`:仅 `server_864` 必填 +- `ABOT_DASHBOARD_PASSWORD` +- `ABOT_DASHBOARD_SECRET_KEY` 3. 启动服务 @@ -42,13 +54,19 @@ Copy-Item .env.docker.example .env docker compose up -d --build ``` -更多说明见 [docs/Docker部署说明.md](/d:/learn/abot/docs/Docker部署说明.md:1)。 +4. 访问 Dashboard + +- 默认地址:`http://127.0.0.1:8888` +- 默认用户名:`admin` +- 默认密码以你的 `.env` 中 `ABOT_DASHBOARD_PASSWORD` 为准 + +更完整的上线说明见 [docs/Docker部署说明.md](/d:/learn/abot/docs/Docker部署说明.md:1)。 ### 方式二:本地直跑 1. 准备 Python 3.10+ 2. 准备 MySQL、Redis -3. 复制配置文件 +3. 复制配置模板 ```bash cp config.example.yaml config.yaml @@ -71,40 +89,57 @@ pip install -r requirements.txt pip install pysilk-mod ``` -5. 启动主程序 +5. 启动项目 ```bash python main.py ``` -## 配置说明 +## 配置约定 -### 全局配置 +### 静态配置 -项目支持从 `.env` 自动加载环境变量,并在 [config.example.yaml](/d:/learn/abot/config.example.yaml:1) / `config.yaml` 中使用: +推荐只维护以下两类文件: -- `${ENV_NAME}` -- `${ENV_NAME:默认值}` +- `.env` +- `config.yaml` -示例: - -- `${ABOT_DB_PASSWORD}`:必须提供 -- `${ABOT_DB_HOST:127.0.0.1}`:可缺省时回退 +`config.yaml` 支持 `${ENV_NAME}` / `${ENV_NAME:default}` 占位符,因此更推荐把敏感配置写进 `.env`,把结构与默认值保留在 YAML 模板里。 ### wechat_ipad 配置 -现在 `wechat_ipad` 的静态连接参数已经统一走 `.env` / `config.yaml`: +当前 `wechat_ipad` 的静态连接配置统一走环境变量: - `WECHAT_SERVER_URL` - `WECHAT_SERVER_IP` - `WECHAT_SERVER_PORT` - `WECHAT_SERVER_TYPE` +- `WECHAT_SERVER_KEY`:仅 `server_864` 必填 -登录后的 `wxid / device_id / device_name` 不再要求你手工维护,它们会自动写入本地状态文件: +运行时状态不再要求人工维护,会自动写到: -- 默认路径:`wechat_ipad/providers//runtime_state.toml` -- 可通过 `WECHAT_STATE_FILE` 覆盖 -- 启动时会自动兼容历史 `wechat_ipad/config.toml` 中已有的登录态 +- `wechat_ipad/providers//runtime_state.toml` + +这意味着: + +- 每个 provider 的登录态彼此隔离 +- 切换 `855 / 864` 不会默认串用同一份状态 +- 开源仓库不需要再长期维护多份分散配置文件 + +## Docker 交付说明 + +当前仓库已经提供以下开源友好交付物: + +- [Dockerfile](/d:/learn/abot/Dockerfile:1) +- [docker-compose.yml](/d:/learn/abot/docker-compose.yml:1) +- [docker-entrypoint.sh](/d:/learn/abot/docker-entrypoint.sh:1) +- [.env.docker.example](/d:/learn/abot/.env.docker.example:1) + +容器化方案的边界是: + +- `abot`、`mariadb`、`redis` 已拆成独立服务 +- `wechat_ipad server` 仍建议跑在宿主机或独立机器 +- Dashboard 账号、密码、Session Secret、Webhook Token 都支持环境变量覆盖 ## 目录结构 @@ -112,11 +147,11 @@ python main.py abot/ ├── admin/ # 管理后台 ├── base/ # 插件基础接口与管理能力 -├── db/ # 数据库访问层与迁移脚本 -├── docs/ # 部署、设计、使用文档 +├── db/ # 数据库访问层与 SQL 脚本 +├── docs/ # 部署、设计与路线图文档 ├── plugins/ # 业务插件 ├── utils/ # 通用工具与服务 -├── wechat_ipad/ # 微信相关客户端与 server 对接代码 +├── wechat_ipad/ # 微信接入与 provider 适配层 ├── Dockerfile ├── docker-compose.yml ├── config.example.yaml @@ -124,64 +159,68 @@ abot/ └── main.py ``` -## 管理后台 +## Dashboard 与默认安全项 -- 默认端口:`8888` -- 配置文件:[`admin/dashboard/config.toml`](/d:/learn/abot/admin/dashboard/config.toml:1) -- 公开仓库中的账号密码与 webhook token 已改为占位值,部署前务必自行修改 +Dashboard 默认配置文件位于 [admin/dashboard/config.toml](/d:/learn/abot/admin/dashboard/config.toml:1)。 -## Docker 化现状 +为了适配公开仓库,这一层已经做了两件事: -本仓库现在提供的是“开源友好”的基础部署骨架: +- 仓库中的默认密码已不再使用弱口令 `admin123` +- Docker / 环境变量可以直接覆盖后台账号、密码和 webhook token -- 应用、MariaDB、Redis 已拆分为独立服务 -- 提供 `docker-compose.yml`、`.dockerignore`、`.env.docker.example` -- 静态连接配置统一通过 `.env` 注入,更适合开源仓库和多环境部署 -- wechat 登录态缓存默认落到对应 provider 目录下 +正式部署前仍建议你明确设置: -当前仍建议你在正式生产前继续补充: +- `ABOT_DASHBOARD_USERNAME` +- `ABOT_DASHBOARD_PASSWORD` +- `ABOT_DASHBOARD_SECRET_KEY` +- `ABOT_TRENDRADAR_WEBHOOK_TOKEN` -- HTTPS / 反向代理 -- 备份策略 -- CI/CD -- 监控与告警 +## License 与开源边界 -## 开源说明 +### 主许可证 -### License 要不要改 +当前仓库主代码采用 [MIT License](/d:/learn/abot/LICENSE:1)。 -当前主代码仍按 MIT License 分发,通常不必为了“开源”单独换许可证。 +一般情况下,不需要为了“把仓库开源”额外改成别的许可证;但你仍需要确认两件事: -但你需要额外关注: +1. `LICENSE` 中的版权主体是否就是你希望公开使用的名字 +2. 仓库里的第三方资源、字体、二进制是否都允许再分发 -- 字体文件的再分发许可 -- `wechat_ipad/ipad859go` 二进制来源与授权 -- `resource/` 下业务资料是否适合公开 -- 第三方前端静态资源的许可证保留 +相关说明见 [THIRD_PARTY_LICENSES.md](/d:/learn/abot/THIRD_PARTY_LICENSES.md:1)。 -详情见 [THIRD_PARTY_LICENSES.md](/d:/learn/abot/THIRD_PARTY_LICENSES.md:1)。 - -### 不建议公开提交的内容 +### 不建议直接公开提交的内容 - `.env` - `config.yaml` -- `wechat_ipad/providers/*/runtime_state.toml` 中的真实 `wxid` / `device_id` +- `wechat_ipad/providers/*/runtime_state.toml` - 真实数据库密码、LLM API Key、Webhook Token +- 未确认授权来源的字体、二进制与业务素材 + +## 已知仍需你自行确认的事项 + +以下内容我已经在文档中标出来,但不适合由我直接替你做法律判断: + +- `LICENSE` 版权主体是否需要改成你当前对外公开的名称 +- `fonts/` 下字体文件的再分发许可 +- `wechat_ipad/ipad859go` 的来源与授权 +- `resource/` 目录中的业务资料是否适合公开仓库传播 ## 路线图 -当前更优先的方向不是继续无上限堆新功能,而是继续补工程底座: +当前更值得优先推进的方向: -- Docker 化与部署规范 -- 文档与回归清单 -- 插件治理 -- 可观测性与任务中心 -- 开源边界与资产合规 +- 继续完善 `864 provider` 真机联调与高频接口覆盖 +- 补齐 Docker / 部署回归清单 +- 插件治理、任务中心、可观测性增强 +- 开源资产合规清点 -已整理的工程 backlog 见 [docs/工程优化与Feature清单.md](/d:/learn/abot/docs/工程优化与Feature清单.md:1)。 +已整理的工程规划文档: -## 贡献与使用说明 +- [docs/工程优化与Feature清单.md](/d:/learn/abot/docs/工程优化与Feature清单.md:1) +- [docs/wechat_ipad多版本Server适配路线图.md](/d:/learn/abot/docs/wechat_ipad多版本Server适配路线图.md:1) -- 欢迎基于自己的场景二次开发 -- 提交前请避免把本地私有配置、运行日志、登录态一并提交 -- 涉及平台接口、内容抓取、自动推送等能力时,请自行评估目标平台规则与当地法律要求 +## 使用与贡献说明 + +- 欢迎按自己的场景二次开发 +- 提交代码前请确认未误带本地私有配置、日志和登录态 +- 涉及内容抓取、自动推送、第三方平台接口的能力,请自行评估合规与风控要求 diff --git a/admin/dashboard/config.toml b/admin/dashboard/config.toml index 220abce..618d71e 100644 --- a/admin/dashboard/config.toml +++ b/admin/dashboard/config.toml @@ -4,13 +4,18 @@ port = 8888 [auth] username = "admin" -password = "admin123" +# 公开仓库不再提供弱默认密码: +# 1. 新部署环境首次启动时会自动把这里的账号信息播种到后台管理员表; +# 2. 若你的数据库里已经存在管理员账号,则后续以数据库中的真实密码为准; +# 3. 正式环境建议继续通过环境变量覆盖,而不是长期使用仓库示例值。 +password = "ChangeThisPassword_2026!" [trendradar_webhook] # 是否启用 TrendRadar webhook 适配接口 -enabled = true -# 固定 token(建议配置),支持请求头 X-Webhook-Token / query token / payload.token 三种传法 -token = "watHcBbQIxtmyqGRSHKeTDRVjkHOceiRfFytUkQUwmV" +enabled = false +# 固定 token(建议配置),支持请求头 X-Webhook-Token / query token / payload.token 三种传法。 +# 仓库中的值仅为占位示例,正式环境请改成你自己的随机长 token。 +token = "please_change_this_token" # 默认推送目标群(可配置多个) default_group_ids = [] # 是否允许 payload 覆盖目标群(开启后可通过 target_group_ids/group_id 指定) diff --git a/admin/dashboard/server.py b/admin/dashboard/server.py index d99a4e0..874481c 100644 --- a/admin/dashboard/server.py +++ b/admin/dashboard/server.py @@ -153,23 +153,146 @@ class DashboardServer: config_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'config.toml') if os.path.exists(config_path): with open(config_path, 'r', encoding='utf-8') as f: - return toml.load(f) + config_data = toml.load(f) else: # 如果配置文件不存在,创建默认配置 - default_config = { + config_data = { "server": {"host": "0.0.0.0", "port": 8888}, - "auth": {"username": "admin", "password": "admin123"} + "auth": {"username": "admin", "password": "ChangeThisPassword_2026!"}, + "trendradar_webhook": { + "enabled": False, + "token": "please_change_this_token", + "default_group_ids": [], + "allow_payload_target_groups": False, + "send_timeout_seconds": 20, + }, } with open(config_path, 'w', encoding='utf-8') as f: - toml.dump(default_config, f) - return default_config + toml.dump(config_data, f) + return self._apply_dashboard_env_overrides(config_data) except Exception as e: - self.LOG.error(f"加载Dashboard配置文件失败: {e}") + # 这里属于 Dashboard 构造早期阶段: + # 1. `self.LOG` 还没在 `__init__` 中完成赋值; + # 2. 若此时配置文件损坏,仍然需要把错误稳定打印出来; + # 3. 因此这里直接回退到模块级 logger,避免异常再次被属性缺失覆盖。 + logger.error(f"加载Dashboard配置文件失败: {e}") # 返回默认配置 - return { + fallback_config = { "server": {"host": "0.0.0.0", "port": 8888}, - "auth": {"username": "admin", "password": "admin123"} + "auth": {"username": "admin", "password": "ChangeThisPassword_2026!"}, + "trendradar_webhook": { + "enabled": False, + "token": "please_change_this_token", + "default_group_ids": [], + "allow_payload_target_groups": False, + "send_timeout_seconds": 20, + }, } + return self._apply_dashboard_env_overrides(fallback_config) + + @staticmethod + def _safe_env_bool(value, default: bool) -> bool: + """把环境变量里的开关值安全转成布尔值。""" + if value in (None, ""): + return default + text = str(value).strip().lower() + if text in {"1", "true", "yes", "y", "on"}: + return True + if text in {"0", "false", "no", "n", "off"}: + return False + return default + + @staticmethod + def _safe_env_int(value, default: int) -> int: + """把环境变量里的数字安全转成整数。""" + try: + if value in (None, ""): + return default + return int(value) + except (TypeError, ValueError): + return default + + @staticmethod + def _safe_env_group_ids(value) -> list[str]: + """把逗号分隔的群列表环境变量转成数组。""" + raw_text = str(value or "").strip() + if not raw_text: + return [] + return [item.strip() for item in raw_text.split(",") if item.strip()] + + def _apply_dashboard_env_overrides(self, config_data: dict) -> dict: + """用环境变量覆盖 Dashboard 配置中的敏感项与部署项。""" + merged_config = dict(config_data or {}) + merged_config["server"] = dict(merged_config.get("server", {}) or {}) + merged_config["auth"] = dict(merged_config.get("auth", {}) or {}) + merged_config["trendradar_webhook"] = dict(merged_config.get("trendradar_webhook", {}) or {}) + + # 这里优先让运维通过环境变量覆盖后台配置: + # 1. Docker / PaaS 场景下更容易统一管理账号、端口与 token; + # 2. 也避免公开仓库里的示例 TOML 被误当成最终生产配置; + # 3. 未配置环境变量时仍回退到本地文件,兼容现有非容器部署方式。 + server_section = merged_config["server"] + auth_section = merged_config["auth"] + webhook_section = merged_config["trendradar_webhook"] + + server_section["host"] = str(os.environ.get("DASHBOARD_HOST", server_section.get("host", "0.0.0.0")) or "0.0.0.0") + server_section["port"] = self._safe_env_int( + os.environ.get("DASHBOARD_PORT", server_section.get("port", 8888)), + 8888, + ) + + auth_section["username"] = str( + os.environ.get("ABOT_DASHBOARD_USERNAME", auth_section.get("username", "admin")) or "admin" + ).strip() + auth_section["password"] = str( + os.environ.get("ABOT_DASHBOARD_PASSWORD", auth_section.get("password", "ChangeThisPassword_2026!")) + or "ChangeThisPassword_2026!" + ) + auth_section["session_timeout_minutes"] = self._safe_env_int( + os.environ.get("ABOT_DASHBOARD_SESSION_TIMEOUT_MINUTES", auth_section.get("session_timeout_minutes", 480)), + 480, + ) + auth_section["max_failed_attempts"] = self._safe_env_int( + os.environ.get("ABOT_DASHBOARD_MAX_FAILED_ATTEMPTS", auth_section.get("max_failed_attempts", 5)), + 5, + ) + auth_section["lock_seconds"] = self._safe_env_int( + os.environ.get("ABOT_DASHBOARD_LOCK_SECONDS", auth_section.get("lock_seconds", 900)), + 900, + ) + auth_section["cookie_secure"] = self._safe_env_bool( + os.environ.get("ABOT_DASHBOARD_COOKIE_SECURE", auth_section.get("cookie_secure", False)), + False, + ) + auth_section["cookie_samesite"] = str( + os.environ.get("ABOT_DASHBOARD_COOKIE_SAMESITE", auth_section.get("cookie_samesite", "Lax")) or "Lax" + ).strip() + + webhook_section["enabled"] = self._safe_env_bool( + os.environ.get("ABOT_TRENDRADAR_WEBHOOK_ENABLED", webhook_section.get("enabled", False)), + False, + ) + webhook_section["token"] = str( + os.environ.get("ABOT_TRENDRADAR_WEBHOOK_TOKEN", webhook_section.get("token", "")) or "" + ).strip() + env_default_groups = os.environ.get("ABOT_TRENDRADAR_DEFAULT_GROUP_IDS", "") + if env_default_groups not in (None, ""): + webhook_section["default_group_ids"] = self._safe_env_group_ids(env_default_groups) + webhook_section["allow_payload_target_groups"] = self._safe_env_bool( + os.environ.get( + "ABOT_TRENDRADAR_ALLOW_PAYLOAD_TARGET_GROUPS", + webhook_section.get("allow_payload_target_groups", False), + ), + False, + ) + webhook_section["send_timeout_seconds"] = self._safe_env_int( + os.environ.get( + "ABOT_TRENDRADAR_SEND_TIMEOUT_SECONDS", + webhook_section.get("send_timeout_seconds", 20), + ), + 20, + ) + return merged_config def _create_app(self) -> Flask: """创建Flask应用""" diff --git a/docker-compose.yml b/docker-compose.yml index 5eb12c2..9ae4550 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -81,10 +81,15 @@ services: WECHAT_SERVER_IP: ${WECHAT_SERVER_IP:-host.docker.internal} WECHAT_SERVER_PORT: ${WECHAT_SERVER_PORT:-8059} WECHAT_SERVER_TYPE: ${WECHAT_SERVER_TYPE:-legacy_855} + WECHAT_SERVER_KEY: ${WECHAT_SERVER_KEY:-} WECHAT_WXID: ${WECHAT_WXID:-} WECHAT_DEVICE_NAME: ${WECHAT_DEVICE_NAME:-} WECHAT_DEVICE_ID: ${WECHAT_DEVICE_ID:-} WECHAT_STATE_FILE: ${WECHAT_STATE_FILE:-} + ABOT_DASHBOARD_USERNAME: ${ABOT_DASHBOARD_USERNAME:-admin} + ABOT_DASHBOARD_PASSWORD: ${ABOT_DASHBOARD_PASSWORD:-ChangeThisPassword_2026!} + ABOT_DASHBOARD_SECRET_KEY: ${ABOT_DASHBOARD_SECRET_KEY:-} + ABOT_TRENDRADAR_WEBHOOK_TOKEN: ${ABOT_TRENDRADAR_WEBHOOK_TOKEN:-please_change_this_token} ports: - "${DASHBOARD_PORT:-8888}:8888" volumes: diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index 43d0cb9..d495c9d 100644 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -52,6 +52,11 @@ wechat_ipad: server_ip: "\${WECHAT_SERVER_IP:host.docker.internal}" server_port: "\${WECHAT_SERVER_PORT:8059}" server_type: "\${WECHAT_SERVER_TYPE:legacy_855}" + # 864 风格 server 依赖固定 key,这里一并写入自动生成的配置模板: + # 1. 避免容器部署场景下还要手工进容器补 config.yaml; + # 2. 855/859 保持可留空,不影响现有默认行为; + # 3. 真正的值仍由 `.env` / compose 环境变量注入,不会写死在镜像层。 + server_key: "\${WECHAT_SERVER_KEY:}" wxid: "\${WECHAT_WXID:}" device_name: "\${WECHAT_DEVICE_NAME:}" device_id: "\${WECHAT_DEVICE_ID:}" @@ -60,6 +65,34 @@ wechat_ipad: EOF fi +# Dashboard 单独使用 config.toml: +# 1. 公开仓库里的默认账号和 webhook token 不适合作为最终线上值; +# 2. 这里允许通过环境变量在容器启动期覆盖默认配置,降低“改完 .env 还要再改一份 TOML”的成本; +# 3. 若用户自己挂载了定制版 config.toml,也仍然可以继续复用,因为运行时还会再做环境变量兜底覆盖。 +if [ ! -f /app/admin/dashboard/config.toml ]; then + cat > /app/admin/dashboard/config.toml </runtime_state.toml` -- Compose 已将宿主机的 `./wechat_ipad/providers` 目录映射进容器 -- 因此容器重建后,已有登录态仍会保留 - -兼容说明: - -- 启动时仍会尝试兼容历史 `wechat_ipad/config.toml` -- 但新的人工维护入口已经变成 `.env` -- 后续不再建议继续手工编辑旧 TOML 文件 - -## 5. 常用命令 - -查看服务状态: +查看状态: ```bash docker compose ps @@ -87,6 +78,80 @@ docker compose ps docker compose logs -f abot ``` +## 4. 容器内配置生成逻辑 + +容器启动时会自动处理两类配置: + +### 4.1 `config.yaml` + +若容器内不存在 `config.yaml`,入口脚本会自动生成最小可运行模板,并注入: + +- 数据库连接 +- Redis 连接 +- `wechat_ipad` 静态连接参数 +- `WECHAT_SERVER_KEY` + +### 4.2 `admin/dashboard/config.toml` + +若容器内不存在该文件,入口脚本也会自动生成一份基础模板。 +即使该文件存在,运行时仍支持通过环境变量覆盖以下敏感项: + +- `ABOT_DASHBOARD_USERNAME` +- `ABOT_DASHBOARD_PASSWORD` +- `ABOT_DASHBOARD_SECRET_KEY` +- `ABOT_TRENDRADAR_WEBHOOK_TOKEN` + +这样做的目标是: + +- 公开仓库不再依赖固定弱口令 +- Docker 环境只维护 `.env` 一处 +- 非容器部署仍可继续使用本地 TOML 配置 + +## 5. wechat_ipad 配置说明 + +### 5.1 静态连接配置 + +统一通过 `.env` 注入: + +- `WECHAT_SERVER_URL` +- `WECHAT_SERVER_IP` +- `WECHAT_SERVER_PORT` +- `WECHAT_SERVER_TYPE` +- `WECHAT_SERVER_KEY` + +说明: + +- `legacy_855 / 855 / 859` 可不填 `WECHAT_SERVER_KEY` +- `server_864 / 864` 必须提供 `WECHAT_SERVER_KEY` + +### 5.2 运行时状态 + +登录后的 `wxid / device_id / device_name / login_time` 会自动写到 provider 自己的状态文件中: + +- 默认路径:`wechat_ipad/providers//runtime_state.toml` + +Compose 已将整个 `./wechat_ipad/providers` 目录映射到宿主机,因此: + +- 容器重建后状态仍会保留 +- `855` 与 `864` 的状态天然分离 +- 不需要再人工维护历史 `wechat_ipad/config.toml` + +## 6. Dashboard 安全建议 + +建议至少设置以下变量后再对外暴露: + +- `ABOT_DASHBOARD_PASSWORD` +- `ABOT_DASHBOARD_SECRET_KEY` +- `ABOT_TRENDRADAR_WEBHOOK_TOKEN` + +补充说明: + +- 仓库默认密码已不再使用 `admin123` +- 若数据库里已存在管理员账号,登录以数据库中的真实密码为准 +- 如果你把 Dashboard 暴露到公网,建议再增加反向代理、HTTPS 和 IP / VPN 访问控制 + +## 7. 常用运维命令 + 停止服务: ```bash @@ -99,7 +164,20 @@ docker compose down docker compose down -v ``` -## 6. 升级建议 +进入应用容器: + +```bash +docker compose exec abot bash +``` + +重建应用镜像: + +```bash +docker compose build --no-cache abot +docker compose up -d +``` + +## 8. 升级建议 拉取新代码后建议执行: @@ -108,13 +186,21 @@ docker compose down docker compose up -d --build ``` -若数据库结构发生变更,请先备份再升级。 +若数据库结构发生变更,请先备份数据库与关键挂载目录,再执行升级。 -## 7. 公开仓库注意事项 +建议重点备份: -在公开仓库或分享部署示例前,请再次确认: +- MariaDB 数据卷 +- `./logs` +- `./wechat_ipad/providers` +- 你自己的 `.env` + +## 9. 开源仓库注意事项 + +在公开仓库、打包镜像或分享部署模板前,请再次确认: 1. `.env` 未提交 2. `config.yaml` 未提交真实密钥 3. `wechat_ipad/providers/*/runtime_state.toml` 未被误公开 -4. Dashboard 账号密码与 webhook token 已替换为你自己的值 +4. Dashboard 密码、Session Secret、Webhook Token 已替换为你自己的值 +5. 未确认授权来源的字体、二进制与业务素材没有被一起公开