综合 Anubis 部署笔记:Docker + Nginx unix socket,用 PoW 挑战把爬虫成本抬起来

2026-09-28 21:31:25

Anubis 部署笔记:Docker + Nginx unix socket,用 PoW 挑战把爬虫成本抬起来

项目信息

  • 仓库:
  • 文档站:
  • 容器镜像:ghcr.io/techarohq/anubis:latest

Anubis 是 TecharoHQ 出的 Web AI Firewall,靠工作量证明(Proof of Work)挑战拦截爬虫和 AI 抓取。已在 FFmpeg、GNOME、Arch Linux、Codeberg 等项目上跑着。

它是怎么工作的

Anubis 坐在反向代理(Nginx/Caddy)和目标服务之间,每个被保护的服务需要一个 Anubis 实例。客户端浏览器要跑一段 JS 做数学计算,算出正确结果才放行。对真人用户透明且快,对自动化爬虫则把成本显著抬高。

官方自己的说法是:多数情况下你可能不需要它,直接用 Cloudflare 保护源站就行;只有当不能或不想用 Cloudflare 时才有必要上。它是一个「核选项」——能挡住小型爬虫,也可能误伤 Internet Archive 这类「好爬虫」,后者可以通过 bot policy 显式放行。

安装

官方目前唯一支持的方式就是 Docker 镜像 ghcr.io/techarohq/anubis。容器以 UID 1000 / GID 1000 运行,挂载的卷必须属于该用户或对其可写。

策略文件 policy.yaml

新版用 YAML 写策略:

bots:
# 拦截激进爬虫
- name: pathological-bots
user_agent_regex: (?i:bot|crawler|scraper)
action: DENY
# 对 AI 爬虫发起挑战
- name: ai-bots
user_agent_regex: (?i:gptbot|claude|anthropic|openai)
action: CHALLENGE
status_codes:
CHALLENGE: 200
DENY: 200
store:
backend: memory   # 快速开始用内存;生产用 bbolt
logging:
sink: stdio
level: INFO

生产策略可以直接 import 内置策略库:

bots:
- import: (data)/bots/_deny-pathological.yaml
- import: (data)/bots/aggressive-brazilian-scrapers.yaml
- import: (data)/meta/ai-block-aggressive.yaml
- import: (data)/crawlers/_allow-good.yaml
- import: (data)/common/keep-internet-working.yaml
store:
backend: bbolt
parameters:
path: /data/anubis.bdb

docker run

docker run -d \
--name anubis \
-p 8923:8923 \
-p 9090:9090 \
-e BIND=":8923" \
-e TARGET="http://localhost:3000" \
-e DIFFICULTY="4" \
-e POLICY_FNAME="/config/policy.yaml" \
-v $(pwd)/policy.yaml:/config/policy.yaml:ro \
ghcr.io/techarohq/anubis:latest

docker-compose

services:
anubis:
image: ghcr.io/techarohq/anubis:latest
ports:
- "8923:8923"
- "9090:9090"
environment:
BIND: ":8923"
TARGET: "http://app:3000"
DIFFICULTY: "4"
POLICY_FNAME: "/config/policy.yaml"
METRICS_BIND: ":9090"
SLOG_LEVEL: "INFO"
volumes:
- ./policy.yaml:/config/policy.yaml:ro
restart: unless-stopped
app:
image: your-app:latest
expose:
- "3000"

常用环境变量

以下取自 cmd/anubis/main.go:

变量默认值说明
BIND:8923监听地址
TARGEThttp://localhost:3923后端服务 URL
DIFFICULTY4(1–10)挑战难度,即结果前缀 0 的个数
POLICY_FNAME内置策略 YAML 路径
METRICS_BIND:9090Prometheus 指标与健康检查
COOKIE_EXPIRATION_TIME24h(另有文档写 168h)通行证有效期
SLOG_LEVELINFO日志级别
USE_REMOTE_ADDRESSfalse是否从网络请求读客户端 IP
XFF_STRIP_PRIVATEtrue从 X-Forwarded-For 去掉私网 IP
ED25519_PRIVATE_KEY_HEX_FILE—持久化存储或多实例部署需要的签名密钥
BIND_NETWORK—可选 tcp/unix;用 unix socket 时 BIND 形如 /run/anubis/anubis.sock

健康检查

Docker 侧:

healthcheck:
test: ["CMD", "anubis", "--healthcheck"]
interval: 5s
timeout: 30s
retries: 5
start_period: 500ms

Nginx + Anubis 的 unix socket 模式

这么做的好处是 Anubis 不必额外暴露端口,TLS 和路由都交给 Nginx。

anubis 容器环境:

COOKIE_DOMAIN: "example.com"
TARGET: "unix:/tmp/nginx.sock"
BIND: "/run/anubis/anubis.sock"
BIND_NETWORK: "unix"
SOCKET_MODE: "0770"

nginx 与 anubis 共享 volume,nginx 的 server 段 include 一个 anubis.conf:

location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://anubis:8923;
}

443 的 server 里 include anubis.conf,其余指令移到监听 unix:/tmp/nginx.sock 的 server 段,并加上 set_real_ip_from unix;。如果漏掉这一句,依赖真实 IP 的应用(比如 MediaWiki)会拿不到客户端 IP——$REMOTE_ADDR 会始终是 unix:。

指标与 DNSBL

Prometheus 指标:访问 http://:/metrics。

Anubis 默认对访客 IP 做 DNSBL 查询,而很多 IPv6 并不在数据库里。可以在策略文件里写 dnsbl: false 关掉。

踩坑要点

  • 卷权限:容器以 UID/GID 1000 跑,挂进去的目录和文件属主/权限要对,否则读写策略文件和 bbolt 数据库会失败。
  • 签名密钥:用持久化存储(bbolt)或多实例部署,必须挂 ED25519_PRIVATE_KEY_HEX_FILE。不挂的话,重启或多副本之间签发的通行证互不认,用户会反复过挑战。
  • 难度取舍:DIFFICULTY 越大,客户端算得越久。防护更强,但用户等待也更久。被爬虫打满时往上调,收到用户抱怨慢时往下调。
  • 真实 IP:走 unix socket 时记得 set_real_ip_from unix;,否则后端的 $REMOTE_ADDR 只有一个 unix:。

一个绕不过去的自指

文档站 anubis.techaro.lol 本身就跑着 Anubis。直接抓取会返回 Making sure you're not a bot! 挑战页——想读文档,得用浏览器先过一次 PoW。

复制全文 生成海报 Go 反向代理 爬虫防护 Docker Nginx

推荐文章

程序员茄子在线接单