Files
agento3/SOUL.md
akiba 085cc7a140 AO3 Mirror v4 — initial commit
Cookie-aware proxy pool with CF challenge solving
- Tiered proxy pool (fast 50 + main 676)
- Per-proxy cf_clearance cookie persistence
- CF challenge detection + user-browser solving
- Safari + Chrome TLS fingerprint rotation
- Async FastAPI backend with LRU cache
- Passive daemon with systemd supervision
- Stats dashboard + Prometheus metrics
2026-06-23 08:04:04 +00:00

8.1 KiB
Raw Blame History

AO3 Mirror — SOUL v4

项目宗旨

为中国用户恢复 archiveofourown.org 的访问。维护一个高可用、高效、经济的反向代理镜像站。 目标:单台服务器承受 200+ QPSCF 5 秒盾自动求解。

核心指标

指标 当前值 目标
本地 QPS缓存命中 720 QPS ≥200
平均延迟(缓存命中) 14-42ms ≤100ms
代理存活率AO3/CF ~72% (最佳端口) ≥70%
代理池 726 WebShare (最佳端口)
有效代理 ~524 (72%) ≥500
Cookie 代理 ≥200 (持有 cf_clearance)
CF 挑战 主动求解 (用户浏览器) 零感知
用户 ──→ Cloudflare CDN ──→ Caddy (443, 60s) ──→ 2× uvicorn workers (8081-8082) [全异步]
                                                       │
                                                ┌──────┴──────┐
                                                │  Tiered Pool │
                                                │              │
                                                │  Fast (50)   │ ← POST/login (8s, 1 retry)
                                                │  Main (676)  │ ← GET/browse (15s, 2 retries)
                                                │              │
                                                │  Cookie 感知  │ ← 每个代理持有自己的 cookie jar
                                                │  (cf_clearance│    成功请求后自动保存 Set-Cookie
                                                │   等持久化)   │    后续请求自动注入
                                                └──────┬──────┘
                                                       │
                                              curl_cffi AsyncSession
                                              (safari15_5/17_0, chrome123/124
                                               TLS 指纹 + 连接复用)

v4 关键改进

改进 v3 v4
Cookie 持久化 裸请求 每代理 cookie jar
CF 挑战检测 当代理死亡 分离检测,不退避
CF 挑战求解 放弃 用户浏览器自动求解
代理亲和性 随机 Challenge token 保证同 proxy
TLS 指纹 chrome123/124 safari15_5, safari17_0, chrome123/124
统计准确度 alive=total (假数据) 实时遍历计数
Cookie 代理数 N/A 统计面板展示
用户感知 502 错误页 短暂「检查浏览器」→ 自动恢复

核心组件

1. 异步代理池 (proxy_pool.py) v4

  • ProxySession — 每个代理持有自己的 AsyncSession + cookie jar
  • Cookie 生命周期:成功请求自动保存 → 过期自动清理 → 后续请求自动注入
  • CF 挑战分离:mark_challenged()mark_failure() — 不退避
  • 加权轮询:响应速度越快的代理,被选中的概率越大
  • 指数退避:仅对真失败 (connection error/timeout) → 5s→15s→30s→60s→120s→300s
  • Cookie-aware 选择:get_proxy_with_cookies() 优先返回持有 cf_clearance 的代理

2. 异步抓取器 (ao3_fetcher.py) v4

  • async fetch_url() — Cookie 感知 + CF 挑战检测 + 智能重试
  • is_cf_challenge() — 检测 403/503 是否为 CF 挑战页body markers + Server header
  • 智能重试策略:
    1. 首次尝试 → 优先用带 cookie 的代理
    2. 遇到 CF 挑战 → 换代理(不退避)
    3. 遇到真失败 → 退避 + 换代理
  • 重试 2 次fast 路径 1 次)
  • 请求超时15s (普通), 8s (交互)

3. 后端服务 (app.py) v4

FastAPI绑定 127.0.0.1。

  • Challenge token 映射_challenge_map[token] → (method, url, headers, body, proxy_host)
    • 用户浏览器求解 CF 挑战时保证后续请求使用同一代理IP 亲和性)
    • TTL 120s过期自动清理
  • 挑战页面透传:所有代理都遇 CF 挑战 → 重写页面 → 发给用户浏览器
    • 注入 _cf_token cookie 和 meta 标签
    • 用户浏览器自动执行 CF JS → 验证通过 → redirect 回镜像
    • Worker 捕获 cf_clearance → 保存到代理 cookie jar
  • Cookie 流转发AO3 的 Set-Cookie (用户 session + cf_clearance) 域名重写后传给用户
  • URL 重写:archiveofourown.orgagento3.miscs.dev
  • CORS 全开
  • 端点:/health /stats /metrics /robots.txt

4. 缓存 (cache.py)

  • LRU 实现,容量 5000
  • TTL 按路径差异化首页30s, 章节120s, 图片600s
  • 每个 worker 独立

5. 统计系统 (stats.py) v2

  • 内存热路径:计时器 + 桶式计数 (1s 粒度)
  • SQLite 批量写入:每 60s flush
  • 统计面板新增Cookie 代理数

6. URL 重写器 (url_rewriter.py)

  • HTML/CSS/JS 中 archiveofourown.orgagento3.miscs.dev
  • 响应头 Location/Set-Cookie 重写
  • CF 挑战页面特殊 URL 处理

代理策略

TLS 指纹(按优先级)

  1. safari15_5 — 最高 CF 绕过率
  2. safari17_0 — 次优
  3. chrome123 — 稳定
  4. chrome124 — 稳定

已弃用chrome110, chrome116 (100% 被CF拦截), chrome120, edge120 (低成功率)

代理分级

  1. Fast Pool (50): 最快代理,用于 POST/登录/注册 (8s timeout, 1 retry)
  2. Main Pool (676): 全部可用代理,用于 GET/浏览 (15s timeout, 2 retries)
  3. Cookie 池: 持有 cf_clearance 的代理,优先使用

代理扫描器 (scripts/scan_proxies_cffi.py)

  • curl_cffi 2 种浏览器指纹 (chrome123/124)
  • 50 并发线程
  • 每 30 分钟 cron 自动扫描
  • 仅扫描最佳端口范围 13500-14499 (72.6% 成功率)
  • 结果排序(快→慢)

负载均衡

Caddy (agento3.miscs.dev:443)
  ├── Round Robin → 127.0.0.1:8081
  └── Round Robin → 127.0.0.1:8082

自维护框架(被动模式)

层级 类型 频率 作用
daemon.py systemd service 30s 轮询 Worker 被动监督3 次挂才重启
代理刷新 Hermes cron 30min 重新扫描代理池
统计报告 Hermes cron 1h 聚合指标 + 异常告警

不运行e2e 测试、Caddy 检查、文件日志、主动健康检查全部 726 代理

关键路径

/home/ubuntu/
├── proxy.txt                          # 5000 原始代理
├── ao3-mirror/
│   ├── app.py                         # FastAPI v4 (cookie-aware + CF solver)
│   ├── proxy_pool.py                  # 异步代理池 v4 (cookie jar)
│   ├── ao3_fetcher.py                 # 异步抓取器 v4 (CF detection)
│   ├── cache.py                       # LRU 缓存 (5000)
│   ├── stats.py                       # 内存热路径统计 v2
│   ├── url_rewriter.py                # URL 重写
│   ├── Caddyfile                      # Caddy 配置
│   ├── start.sh / stop.sh
│   ├── ao3-mirror.service / ao3-daemon.service
│   ├── SOUL.md                        ← 本文档
│   ├── scripts/
│   │   ├── daemon.py                  # 自维护守护进程
│   │   ├── scan_proxies_cffi.py       # TLS 指纹代理扫描
│   │   └── restart_workers.py         # Worker 重启工具
│   └── worker-*.log                   # Per-worker stdout logs
/dev/shm/
├── working_proxies.txt               # 有效代理
├── ao3_stats.db                      # 统计数据(冷存储)
└── ao3/
    └── status.json                   # 守护进程状态

已知限制

  • 每个 worker 独立缓存,无共享层
  • Cookie jar 是内存存储worker 重启后丢失
  • 用户浏览器求解 CF 挑战需要 120s 内完成token TTL
  • 挑战页面 JS 执行依赖用户浏览器环境

下一步

  • Cookie 感知代理层 (v4)
  • CF 挑战检测与分离 (v4)
  • 用户浏览器 CF 挑战求解 (v4)
  • 共享缓存层 (Redis/memcached) 跨 worker
  • Cookie jar 持久化 (重启后恢复)
  • 多 proxy provider 源
  • 预加载热门页面到缓存
  • Worker 间 cookie jar 同步