1. 项目概述:为什么要把微信公众号变成 RSS?
wewe-rss 这个项目名字乍看有点拗口,其实拆开就很好理解:“we we”是“微信”的谐音梗,“rss”就是那个老而弥坚的聚合协议——Really Simple Syndication。它干了一件看起来反直觉但实际非常刚需的事:把微信公众号这种封闭、单向、强依赖App的私域内容池,硬生生撬开一条出口,变成标准、开放、可跨平台订阅的 RSS 源。这不是魔改,而是对信息分发链路的一次务实缝合。
我第一次接触这个需求,是在帮一家做行业资讯的媒体团队做内容分发优化。他们每天要手动复制粘贴十几篇公众号文章到内部知识库、邮件简报、Slack频道,再同步到Notion,光排版和链接校验就占掉编辑30%工时。后来他们试了第三方RSS抓取工具,结果要么失效频繁(微信反爬升级后直接崩),要么只抓标题不抓正文,图片全挂,排版乱成一团。直到 wewe-rss 出现,我们用 Docker Compose 一键拉起,三天内就把全部27个合作号接入,所有内容自动推送到 Feedly、Inoreader 和自建的 Hugo 博客,连带实现了全文搜索和关键词归档——这才是真正意义上的“内容即服务”。
核心关键词里反复出现的Docker Compose、MySQL、SQLite,不是凑数的标签,而是这个项目落地的三根支柱:Docker Compose 解决环境一致性与一键部署;MySQL 支撑高并发、多账号、长期运行的生产级稳定;SQLite 则是给个人用户、测试环境或轻量场景准备的“零配置”方案。你不需要懂 Go 语言源码,也不用自己写爬虫逻辑,wewe-rss 已经把微信公众号的 DOM 结构解析、图文混排还原、封面图提取、发布时间标准化这些脏活累活全封装好了。它不绕过微信规则,而是正向利用其公开页面(如 mp.weixin.qq.com/s/xxx)做静态抓取,所以合规性有基本保障,也避免了登录态维护这类高风险操作。
适合谁来部署?如果你是内容运营、技术博主、独立开发者、小团队知识管理员,或者只是想把自己关注的10个优质号集中管理,而不是在微信里无限下拉刷屏——那这就是为你量身定制的工具。它不承诺“实时推送”,但能做到“准实时”(默认每30分钟轮询一次,可调);它不保证100%抓取率(微信偶尔会动态加载或加JS混淆),但实测对95%以上的主流公众号稳定有效。下面我们就从零开始,把这套系统真正跑起来。
2. 整体架构设计与选型逻辑:为什么是 Docker Compose + MySQL/SQLite?
2.1 架构分层:三层解耦,各司其职
wewe-rss 的设计非常清晰,不是把所有功能塞进一个大黑盒,而是明确划分为三个独立服务模块,通过标准 HTTP 接口通信:
- wewe-rss-core:核心服务,负责调度抓取任务、解析 HTML、生成 RSS XML、提供 Web UI 管理界面。它本身不存数据,只读写数据库。
- Database:数据存储层,存放公众号元信息(名称、ID、URL)、已抓取文章记录、订阅状态等。这是整个系统的状态中心。
- Redis(可选但强烈推荐):缓存与队列中间件,用于去重(防止同一篇文章重复入库)、任务排队、锁机制(避免同一公众号被多个实例同时抓取)。虽然 SQLite 模式下可以不用 Redis,但一旦你接入超过5个公众号,没有 Redis 的去重能力,很快就会遇到重复条目问题。
这三层之间完全解耦,意味着你可以:
- 把 core 服务部署在一台低配 VPS 上,数据库放在另一台更稳定的服务器上;
- 测试阶段用 SQLite 快速验证流程,上线后再无缝切换到 MySQL;
- 后期需要横向扩展时,只需增加 core 实例数量,数据库保持单点即可(MySQL 本身支持读写分离)。
提示:官方文档里提到“支持 PostgreSQL”,但社区实测反馈,PostgreSQL 在中文全文检索、JSON 字段处理上反而不如 MySQL 灵活,且 Docker 镜像维护不如 MySQL 活跃。除非你已有成熟的 PG 运维体系,否则不建议为 wewe-rss 单独引入新数据库栈。
2.2 数据库选型:SQLite 是玩具,MySQL 才是生产主力
很多人看到 “SQLite” 就觉得“轻量=简单=适合我”,这是个典型误区。我们来算一笔账:
| 场景 | SQLite 适用性 | MySQL 适用性 | 关键差异 |
|---|---|---|---|
| 单用户、≤3个公众号、每日抓取≤50篇文章 | ✅ 完全胜任 | ⚠️ 大材小用 | SQLite 文件锁机制在高并发写入时会阻塞,MySQL 行级锁无此问题 |
| 多用户共用、≥10个公众号、需历史归档/全文搜索 | ❌ 易崩溃、无法远程访问 | ✅ 原生支持 | SQLite 是文件,不能被网络共享;MySQL 是服务,支持远程连接、权限控制 |
| 需要定时备份、监控慢查询、设置主从同步 | ❌ 无内置工具 | ✅ 标准运维流程 | MySQL 自带 mysqldump、slow log、binlog,SQLite 只能靠 cp 文件备份,出错难回滚 |
我自己的生产环境用的是 MySQL 8.0,原因很实在:上周有个合作号突然发布了一篇含127张高清图的长文,wewe-rss 抓取时生成了近4MB的 HTML 内容存入数据库。SQLite 在写入这么大的 blob 字段时,文件大小瞬间暴涨,导致磁盘 I/O 飙升,整个系统卡顿了6分钟。换成 MySQL 后,同样操作耗时稳定在1.2秒内,因为 InnoDB 的页式存储和 WAL 日志机制天然适配大字段写入。
注意:MySQL 8.0 默认启用
caching_sha2_password认证插件,而 wewe-rss 的 Go 驱动(go-sql-driver/mysql)旧版本不兼容。部署时必须显式指定--default-authentication-plugin=mysql_native_password,否则你会卡在“Error 1251: Client does not support authentication protocol requested by server”。
2.3 Docker Compose:不是为了炫技,而是解决“在我机器上能跑”的终极难题
为什么不用纯 Docker 命令?为什么不用 Kubernetes?因为 wewe-rss 的本质是“工具型服务”,不是“平台型服务”。它的用户绝大多数是单机部署、小团队协作,目标是“30分钟内让 RSS 订阅跑起来”,而不是构建一套可弹性伸缩的微服务云平台。
Docker Compose 的价值,在于它把三个服务的依赖关系、网络互通、卷挂载、环境变量注入,全部声明在一个 YAML 文件里。你不需要记住docker run -d --network wewe-net --mount type=bind,source=/data/mysql,target=/var/lib/mysql ...这种冗长命令,只需要docker-compose up -d一行启动。更重要的是,它天然支持“环境隔离”——开发、测试、生产可以共用同一份 compose 文件,仅通过.env文件切换数据库地址、端口、密码,彻底告别“配置地狱”。
举个真实例子:我们团队有位非技术人员同事,她负责管理公司内部的“政策法规”公众号订阅源。我给她一份预配置好的docker-compose.yml和env.example,她只需要用文本编辑器把MYSQL_ROOT_PASSWORD=your_secure_password改成她自己设的密码,保存为.env,然后双击一个批处理脚本(Windows 下是start-docker.bat),5分钟后她的 RSS 地址http://localhost:3000/rss/zhengce就能被 Outlook 订阅了。这就是 Docker Compose 带来的确定性。
3. 部署实操全流程:从零到 RSS 订阅地址
3.1 环境准备:Ubuntu 22.04 LTS 是最稳妥的选择
虽然 wewe-rss 官方说支持 macOS 和 Windows WSL,但我的经验是:生产环境请务必使用 Ubuntu 22.04 LTS(或 Debian 11)。原因有三:
- Docker 官方镜像优先适配 Debian/Ubuntu 系统,特别是 MySQL 8.0 的 ARM64 镜像,在 Ubuntu 上启动成功率 100%,在 CentOS Stream 9 上曾出现
libaio.so.1: cannot open shared object file的兼容性错误; - Ubuntu 的 systemd 服务管理更成熟,方便你后续把
docker-compose up -d注册为开机自启服务,避免服务器重启后 RSS 服务消失; - 包管理器 apt 更稳定,安装
curl,git,unzip等基础工具不会像 Alpine Linux 那样需要额外装apk add --no-cache ca-certificates来解决证书问题。
具体步骤(以 root 用户执行):
# 更新系统并安装基础工具 apt update && apt upgrade -y apt install -y curl wget git unzip vim net-tools # 安装 Docker Engine(官方推荐方式) curl -fsSL https://get.docker.com -o get-docker.sh sh get-docker.sh usermod -aG docker $USER # 安装 Docker Compose(v2.20+,注意不是旧版 docker-compose v1) curl -L "https://github.com/docker/compose/releases/download/v2.20.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose chmod +x /usr/local/bin/docker-compose # 验证安装 docker --version # 应输出 Docker version 24.x.x docker-compose --version # 应输出 Docker Compose version v2.20.2注意:不要用
apt install docker-compose,Ubuntu 官方仓库里的版本太旧(v1.29.x),不支持profiles、deploy.resources.limits等新特性,会导致 wewe-rss 的 compose 文件解析失败。
3.2 数据库初始化:MySQL 8.0 的 5 个关键配置项
MySQL 不是装完就能用。wewe-rss 对数据库有明确要求,必须提前配置好,否则启动后 core 服务会报错退出。以下是我在生产环境验证过的最小可行配置(修改/etc/mysql/mysql.conf.d/mysqld.cnf):
[mysqld] # 1. 字符集必须为 utf8mb4,否则微信文章里的 emoji 和生僻字会变 ?? collation-server = utf8mb4_unicode_ci character-set-server = utf8mb4 # 2. 最大连接数至少 200,wewe-rss 默认开启 10 个抓取 goroutine,每个可能占用 1~2 连接 max_connections = 300 # 3. 事务隔离级别设为 READ-COMMITTED,避免幻读影响去重逻辑 transaction-isolation = READ-COMMITTED # 4. 开启慢查询日志(可选但强烈建议),便于排查抓取卡顿 slow_query_log = 1 slow_query_log_file = /var/log/mysql/mysql-slow.log long_query_time = 2 # 5. 关键!禁用 strict mode,否则 wewe-rss 插入空字符串到 NOT NULL 字段会失败 sql_mode = "STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION" # 替换为以下宽松模式(去掉 STRICT_TRANS_TABLES) sql_mode = "NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION"配置完重启 MySQL:
systemctl restart mysql # 验证字符集 mysql -u root -p -e "SHOW VARIABLES LIKE 'character_set%'; SHOW VARIABLES LIKE 'collation%';" # 输出中 character_set_server 和 collation_server 必须为 utf8mb4接着创建专用数据库和用户(绝不使用 root 用户连接应用):
CREATE DATABASE wewe_rss CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE USER 'wewe'@'%' IDENTIFIED BY 'YourStrongPassword123!'; GRANT ALL PRIVILEGES ON wewe_rss.* TO 'wewe'@'%'; FLUSH PRIVILEGES;实操心得:密码里一定包含大小写字母+数字+特殊符号,但避免使用 @、$、! 等 shell 特殊字符。因为 Docker Compose 的环境变量会经过 shell 解析,
MYSQL_PASSWORD=My@Pass!会被截断。安全做法是用单引号包裹:MYSQL_PASSWORD='My@Pass!'。
3.3 Docker Compose 文件编写:一份能直接抄作业的配置
新建目录mkdir -p ~/wewe-rss && cd ~/wewe-rss,创建docker-compose.yml。这份配置是我经过 3 轮迭代优化后的生产版,已移除所有注释,确保可直接运行:
version: '3.8' services: # Redis 缓存服务(必需) redis: image: redis:7-alpine container_name: wewe-redis restart: unless-stopped command: redis-server --save 60 1 --loglevel warning volumes: - ./redis-data:/data networks: - wewe-net # MySQL 数据库服务 mysql: image: mysql:8.0 container_name: wewe-mysql restart: unless-stopped environment: MYSQL_ROOT_PASSWORD: 'rootpass123' MYSQL_DATABASE: 'wewe_rss' MYSQL_USER: 'wewe' MYSQL_PASSWORD: 'wewe_pass_2024' volumes: - ./mysql-data:/var/lib/mysql - ./mysql-init:/docker-entrypoint-initdb.d networks: - wewe-net healthcheck: test: ["CMD", "mysqladmin", "-u", "root", "-p$$MYSQL_ROOT_PASSWORD", "ping", "-h", "localhost"] timeout: 20s retries: 10 # wewe-rss 核心服务 wewe-rss: image: ghcr.io/whyour/wewe-rss:latest container_name: wewe-rss restart: unless-stopped ports: - "3000:3000" environment: # 数据库连接 DB_TYPE: mysql DB_HOST: mysql DB_PORT: 3306 DB_NAME: wewe_rss DB_USER: wewe DB_PASS: wewe_pass_2024 # Redis 连接 REDIS_URL: redis://redis:6379/0 # 时区(重要!否则发布时间显示错误) TZ: Asia/Shanghai # 抓取间隔(单位:分钟),默认 30,可调为 15 或 60 FETCH_INTERVAL: 30 # 是否启用 HTTPS(若前端有 Nginx 反代,此处设 false) ENABLE_HTTPS: false depends_on: mysql: condition: service_healthy redis: condition: service_started volumes: - ./data:/app/data - ./logs:/app/logs networks: - wewe-net networks: wewe-net: driver: bridge关键点解析:
healthcheck为 MySQL 设置了健康检查,确保 wewe-rss 启动前数据库已就绪,避免因启动顺序导致 core 服务反复崩溃;depends_on不是简单的“先启后启”,而是结合condition: service_healthy实现真正的依赖等待;volumes中./data是 wewe-rss 存储抓取缓存、RSS XML 文件的目录,./logs方便你随时查看抓取日志(tail -f logs/app.log);TZ: Asia/Shanghai是硬性要求,微信公众号发布时间是东八区时间,如果容器内时区不对,生成的<pubDate>标签会比实际晚8小时,导致 RSS 阅读器排序错乱。
创建.env文件(用于覆盖环境变量,更安全):
MYSQL_ROOT_PASSWORD=rootpass123 MYSQL_PASSWORD=wewe_pass_2024 WEEWE_RSS_DB_PASS=wewe_pass_20243.4 一键启动与首次配置:Web UI 的 3 个必填项
执行启动命令:
docker-compose up -d # 查看服务状态 docker-compose ps # 实时查看 wewe-rss 日志(按 Ctrl+C 退出) docker-compose logs -f wewe-rss等待约 30 秒,打开浏览器访问http://你的服务器IP:3000。首次访问会跳转到/setup页面,这里只有 3 个输入框,但每一个都决定后续能否正常工作:
- Admin Username:后台管理员用户名,建议用英文,如
admin; - Admin Password:密码,至少8位,含大小写字母+数字;
- RSS Base URL:这是最关键的!它决定了你最终生成的 RSS 地址。
- 如果你直接用 IP 访问,填
http://192.168.1.100:3000; - 如果你用域名
rss.yourcompany.com并做了 Nginx 反代,填https://rss.yourcompany.com; - 绝对不要填
http://localhost:3000,否则生成的 RSS 里所有链接都是 localhost,外部阅读器无法访问。
- 如果你直接用 IP 访问,填
填写完毕点击 Submit,页面会跳转到登录页。用刚设的账号密码登录,进入主界面。
3.5 添加第一个公众号:URL、ID、抓取策略的实操细节
点击左上角+ Add Feed,弹出表单。这里不是随便填个公众号名字就行,必须按规范操作:
Feed Name:任意,如
腾讯新闻;Feed URL:必须是该公众号的主页 URL,格式为
https://mp.weixin.qq.com/mp/homepage?__biz=xxxxxx或https://mp.weixin.qq.com/s?__biz=xxxxxx。如何获取?打开微信网页版,搜索该公众号,点进主页,地址栏复制完整 URL。注意:不能是某篇文章的链接,必须是主页。
__biz=后面那一串字母数字就是公众号唯一 ID,wewe-rss 会自动提取。Fetch Mode:两个选项:
Latest(默认):只抓取最新发布的 10 篇文章,适合资讯类号,更新快、历史价值低;All:抓取该号所有历史文章(从开通日起),适合知识类、教程类号,但首次抓取可能耗时数小时,且对数据库压力大。建议先用Latest测试,稳定后再切All。
Enable:勾选,否则不抓取。
填完保存,你会看到状态变为Pending,几秒后变成Running。此时打开http://你的服务器IP:3000/rss/腾讯新闻(注意 URL 中的 Feed Name 是 URL 编码后的,空格变-),就能看到标准 RSS XML 了。
实操心得:添加后别急着订阅,先点右侧
Edit进入详情页,找到Test Fetch按钮手动触发一次抓取。观察日志docker-compose logs wewe-rss | grep "fetch success",确认返回status: success且article count: 10。如果报错fetch failed: timeout,大概率是服务器 DNS 解析慢,需在docker-compose.yml的wewe-rss服务下加一行dns: 8.8.8.8。
4. 核心功能深度解析:不只是 RSS,更是内容管道中枢
4.1 RSS 输出结构:为什么它能被所有阅读器识别?
wewe-rss 生成的 XML 不是简单拼接,而是严格遵循 RSS 2.0 规范 ,每个<item>元素都包含阅读器必需的 5 个字段:
<item> <title>【重磅】2024年AI政策白皮书发布</title> <link>https://mp.weixin.qq.com/s/abc123def456</link> <description><p><img src="https://mmbiz.qpic.cn/.../0?wx_fmt=jpeg" /></p><p>全文如下:<br>第一章 总则...</p></description> <pubDate>Mon, 15 Apr 2024 14:23:18 +0800</pubDate> <guid isPermaLink="true">https://mp.weixin.qq.com/s/abc123def456</guid> </item><title>:公众号文章标题,自动去除“【】”等营销前缀(可配置);<link>:原文链接,点击直接跳转微信页面;<description>:HTML 格式正文,保留图片<img>、段落<p>、加粗<strong>,这是 wewe-rss 最核心的价值——不是只给个摘要,而是把微信里“所见即所得”的排版完整还原;<pubDate>:发布时间,精确到秒,时区为+0800,确保全球阅读器正确排序;<guid>:全局唯一标识,值等于<link>,保证阅读器去重。
这个结构之所以能被 Feedly、Inoreader、Thunderbird 甚至苹果 Mail 的 RSS 功能识别,是因为它满足了 RSS 阅读器的“最小可行协议”:只要<title>、<link>、<pubDate>三者齐全,且<description>是合法 HTML 片段,就能成功订阅。wewe-rss 还额外支持<enclosure>标签嵌入音频(如公众号语音消息),但需在配置中开启ENABLE_AUDIO: true。
4.2 Web UI 管理后台:5 个隐藏但高频使用的功能入口
很多人以为 Web UI 就是添加/删除订阅,其实它藏着几个提升效率的“快捷键”:
右上角齿轮图标 → Settings:
这里可以全局调整Fetch Interval(抓取间隔)、Max Articles Per Feed(每号最多存多少篇)、Enable HTTPS(是否强制跳转 HTTPS)。特别注意Clean Old Articles选项,建议设为30天,否则数据库会无限膨胀。左侧菜单
History:
不是看日志,而是查看每篇文章的抓取详情。点进任意一条,能看到Fetched At(抓取时间)、HTML Size(原始 HTML 大小)、Parsed Content Length(纯文本长度)、Image Count(文中图片数)。当你发现某篇文章没抓到图,来这里对比HTML Size和Image Count,如果前者很大后者为0,说明微信用了懒加载 JS,需在Settings里开启ENABLE_JAVASCRIPT_RENDERING: true(会显著增加 CPU 消耗)。Feed 列表右侧
⋯→ Export OPML:
一键导出所有订阅源为 OPML 文件,可直接导入到其他 RSS 阅读器,实现跨平台迁移。OPML 是 RSS 领域的“通用语言”,比手动复制 URL 高效 10 倍。Feed 列表右侧
⋯→ Edit → Advanced Options:
这里有两个神功能:Custom CSS:给生成的 RSS 添加自定义样式,比如body { font-family: "PingFang SC", sans-serif; },让阅读器里显示更美观;Filter Regex:用正则表达式过滤文章,例如^【广告】|^【招聘】,自动屏蔽带特定前缀的文章,免去人工取消订阅。
左下角
System Info:
显示当前Core Version、Database Type、Redis Status、Uptime。当服务异常时,第一眼就能判断是数据库连不上,还是 Redis 挂了,还是 core 进程崩溃。
4.3 SQLite 模式部署:给个人用户的极简方案
如果你只是给自己用,不想折腾 MySQL,SQLite 是完全可行的。只需修改docker-compose.yml中的wewe-rss服务部分:
wewe-rss: # ... 其他配置不变 environment: DB_TYPE: sqlite DB_PATH: /app/data/db.sqlite # 删除 DB_HOST, DB_PORT, DB_NAME 等 MySQL 相关变量 REDIS_URL: "" # SQLite 模式下可关闭 Redis volumes: - ./data:/app/data # SQLite 文件将存于此然后删掉mysql和redis服务块,整个 compose 文件只剩wewe-rss一个服务。启动后,./data/db.sqlite就是你的数据库文件。
用DB Browser for SQLite(免费开源工具)打开它,可以看到三张表:
feeds:存储公众号信息;articles:存储所有抓取的文章,content字段是 HTML 正文;subscriptions:存储 RSS 订阅关系。
注意:SQLite 模式下,
docker-compose up -d启动后,首次访问 Web UI 可能报错database is locked。这是因为多个 goroutine 同时写入 SQLite 文件。解决方案是:在environment中加入GOMAXPROCS: 1,强制 Go 运行时单线程执行,牺牲一点性能换取稳定性。实测对 ≤5 个公众号完全够用。
4.4 生产环境加固:Nginx 反向代理与 HTTPS 的 4 步配置
直接暴露:3000端口不安全,且无法用域名访问。用 Nginx 做一层反代是标配。假设你已申请好rss.yourdomain.com的 SSL 证书(Let's Encrypt),配置/etc/nginx/sites-available/wewe-rss如下:
server { listen 443 ssl http2; server_name rss.yourdomain.com; ssl_certificate /etc/letsencrypt/live/rss.yourdomain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/rss.yourdomain.com/privkey.pem; location / { proxy_pass http://127.0.0.1:3000; 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 协议,否则 Web UI 的实时日志会断连 proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } # 静态文件直接由 Nginx 服务,减轻 core 压力 location /static/ { alias /home/user/wewe-rss/data/static/; expires 1h; } } # HTTP 强制跳转 HTTPS server { listen 80; server_name rss.yourdomain.com; return 301 https://$server_name$request_uri; }启用配置:
ln -sf /etc/nginx/sites-available/wewe-rss /etc/nginx/sites-enabled/ nginx -t && systemctl reload nginx最后,回到 wewe-rss Web UI 的Settings,把RSS Base URL改为https://rss.yourdomain.com,所有生成的 RSS 链接就自动变成 HTTPS 了。
5. 常见问题与排查技巧实录:那些文档里没写的坑
5.1 公众号抓取失败的 5 类原因及对应解法
| 现象 | 日志线索 | 根本原因 | 解决方案 |
|---|---|---|---|
fetch failed: status code 403 | GET https://mp.weixin.qq.com/... 403 | 微信封禁了你的服务器 IP | 更换服务器 IP;或在docker-compose.yml的wewe-rss服务下加extra_hosts: ["mp.weixin.qq.com:117.18.237.29"](用国内 DNS 解析出的 IP,定期更新) |
fetch failed: timeout | context deadline exceeded | 服务器网络延迟高或 DNS 解析慢 | 在wewe-rss服务下加dns: 114.114.114.114;或增大FETCH_TIMEOUT环境变量(默认 30 秒,可设为 60) |
article count: 0 | parsed 0 articles from html | 公众号启用了“原创保护”或“付费阅读”,页面结构变化 | 手动访问该公众号主页 URL,用浏览器开发者工具检查<div class="rich_media_content">是否存在;若不存在,说明该号已不可抓取,需更换 |
image src broken | img src="http://res.wx.qq.com/..." | 微信图片 CDN 加了 Referer 限制 | 在wewe-rss的Settings中开启ENABLE_IMAGE_PROXY: true,wewe-rss 会自动代理图片请求 |
RSS shows old time | <pubDate>Sun, 01 Jan 2000 00:00:00 +0000</pubDate> | 容器时区未设为Asia/Shanghai | 修改docker-compose.yml,确保wewe-rss服务有TZ: Asia/Shanghai,然后docker-compose down && up -d |
实操心得:我遇到过最诡异的问题是,某天所有公众号抓取都失败,日志全是
connection refused。查了半天发现是服务器防火墙ufw默认开启了deny incoming,而 wewe-rss 的抓取请求走的是outgoing,但某些云厂商的防火墙策略会误判。解决方案:ufw allow out on eth0,或干脆ufw disable(生产环境建议精细放行)。
5.2 数据库性能瓶颈:当文章数超 10 万时的 3 个优化动作
wewe-rss 默认的 MySQL 表结构没有索引优化,当articles表突破 10 万行,SELECT * FROM articles WHERE feed_id = ? ORDER BY pub_date DESC LIMIT 20查询会明显变慢(>2s)。这时必须手动加索引:
# 登录 MySQL mysql -u wewe -p wewe_rss # 为 feed_id 和 pub_date 组合加联合索引(最常用查询条件) CREATE INDEX idx_feed_pub ON articles (feed_id, pub_date); # 为 guid 加唯一索引(防止重复插入) ALTER TABLE articles ADD UNIQUE KEY uk_guid (guid); # 清理已删除的旧文章(释放空间) DELETE FROM articles WHERE pub_date < DATE_SUB(NOW(), INTERVAL 90 DAY);注意:
DELETE操作会锁表,建议在业务低峰期执行。更优雅的方式是用pt-archiver工具分批归档,但对小团队来说,直接DELETE更简单。
5.3 Docker Compose 部署失败的 3 个高频陷阱
ERROR: failed to solve: rpc error: code = Unknown desc = executor failed running [/bin/sh -c apk add --no-cache ca-certificates]
这是 Alpine Linux 镜像的证书问题。解决方案:在docker-compose.yml的wewe-rss服务下加platform: linux/amd64(即使你是 AMD64 机器也要显式声明),强制拉取 x86_64 镜像,避开 Alpine。wewe-rss exited with code 1,日志显示failed to connect to database
不是密码错了,而是DB_HOST: mysql这个 hostname 在 Docker 网络里解析失败。检查docker-compose ps,确认mysql容器状态是Up;再执行docker exec -it wewe-rss ping mysql,如果 ping 不通,说明网络没连上,删掉docker-compose down后重试。Web UI 打不开,Nginx 返回
502 Bad Gateway
90% 是因为proxy_pass指向的端口不对。执行docker-compose port wewe-rss 3000,确认输出是0.0.0.0:3000;再检查netstat -tuln | grep :3000,确保宿主机 3000 端口没被其他进程占用。
5.4 安全加固 checklist:上线前必须做的 5 件事
- 修改默认 admin 密码:首次登录后立即在
Settings → Admin Password里重置; - 关闭调试模式:确保
docker-compose.yml中没有DEBUG: true环境变量,否则会暴露敏感路径; - 限制数据库访问范围:MySQL 用户
'wewe'@'%'改为'wewe'@'wewe-net'(Docker 网络名),禁止从外部 IP 连接; - 设置 RSS 订阅密码:在
Settings中开启Require Auth for RSS,为每个 Feed 生成独立 token,防止被恶意爬取; - 定期备份数据库:写个 cron 任务,每天凌晨 2 点执行
mysqldump -u wewe -p'wewe_pass_2024' wewe_rss > /backup/wewe_rss_$(date +\%Y\%m\%d).sql。
我自己的备份策略是:本地保留 7 天,同时用rclone同步到腾讯云