Anubis v1.28.2 配置参数详解

Anubis v1.28.2 两层配置体系详解:环境变量(监听/上游/Cookie/密钥/质询难度/日志)与 botPolicies.yaml(规则字段、四种动作、WEIGH 权重阈值分档、质询算法、status_codes、store 后端),附难度代价、权重叠加、403 定制、网段放行四个实测与生产配置模板。

Anubis安全爬虫WAFGolang2026/10/28

Anubis v1.28.2 配置参数详解

目标:系统梳理 Anubis v1.28.2 的两层配置体系——进程级环境变量与策略级 botPolicies.yaml,逐组解析参数语义、默认值与取值影响,并以四个可复现实验验证关键参数(质询难度代价、WEIGH 权重分档、状态码定制、网段放行)。本文按原生包(systemd 托管)部署形态书写;容器栈部署的编排层参数见 《Anubis 1.28 Docker Compose 部署实战》。

一、环境信息

  • Anubis 版本:v1.28.2(2026-10-28 查询的官方最新稳定版)
  • 部署形态:Debian 系原生包(anubis systemd 模板单元),以 anubis@gitea.service 实例化
  • 配置路径约定(官方 native-install 文档,查询日期 2026-10-28):
    • 环境变量文件:/etc/anubis/<实例>.env(如 /etc/anubis/gitea.env)
    • 策略文件:/etc/anubis/<实例>.botPolicies.yaml(POLICY_FNAME 指向)
    • 出厂默认策略:编译内置于二进制,无独立磁盘文件;anubis --extract-resources <目录> 可导出内置策略与规则片段库(<目录>/data/botPolicies.yaml),/usr/share/doc/anubis/ 下仅有 data/、docs/ 参考目录
  • 验证手段:systemctl restart anubis@gitea + journalctl -u anubis@gitea -o cat 观察加载日志,curl 验证行为变化
  • 本文所有行为验证回显均在 Anubis v1.28.2 实例上实测取得(2026-10-28)

二、前置条件

  1. 已按安装文档完成 Anubis 原生包安装并存在一个受 systemd 托管的实例(systemctl status anubis@<实例> 为 active);尚未部署的读者先完成 《Anubis 1.28 Docker Compose 部署实战》 或原生包安装;
  2. 明确参数修改生效路径:两类配置都只在启动时读取一次,修改后必须重启实例:
sudo systemctl restart anubis@gitea
  1. 日志观察窗口(本文回显均来自此命令,-o cat 只输出消息体便于阅读):
journalctl -u anubis@gitea -o cat --since "5 minutes ago"
  1. 行为验证基线:受保护站点入口(反代转发到的 Anubis 监听端口),本文以 curl 加不同 UA/请求头对照请求。

三、配置体系总览

Anubis 的配置分两层,职责不同、互不替代:

层载体决定什么生效方式
进程层环境变量(systemd EnvironmentFile,即 /etc/anubis/<实例>.env)监听地址、上游目标、Cookie 行为、签名密钥、质询默认难度、日志级别等进程运行参数重启实例
策略层botPolicies.yaml(YAML/JSON 均可,POLICY_FNAME 指定路径)每条请求的裁决规则、权重阈值、质询算法档位、存储后端、蜜罐等流量裁决行为重启实例

两层加载顺序与排错入口:实例启动时先读环境变量(决定「怎么跑」),再加载策略文件(决定「怎么判」)。启动日志的固定锚点是这两行(实测回显):

{"time":"2026-10-27T17:36:51.166704975Z","level":"INFO","source":{"function":"main.run","file":"github.com/TecharoHQ/anubis/cmd/anubis/main.go","line":308},"msg":"loading policy file","fname":"/data/cfg/botPolicy.yaml"}
{"time":"2026-10-27T17:36:51.195711611Z","level":"INFO","source":{"function":"main.run","file":"github.com/TecharoHQ/anubis/cmd/anubis/main.go","line":487},"msg":"listening","url":"http://localhost:8923","difficulty":4,"serveRobotsTXT":true,"target":"http://anubis-1.28.2-backend","version":"v1.28.2","use-remote-address":false,"custom-real-ip-header":"","debug-benchmark-js":false,"og-passthrough":false,"og-expiry-time":86400000000000,"base-prefix":"","cookie-expiration-time":604800000000000,"rule-error-ids":{"deny-amazonbot":"d7f8451854c8a486"},"public-url":""}

(上两行回显取自 v1.28.2 容器栈实验实例,listening 行字段最全。原生 systemd 实例的同名日志为 snake_case 简形,仅含少量字段,2026-10-28 实测:)

{"time":"2026-10-28T02:00:02.206613337Z","level":"INFO","source":{"function":"main.run","file":"github.com/TecharoHQ/anubis/cmd/anubis/main.go","line":308},"msg":"loading policy file","fname":"/etc/anubis/gitea.botPolicies.yaml"}
{"time":"2026-10-28T02:11:52.812839753Z","level":"INFO","msg":"listening","subsystem":"anubis","bind":"127.0.0.1:8239","bind_network":"tcp","version":"v1.28.2","use_remote_address":false,"difficulty":4,"serve_robots_txt":false}

listening 行回显进程层关键参数(difficulty、version、监听地址等,flag 方式启动时还含 target/cookie-expiration-time/rule-error-ids 等),改完环境变量后核对这行即确认生效;策略文件解析失败则进程直接退出(排错见第七节)。

四、环境变量详解

以下变量逐项核对自官方 installation 文档的环境变量表(查询日期 2026-10-28),「实测」标记的条目附本文验证结论。

4.1 网络监听与上游

变量默认值说明
BIND:8923主监听地址(质询入口),可写 127.0.0.1:8923 收敛到本机
BIND_NETWORKtcp监听网络类型,支持 unix(配 SOCKET_MODE 控制套接字权限)
TARGEThttp://localhost:3923质询通过后转发的上游地址,支持 http(s):// 与 unix://
TARGET_HOST/TARGET_SNI/TARGET_INSECURE_SKIP_VERIFY未设上游 TLS 伪装三件套:重写 Host 头 / SNI / 忽略上游证书校验(自签场景用)
USE_REMOTE_ADDRESS未设不信任反代头、直接用 TCP 对端地址作为客户端 IP(无前置反代的裸跑场景)
CUSTOM_REAL_IP_HEADER未设自定义真实 IP 头(如 CF-Connecting-IP),默认读 X-Real-IP
XFF_STRIP_PRIVATEfalse剥离 X-Forwarded-For 中的私有地址跳数

实测:USE_REMOTE_ADDRESS 未设(默认)时,请求缺少 X-Real-IP 头会直接 500,日志 err 为 [misconfiguration] X-Real-IP header is not set(完整排障过程见部署篇 11.1);这是「Anubis 必须置于反代之后」形态的默认假设,直连部署务必补设该变量或让反代传头。

4.2 质询与性能

变量默认值说明
DIFFICULTY4全局默认 PoW 难度(SHA-256 前导零个数);单条规则可在 challenge.difficulty 覆盖
ED25519_PRIVATE_KEY_HEX未设(随机生成)质询凭证签名私钥(hex 编码);多实例共域/持久化凭证必须显式固定
ED25519_PRIVATE_KEY_HEX_FILE未设从文件读私钥(密钥管理器场景)
JWT_HS512_SECRET/_FILE未设HS512 对称签名备选(默认 Ed25519)
OG_PASSTHROUGHfalse质询页透传上游页面 Open Graph 元数据(修复社交卡片)
OG_EXPIRY_TIME24h透传 OG 数据缓存时长
OG_CACHE_CONSIDER_SERVER_TZfalseOG 缓存按服务器时区计算
DEBUG_BENCHMARK_JSfalse质询页显示 JS 基准测试数据(评估难度用)

注:部分早期资料提到 DEBUG_X_ANUBIS_STATUS(响应带 X-Anubis-Status 头显示裁决结果)。v1.28.2 实测该开关不存在——anubis --help 无对应 flag,设置同名环境变量后响应中也没有该头(2026-10-28 实测)。裁决结果请直接看 JSON 日志与 anubis_policy_results 指标,方法见 《Anubis 1.28 常用命令与运维实战(核心篇)》。

难度实测(核心证据):同一请求在 difficulty 4 与 6 下解出 PoW 的代价对比(Python 单线程等价模拟,多核浏览器会分摊但量级一致):

difficulty=4: nonce=19767   hash=00001302…  elapsed=9ms
difficulty=6: nonce=6517540 hash=0000001f…  elapsed=2999ms

每加 1 难度计算量约乘 16(本例 330 倍、约 3 秒)。官方默认策略在极端档用到 difficulty 16(视为「不可能完成」的惩罚档),日常站点 4 起步、对可疑流量分档加码是推荐用法。另一处坑:DIFFICULTY_IN_JWT 影响凭证内难度校验,与 DIFFICULTY 含义不同,勿混用。

密钥实测:未设 ED25519_PRIVATE_KEY_HEX 时每次启动随机生成,日志出现(实测回显):

{"level":"WARN","msg":"generating random key, Anubis will have strange behavior when multiple instances are behind the same load balancer target, for more information: see https://anubis.techaro.lol/docs/admin/installation#key-generation"}

单实例重启也会让历史通行 Cookie 全部作废(用户重新过质询),生产建议固定密钥:openssl rand -hex 32 生成后写入 env 文件。

变量默认值说明
COOKIE_DOMAIN未设(当前 host)通行 Cookie 的 Domain 属性;跨子域共享凭证(如 git.example.com 与 wiki.example.com 共用同一 Anubis 实例群)才需要设为 example.com
COOKIE_DYNAMIC_DOMAINfalse按请求 Host 动态设置 Domain(多域名站点用)
COOKIE_EXPIRATION_TIME168h通行凭证有效期
COOKIE_PREFIXtecharo.lol-anubisCookie 名前缀
COOKIE_SECUREtrueSecure 标记;纯 HTTP 部署必须显式 false,否则浏览器不回传 Cookie 导致循环质询(完整复现见部署篇 11.2)
COOKIE_SAME_SITENoneSameSite 属性;None 要求 HTTPS,HTTP 用 Lax
COOKIE_HTTP_ONLYtrueHttpOnly 标记(防 JS 读凭证)
COOKIE_PARTITIONEDfalseCHIPS 分区 Cookie(跨站 iframe 嵌入场景)
DYNAMIC_COOKIE_SUFFIX未设(自动)凭证名后缀(如 a9d36a45),按 Cookie 配置哈希生成,防同名 Cookie 死循环

实测:HTTP 演示链路(COOKIE_SECURE: false、COOKIE_SAME_SITE: Lax)完成质询后签发 3 枚 Cookie(实测回显):

techaro.lol-anubis-cookie-verification-a9d36a45
techaro.lol-anubis-auth-a9d36a45
techaro.lol-anubis-original-referer-a9d36a45

…-anubis-auth-… 为通行凭证;-cookie-verification- 用于浏览器是否回传 Cookie 的验证位(排障利器:若它存在而 auth 不存在,就是 Secure/SameSite 域属性问题)。

4.4 日志、观测与辅助

变量默认值说明
SLOG_LEVELINFO结构化日志级别 DEBUG/INFO/WARN/ERROR;观测期用 DEBUG 可见每条请求的规则裁决流
METRICS_BIND:9090Prometheus 指标监听地址(独立端口,/metrics 与 /healthz)
METRICS_BIND_NETWORKtcp指标端网络类型
SERVE_ROBOTS_TXTfalsetrue 时由 Anubis 直接应答 robots.txt(内容为逐个点名的 AI 爬虫 Disallow 全站列表)
WEBMASTER_EMAIL未设错误页展示站长邮箱,便于误伤用户申诉
BASE_PREFIX/STRIP_BASE_PREFIX未设挂在子路径下时声明前缀(如 /anubis)
PUBLIC_URL未设对外公布的站点 URL(质询跳转构造用)
REDIRECT_DOMAINS未设质询后允许重定向的域名白名单
FORCED_LANGUAGE跟随 Accept-Language强制质询页语言
SALT未设质询随机盐(保持未设即可,默认从时间源生成)

实测:robots.txt 实际输出以成对的 User-agent: / Disallow: / 段构成,点名列表极长(AddSearchBot、AI2Bot、Amazonbot、AIWebIndex 等 AI 爬虫逐个出现),SERVE_ROBOTS_TXT=true 时无需上游配合即可声明禁止 AI 采集。注意它与策略文件的 robots-txt ALLOW 规则配合使用——Anubis 自己应答该路径,不转发上游。

4.5 实验性/企业版特性(了解即可)

OVERLAY_FOLDER(模板覆盖目录)、USE_TEMPLATES(加载 Go 模板)、CHALLENGE_TITLE/ERROR_TITLE(自定义页面标题)、ASSET_LOOKUP_HEADER 等属 BotStopper(企业版)或实验特性,普通部署不涉及,此处仅作索引,避免误当开源能力。

五、botPolicies.yaml 策略详解

5.1 顶层键总览

键类型作用
bots规则列表逐条匹配、声明裁决(本文核心)
thresholds阈值列表按累积权重分档裁决(CEL 表达式)
status_codes映射自定义 CHALLENGE/DENY 的 HTTP 状态码(默认均 200)
dnsbl映射DNSBL 实时黑名单(默认关闭)
honeypot映射蜜罐路由与封禁实现(默认 naive)
openGraph映射OG 透传的规则化开关
store映射质询状态存储后端(默认 memory)
metrics映射指标端 TLS/BasicAuth/mTLS
impressum字符串页脚版权声明(欧洲合规用)

5.2 规则字段与匹配维度

一条规则的可匹配字段(同一规则内多条件为 AND 关系):

字段类型匹配内容
path_regex正则请求路径
user_agent_regex正则User-Agent
headers_regex映射任意请求头(键=头名,值=正则)
remote_addressesCIDR 列表客户端 IP 段(按 X-Real-IP 或 TCP 对端)
geoip/asns列表GeoIP 国家代码 / 自治域号(需在 env 配 MaxMind 数据库)
expressionCEL 表达式组合条件(如 strcasecmp(header.Get("X-Bot"),"true") == "true")
import路径引用内置/外部规则片段((data)/meta/ai-block-aggressive.yaml 等)
action枚举裁决动作(见 5.3)
weight.adjust整数WEIGH 动作的权重增减量
challenge.difficulty/challenge.algorithm整数/枚举CHALLENGE 动作的难度与算法覆盖

四种动作语义:

  • ALLOW:直接转发上游;
  • DENY:拒绝,返回让爬虫「以为成功」的错误页(默认 200 + Oh noes! 页);
  • CHALLENGE:下发质询页或校验凭证(默认 200 + Making sure you're not a bot! 页);
  • WEIGH:不终止匹配,调整本请求权重后继续评估后续规则与 thresholds。

默认行为:所有规则都未命中时放行(日志记为 default/allow),因此策略必须显式 DENY 危险 UA、显式 CHALLENGE 浏览器流量;只写「白名单」不写兜底质询等于没防护。

5.3 质询算法与难度档位

challenge.algorithm 可选值(官方 challenges 文档,查询日期 2026-10-28;method 字段实测同义):

算法原理适用
fast多线程优化的 SHA-256 PoW(Web Worker/WASM)默认主路径
slow单线程朴素 PoW兼容保留
metarefresh无 JS:客户端等待数秒后刷新页面即通过无障碍/文本浏览器场景,对现代无头爬虫拦截力弱
preactPreact 渲染的质询界面自定义 UI 场景

metarefresh 实测:将阈值档 mild-suspicion 设为 algorithm: metarefresh, difficulty: 1 后,对应流量收到的质询页 anubis_challenge JSON 实测为:

{"rules": {"algorithm": "metarefresh", "difficulty": 1}, "challenge": {"issuedAt": "2026-10-27T17:38:23.71049875Z", "method": "metarefresh", "randomData": "18b3e46b…", "id": "01a17e71-195e-7796-ba63-c2032b552762", …}}

页面无 PoW 计算脚本,客户端无需执行哈希运算。难度档位语义(官方默认策略注释):4 普通质询、16 视为不可能完成的惩罚、21 永不可能。

5.4 thresholds 权重分档(实测)

thresholds 配合 WEIGH 实现渐进式防护:每条命中 WEIGH 的规则增减权重(多规则可叠加),然后按 CEL 表达式从上到下取第一个命中的档位。实测策略:

bots:
  - name: cloudflare-workers
    headers_regex:
      CF-Worker: .*
    action: WEIGH
    weight:
      adjust: 25
  - name: generic-browser
    user_agent_regex: Mozilla|Opera
    action: WEIGH
    weight:
      adjust: 10

thresholds:
  - name: minimal-suspicion
    expression: weight <= 0
    action: ALLOW
  - name: mild-suspicion
    expression: weight > 0
    action: CHALLENGE
    challenge:
      algorithm: metarefresh
      difficulty: 1
  - name: moderate-suspicion
    expression:
      all:
        - weight >= 10
        - weight < 20
    action: CHALLENGE
    challenge:
      algorithm: fast
      difficulty: 4
  - name: extreme-suspicion
    expression: weight >= 20
    action: CHALLENGE
    challenge:
      algorithm: fast
      difficulty: 6

三组实测回显:

① curl 默认 UA(无规则命中,weight=0)→ 200,直接拿到上游页面(minimal-suspicion: ALLOW)
② Mozilla UA(generic-browser,weight=10)→ 质询页 challenge: fast / difficulty 4(moderate-suspicion)
③ Mozilla UA + CF-Worker 头(两规则叠加 weight=35)→ 质询页 rules: fast / difficulty 6(extreme-suspicion)

结论:权重叠加生效、档位逐级加强,这正是官方默认策略「疑罪从轻、阶梯惩罚」的实现骨架(出厂五档:weight <= 0 放行 / > 0 mild / >= 10 moderate / >= 20 severe / >= 30 extreme difficulty 6)。注意质询页内嵌 JSON 的难度字段位置随质询路径有两种形态(challenge.difficulty 或 rules.difficulty),解析时两者都要兼容。

5.5 status_codes 定制(实测)

默认 CHALLENGE/DENY 都回 200(官方注释:最激进的爬虫「非常想要 200」,拿到 200 才停手)。若你的监控体系依赖状态码或明确不惧怕暴露拦截行为,可改:

status_codes:
  CHALLENGE: 403
  DENY: 403

实测回显:

Mozilla CHALLENGE -> HTTP 403
Amazonbot DENY    -> HTTP 403

5.6 remote_addresses 网段放行(实测)

给办公网/内网探测开白(不触发质询):

bots:
  - name: internal-network
    remote_addresses:
      - 10.89.62.0/24
    action: ALLOW

实测(X-Real-IP: 10.89.62.99 + Mozilla UA,命中白名单先于质询规则):

X-Real-IP 10.89.62.99 (internal) -> HTTP 200
<h1>Hello from upstream backend</h1>

搜索引擎真伪校验同样依赖此字段:官方默认策略对 Googlebot 等 UA 同时要求 remote_addresses 落在搜索引擎公布的官方网段,防止「自称 Googlebot」的伪造 UA。

5.7 store 存储后端

后端特性适用
memory单实例内存(默认)单机部署
bbolt单机落盘文件单机大流量,重启凭证不失效
s3apiS3 兼容对象存储(AWS S3/R2/MinIO)多实例共享状态
valkeyRESP 协议远程缓存(Redis 兼容)多实例低延迟共享

多实例共享存储时必须同时固定 ED25519_PRIVATE_KEY_HEX,否则各实例密钥不同、凭证互不承认。

六、生产配置模板

以「公网自托管 Git 服务」为例,给出一份可直接改用的组合模板。

/etc/anubis/gitea.env:

BIND=127.0.0.1:8239
BIND_NETWORK=tcp
DIFFICULTY=4
METRICS_BIND=127.0.0.1:8240
METRICS_BIND_NETWORK=tcp
POLICY_FNAME=/etc/anubis/gitea.botPolicies.yaml
TARGET=http://localhost:3000
ED25519_PRIVATE_KEY_HEX=<openssl rand -hex 32 的输出>
COOKIE_SECURE=true
COOKIE_SAME_SITE=None
WEBMASTER_EMAIL=root@example.com
SLOG_LEVEL=INFO

/etc/anubis/gitea.botPolicies.yaml(骨架,按需增删):

bots:
  - import: (data)/meta/ai-block-aggressive.yaml   # 内置 AI 爬虫黑名单片段(import 规则只能有 import 一个键)
  - import: (data)/bots/_deny-pathological.yaml    # 内置高危 UA 黑名单(内置片段名以 _ 开头)
  - name: well-known
    path_regex: ^/.well-known/.*$
    action: ALLOW
  - name: favicon
    path_regex: ^/favicon.ico$
    action: ALLOW
  - name: robots-txt
    path_regex: ^/robots.txt$
    action: ALLOW
  - name: git-protocol-allow         # git clone 走 HTTP 协议端点放行,避免 CI 被质询
    path_regex: ^/.+/.+/(info/refs|git-upload-pack|git-receive-pack)$
    action: ALLOW
  - name: internal-network
    remote_addresses:
      - 10.0.0.0/8
    action: ALLOW
  - name: generic-browser
    user_agent_regex: Mozilla|Opera
    action: CHALLENGE

status_codes:
  CHALLENGE: 200
  DENY: 200

store:
  backend: bbolt
  parameters:
    path: /var/lib/anubis/gitea/cache.db

store 段 schema 注意:backend + parameters 两键的写法才是 v1.28.2 的有效格式;写成 store: {bbolt: {path: ...}} 这类嵌套不会报错,但会被静默忽略并回落为内存存储(实测确认:错误 schema 下 cache.db 始终不生成,改正后立即落盘)。校验 store 是否生效要看文件是否真的生成,不能只看服务 active。

启动与验证:

sudo systemctl enable --now anubis@gitea
curl -s http://127.0.0.1:8240/metrics | head -3     # 指标端可达

七、常见问题

7.1 策略文件语法错误:实例启动失败

实测复现(v1.28.2 实例加载含未闭合 YAML 列表的策略文件,前台校验视角,2026-10-28 实测):

2026/10/28 02:21:47 can't parse policy file: can't parse policy file /root/policy-broken.yaml: can't parse policy config YAML /root/policy-broken.yaml: error converting YAML to JSON: yaml: line 3: did not find expected ',' or ']'

(systemctl restart 场景下同一行错误出现在 journalctl -u anubis@<实例> -o cat 中,仅路径替换为实例实际加载的策略路径。)

进程直接退出,服务不可用(上游失去 Anubis 后的暴露策略取决于反代怎么配 502)。处理:journalctl -u anubis@<实例> -o cat | tail 看行级错误 → 修正 YAML → 重启。改策略前先做前台校验:v1.28.2 无独立的策略校验子命令,标准做法是临时前台拉起实例、看输出能否走到 listening(完整方法、四类错误实测回显与错误字典见 《Anubis 1.28 常用命令与运维实战(核心篇)》 §四);yamllint 之类工具只能查 YAML 语法,查不出 action 拼错、正则不合法、import 规则混键这类语义错误。生产上建议策略变更走「先在预发实例解析 → 再上生产」的两步法。

7.2 改了参数不生效

两类配置均为启动时读取:systemctl restart anubis@<实例> 后核对 listening 日志行(环境变量)与 loading policy file 行(策略路径)。路径写错时 loading policy file 行的 fname 会直接暴露问题。

7.3 单实例一切正常,加第二台实例后用户反复过质询

两台实例各自随机生成签名密钥,互不承认对方的凭证。解决:两实例共享同一 ED25519_PRIVATE_KEY_HEX + 共享 store(s3api 或 valkey)+ 反代侧保证 X-Real-IP 一致。

7.4 质询通过但社交平台分享卡片显示质询页标题

质询页默认不带上游 OG 元数据。解决:OG_PASSTHROUGH=true(配合 OG_EXPIRY_TIME),或在上游侧用 openGraph 策略段对爬虫类 UA 放行 OG 抓取路径。

7.5 CI/CD 与 API 客户端被质询拦截

为这类机器流量开显式白名单:固定出口 IP 用 remote_addresses ALLOW;无法固定的(如 GitHub Actions)用 headers_regex 匹配自有标记头放行,或让 CI 走独立域名/端口绕开 Anubis。

八、参考链接