首页
/ cli-anything-adguardhome 技术指南:基于 REST API 的命令行与 Agent 化 AdGuard Home 管理

cli-anything-adguardhome 技术指南:基于 REST API 的命令行与 Agent 化 AdGuard Home 管理

2026-09-07 11:59:01作者:伍希望

AdGuard Home 是一个用 Go 编写的基于 DNS 的全网广告拦截与隐私保护服务,本仓库中的 cli-anything-adguardhome 为它提供了一层"Agent 原生"的命令行封装(harness):CLI 生成结构化命令 → 调用真实 AdGuardHome HTTP API → 校验并解析响应。本文以 ADGUARDHOME.md 为主线,结合 CLI 命令树源码HTTP 客户端封装测试计划,完整讲解其架构、安装、连接配置、全部命令组、双输出模式与测试策略,读完可直接用它完成过滤规则、DNS 改写、客户端、DHCP、统计与查询日志的日常运维,并让 LLM/Agent 通过标准命令接管整台 AdGuard Home。

一、定位与整体架构

与普通"调用某个二进制"的封装不同,cli-anything-adguardhome真实被控对象是运行中的 AdGuardHome HTTP API,CLI 本身不复制业务逻辑,只负责把人类/Agent 的意图翻译成结构化命令,再将 HTTP 响应整理为可读或机器可读输出。ADGUARDHOME.md 将其角色概括为三步闭环:Generate structured commands → Call the real API → Verify responses

关键连接事实(源自 ADGUARDHOME.mdadguardhome_backend.py):

项目
API 基址 http://<host>:<port>/control/
认证 HTTP Basic Auth,请求头形如 Authorization: Basic base64(user:pass)
默认端口 3000
OpenAPI 规范 AdGuardHome 源码中的 openapi/openapi.yaml
上游服务端接口规模 58 个端点、14 个标签分组
本 CLI 覆盖能力 服务/过滤/成人内容屏蔽/安全浏览/安全搜索/服务屏蔽/客户端/统计/日志/DNS 改写/DHCP/TLS

底层 HTTP 客户端 AdGuardHomeClient 的几个工程化细节值得注意,它们直接决定了命令行行为:

  • Base URL 构造:默认 http://host:port/control,但做了两个端口特判——port == 443 时自动切到 https,且当端口为 80/443 时 URL 中省略端口号(见源码 if port == 443: scheme = "https"port not in (80, 443) 分支)。
  • 会话级 Basic Auth:只要提供 usernamepassword,就把认证挂到 requests.Session 上,所有请求统一携带。
  • 请求超时:统一 timeout=10 秒。
  • POST 双编码策略:body 为 dict/list 时以 application/json 发送;为字符串时以 text/plain 编码发送。
  • 空响应处理:无内容体时返回 {},避免对空串做 JSON 解析。
  • 连接失败引导ConnectionError 会被包装为 RuntimeError,提示信息中直接附带安装命令与 Docker 命令,便于排障。

二、前置条件与安装

CLI 面向的是"已运行"的 AdGuardHome 实例。安装服务端有两种官方方式:

# Linux 原生安装(脚本来自 AdGuardTeam 上游 install.sh,此处仅作为服务端获取途径引用)
curl -s -S -L https://raw.githubusercontent.com/AdguardTeam/AdGuardHome/master/scripts/install.sh | sh -s -- -v

# Docker 运行
docker run --name adguardhome -p 3000:3000 adguard/adguardhome

注意:Docker 方式下容器把 Web/API 服务监听在 3000 端口,初始化向导阶段需保留该端口,否则 API 基址会不同。

安装本 CLI 包本身(见 README.mdsetup.py):

cd adguardhome/agent-harness
pip install -e .
cli-anything-adguardhome --help

setup.py 声明了该包的依赖与入口:

  • 依赖:click>=8.0.0(命令框架)、prompt-toolkit>=3.0.0(REPL 交互)、requests>=2.28.0(HTTP);
  • 入口点:cli-anything-adguardhome = cli_anything.adguardhome.adguardhome_cli:main,安装后即获得同名可执行命令;
  • 环境要求:Python >=3.10
  • 包内附带 skills/*.md 作为 package_data,供安装后引用技能说明。

三、连接配置:解析优先级与 config 子命令组

ADGUARDHOME.md 明确规定了配置解析顺序,而源码 project.py 的实现严格印证了这一顺序:

  1. CLI flags--host--port--username--password
  2. 环境变量AGH_HOSTAGH_PORTAGH_USERNAMEAGH_PASSWORD
  3. 配置文件~/.config/cli-anything-adguardhome.json(等价于 Path.home() / ".config" / "cli-anything-adguardhome.json");
  4. 默认值localhost:3000

load_config 的实现顺序是:先以默认值构造 {host: "localhost", port: 3000, username: "", password: "", https: False} → 若配置文件存在则逐 key 覆盖(JSON 解析失败或读文件异常时静默跳过)→ 再让环境变量逐 key 覆盖文件值;随后 adguardhome_cli.py 的根命令host or cfg["host"] 的方式让 CLI flag 最后兜底。因此四层优先级(flags > env > file > defaults)在代码中成立。配置文件样例:

{
  "host": "localhost",
  "port": 3000,
  "username": "admin",
  "password": "your-password",
  "https": false
}

值得补充的是根命令还额外提供几个文档命令树之外但贯穿全局的开关:

全局选项 作用
--host / --port 覆盖连接目标
--username / --password 覆盖 Basic Auth 凭据
--config <path> 指定非默认位置的配置文件
--https 强制使用 HTTPS(--port 443 时后端已自动切换)
--json 切换为机器可读 JSON 输出

config 子命令

cli-anything-adguardhome config show      # 展示当前生效的连接配置(密码打码为 ***)
cli-anything-adguardhome config save      # 将当前连接参数持久化写入配置文件
cli-anything-adguardhome config test      # 请求 GET /control/status 验证连通性

config save 会通过 save_config~/.config/ 下自动创建目录并写入 JSON;config test 则直接调用 server 状态接口并返回 connected: true 及状态详情。Agent 或脚本在批量操作前,建议先执行 config test 确认目标实例可达(这一点在下方 SKILL.md 的"For AI Agents"一节被明确列为最佳实践)。

四、CLI 命令树总览

ADGUARDHOME.md 给出了完整的命令树,现照录并展开(源码层面每个叶子命令都可在 adguardhome_cli.py 中找到对应装饰器与 click group):

cli-anything-adguardhome
├── config show / save / test
├── server status / version / restart
├── filter list / add / remove / enable / disable / refresh / status / toggle
├── blocking parental status/enable/disable
│          safebrowsing status/enable/disable
│          safesearch status/enable/disable
├── blocked-services list / set
├── clients list / add / remove / show
├── stats show / reset / config
├── log show / config / clear
├── rewrite list / add / remove
├── dhcp status / leases / add-static / remove-static
└── tls status

调用某个子命令时,同一命令树中的命令都以 cli-anything-adguardhome <group> <verb> [options] 形式给出;help 别名同时支持 -h

五、API 标签分组与命令组的映射

AdGuardHome 上游把 REST API 划分为若干标签组。下表来自 ADGUARDHOME.md,左侧为 API 标签组、右侧为本 CLI 实际落地的关键命令:

Group(API) Description Key Endpoints 对应 CLI 能力
global 服务器设置与总控 /status/version/restart server status/version/restart
filtering 基于规则列表的过滤 /filtering/status/filtering/add_url/filtering/remove_url filter list/add/remove/enable/disable/refresh/status/toggle
blocked_services 屏蔽服务品类 /blocked_services/get/blocked_services/set blocked-services list/set
clients 已知客户端设备 /clients/clients/add/clients/delete clients list/add/remove/show
stats DNS 查询统计 /stats/stats_reset/stats_config stats show/reset/config
log 查询日志 /querylog/querylog_config/querylog_clear log show/config/clear
dhcp 内置 DHCP 服务 /dhcp/status/dhcp/leases/dhcp/set_config dhcp status/leases/add-static/remove-static
rewrite DNS 改写规则 /rewrite/list/rewrite/add/rewrite/delete rewrite list/add/remove
parental 成人内容屏蔽 /parental/status/parental/enable/parental/disable blocking parental status/enable/disable
safebrowsing 恶意软件/钓鱼拦截 /safebrowsing/status/safebrowsing/enable/safebrowsing/disable blocking safebrowsing status/enable/disable
safesearch 强制安全搜索 /safesearch/status/safesearch/enable/safesearch/disable blocking safesearch status/enable/disable
tls HTTPS/DoH/DoT 设置 /tls/status/tls/configure/tls/validate tls status

下文按功能域逐一给出可复制、可运行的命令示例,并标注其底层调用的 HTTP 端点与源码模块路径,方便读者对照 core 目录 理解实现。

六、server 与 filter:服务器总控和过滤规则生命周期

server(核心实现见 core/server.py

cli-anything-adguardhome server status    # GET /status —— 展示保护状态(adult/enabled 等)
cli-anything-adguardhome server version   # GET /version —— 展示 AdGuardHome 版本
cli-anything-adguardhome server restart   # POST /restart —— 重启服务,无响应体时输出 {"restarted": true}

filter(核心实现见 core/filtering.py

过滤列表管理是整套工具使用最密集的部分:

# 查看全部过滤订阅与整体状态
cli-anything-adguardhome filter list       # GET /filtering/status

# 只取开关状态与订阅数量
cli-anything-adguardhome filter status     # 结果含 enabled 与 filters_count

# 全局开/关过滤(参数为 on 或 off)
cli-anything-adguardhome filter toggle on
cli-anything-adguardhome filter toggle off # POST /filtering/config {"enabled": bool, "interval": ...}

# 新增一个订阅(URL 为规则列表地址,name 为该订阅命名)
cli-anything-adguardhome filter add --url https://example.com/adblock-list.txt --name "My List"
cli-anything-adguardhome filter add --url https://example.com/whitelist.txt --name "My Whitelist" --whitelist
#    底层 POST /filtering/add_url,body = {"name","url","whitelist"}

# 按 URL 移除订阅(--whitelist 用于指明操作对象是白名单)
cli-anything-adguardhome filter remove --url https://example.com/adblock-list.txt

# 单独启用/禁用某一订阅
cli-anything-adguardhome filter enable  --url https://example.com/list.txt --name "My List"
cli-anything-adguardhome filter disable --url https://example.com/list.txt --name "My List"
#    底层 POST /filtering/set_url,body 的 data.enabled 决定启用与否

# 手动触发全量列表刷新(拉取规则最新版本)
cli-anything-adguardhome filter refresh    # POST /filtering/refresh {"whitelist": bool}

filtering.py 可看到两个实现要点:set_enabled 在开关过滤时会先 GET /filtering/status 读出当前 interval(默认 24 小时),再原样回填到 POST /filtering/config,避免切换开关时把定时刷新周期改掉;set_filter_url 的启用/禁用通过同一端点携带 data.enabled 实现,即上游 /filtering/set_url 的语义。

七、blocking / blocked-services:内容安全与品类屏蔽

blocking 命令组统管三类内容安全功能,接口语义完全对称(status 走 GET、enable/disable 走 POST,实现见 core/blocking.py):

# 成人内容 / 家长控制
cli-anything-adguardhome blocking parental status
cli-anything-adguardhome blocking parental enable
cli-anything-adguardhome blocking parental disable

# 恶意软件与钓鱼网站拦截
cli-anything-adguardhome blocking safebrowsing status
cli-anything-adguardhome blocking safebrowsing enable
cli-anything-adguardhome blocking safebrowsing disable

# 强制安全搜索(搜索引擎自动套用安全模式)
cli-anything-adguardhome blocking safesearch status
cli-anything-adguardhome blocking safesearch enable
cli-anything-adguardhome blocking safesearch disable

对应的底层端点分别为 /parental/{status,enable,disable}/safebrowsing/{status,enable,disable}/safesearch/{status,enable,disable}

blocked-services 用于按服务品类整体屏蔽(例如社交网络、视频流媒体、即时通讯等,服务 id 为 AdGuardHome 内置 schema 定义):

# 查看当前被屏蔽的服务
cli-anything-adguardhome blocked-services list    # GET /blocked_services/get

# 覆盖式设定屏蔽集合(可传多个 id)
cli-anything-adguardhome blocked-services set whatsapp telegram   # POST /blocked_services/set {"ids": [...]}

八、clients / rewrite / dhcp:设备、DNS 改写与 DHCP 租约

clients(核心实现见 core/clients.py

# 列出所有已配置客户端
cli-anything-adguardhome clients list             # GET /clients

# 新增客户端(以 name 命名、ip 作为身份标识之一)
cli-anything-adguardhome clients add --name "My PC" --ip 192.168.1.100   # POST /clients/add

# 按名字移除
cli-anything-adguardhome clients remove --name "My PC"                  # POST /clients/delete

# 查看单个客户端详情(本地在 clients 列表中按 name 匹配后输出)
cli-anything-adguardhome clients show --name "My PC"

adguardhome_cli.pyclients_add 可见:--ip 会被放入 ids=[ip] 数组提交,与 AdGuardHome 客户端模型"一个客户端可有多个标识(IP/MAC/ClientID)"对应。

rewrite(核心实现见 core/rewrite.py

DNS 改写常用于搭建本地域名指向内网 IP,或把某域名固定解析到指定地址:

# 新增规则:域名 -> 解析答案(可为 IP 或 CNAME)
cli-anything-adguardhome rewrite add --domain "myserver.local" --answer "192.168.1.50"   # POST /rewrite/add

# 查看全部改写规则
cli-anything-adguardhome rewrite list             # GET /rewrite/list

# 删除某条规则(需与新增时一致地同时给出 domain 与 answer)
cli-anything-adguardhome rewrite remove --domain "myserver.local" --answer "192.168.1.50"  # POST /rewrite/delete

dhcp(核心实现见 core/dhcp.py

# DHCP 服务状态
cli-anything-adguardhome dhcp status              # GET /dhcp/status

# 当前活动租约
cli-anything-adguardhome dhcp leases              # GET /dhcp/leases

# 添加静态租约(mac + ip 必填,hostname 可空)
cli-anything-adguardhome dhcp add-static --mac AA:BB:CC:DD:EE:FF --ip 192.168.1.50 --hostname nas

# 移除静态租约
cli-anything-adguardhome dhcp remove-static --mac AA:BB:CC:DD:EE:FF --ip 192.168.1.50

九、stats / log:观测 DNS 查询统计与查询日志

stats(核心实现见 core/stats.py

# 查看统计(总查询数、被拦截数、按客户端/域名分类等)
cli-anything-adguardhome stats show                # GET /stats

# 清空统计
cli-anything-adguardhome stats reset               # POST /stats_reset

# 不带参数查看当前保留周期配置;带 --interval 则更新保留天数
cli-anything-adguardhome stats config
cli-anything-adguardhome stats config --interval 30   # 查询/更新 POST /stats_config {"interval": N}

log(核心实现见 core/log.py

# 查看最近查询记录(默认 limit=50,可用 offset 翻页)
cli-anything-adguardhome log show                  # GET /querylog?limit=50&offset=0
cli-anything-adguardhome log show --limit 200 --offset 100

# 查看当前日志配置;或同时更新开关与保留天数
cli-anything-adguardhome log config
cli-anything-adguardhome log config --enabled --interval 90      # 启用并保留 90 天
cli-anything-adguardhome log config --disabled                    # 关闭查询日志

# 清空查询日志
cli-anything-adguardhome log clear                 # POST /querylog_clear

adguardhome_cli.py 的 log_config 实现了一个细节:当只给 --enabled/--disabled 或只给 --interval 时,会先 GET 当前配置读出另一项(interval 缺省沿用现有值、默认 90 天),再整体 POST,避免部分更新覆盖已有设置。

tls

# 查看 HTTPS/DoH/DoT 配置状态
cli-anything-adguardhome tls status                # GET /tls/status(复用 core/server.py 的 get_tls_status)

十、REPL 交互模式与双输出格式

不带任何子命令直接运行会进入 REPL(实现见 adguardhome_cli.py 的 repl 命令,基于 prompt-toolkit 皮肤 repl_skin.py):

cli-anything-adguardhome
# 横幅显示版本与连接目标,交互提示符包含 host:port
# 支持 help(列出全部命令)、exit / quit 退出;输入行经 shlex 切分后复用于同一命令树

REPL 内可直接输入 server statusfilter list 等与命令行完全一致的短语。

输出层面所有命令都支持两种格式(来自 SKILL.md 的 "Output Formats"):

  • 人类可读(默认):dict 按 key: value 逐行打印,list 逐元素输出;
  • 机器可读(--json:整个结果以 indent=2 的 JSON 输出,供 Agent/LLM 解析。
cli-anything-adguardhome filter list
cli-anything-adguardhome --json filter list

此外根命令还隐藏了 错误输出契约main() 捕获 RuntimeErrorrequests 异常;当检测到 --json 时,向 stdout 输出 {"error": "..."} 结构化错误并 exit(1),非 JSON 模式下则向 stderr 打印可读信息——这保证了 Agent 用 --json 驱动的管道永远不会拿到不可解析的输出。

十一、面向 AI Agent 的使用规约

包内技能文档 SKILL.md(发布分发副本位于 skills/cli-anything-adguardhome/SKILL.md)在其 frontmatter 中明确描述自身定位:"Designed for AI agents and power users who need to manage filtering, DNS rewrites, clients, DHCP, and query logs without a GUI",并为程序化调用约定了一组规约:

  1. 始终加 --json:保证输出可解析,不依赖终端格式化;
  2. 检查返回码:0 表示成功,非 0 表示失败;
  3. 失败时读 stderr:错误信息统一走标准错误流;
  4. 文件操作使用绝对路径
  5. config test 再执行其它命令:把连通性校验作为一切批量操作的前置步骤。

十二、测试策略:三层验证

TEST.md 与源码测试把测试分成三层,逐层加固"命令 → 真实 API → 响应校验"的闭环:

1. 单元测试(tests/test_core.py——无需真实 AdGuardHome:

  • unittest.mock 桩掉 HTTP 调用,逐端点断言 method、URL、body 是否拼对;
  • 覆盖 HTTP 客户端构造(默认值、带认证、URL 拼接)、空响应、连接错误包装、配置加载(默认值/文件覆盖/环境变量优先/保存)以及各 core 模块的端点映射;
  • 例如 test_client_url_constructiontest_load_config_env_overridetest_add_filter(断言 POST /filtering/add_url 的请求体)。

2. E2E 测试(tests/test_full_e2e.py——隔离的真实实例:

  • 通过 fixture 拉起官方 adguard/adguardhome Docker 容器,映射到 3001 端口避免与本地实例冲突(测试端口常量为 AGH_TEST_PORT = 3001);
  • 启动后轮询 GET /control/status 等待就绪,再调用 /control/install/configure 完成初始化向导(设置 web/dns 监听与 admin 账号密码);
  • 跑完整业务流:服务器状态、过滤列表、rewrite 生命周期(增→查→删)、stats、config test。文件末尾记录的实测结果为 36/36 全部通过:单元 24、子进程 7、Docker E2E 5(对 AdGuardHome v0.107.73)。

3. 子进程测试(tests/test_full_e2e.pyTestCLISubprocess——验证已安装 CLI 本身:

  • _resolve_cli("cli-anything-adguardhome") 优先解析 PATH 中的已安装命令;未安装时回退 python -m cli_anything.adguardhome.adguardhome_cli(开发态);
  • 设置 CLI_ANYTHING_FORCE_INSTALLED=1 可强制要求真实已安装二进制,用于发布前校验 console script 是否可用;
  • 用例包括 --help 退出码为 0、--json config show 输出合法 JSON、各子命令组的 help 是否完整列出。

本地复现全部测试的命令:

cd adguardhome/agent-harness
python3 -m pytest cli_anything/adguardhome/tests/test_core.py -v
python3 -m pytest cli_anything/adguardhome/tests/test_full_e2e.py -v -s        # 需要 docker pull adguard/adguardhome
CLI_ANYTHING_FORCE_INSTALLED=1 python3 -m pytest cli_anything/adguardhome/tests/ -v -s

十三、从文档到源码的实现索引

若想深入理解某一命令背后的实现,可按下面索引直达对应源码(所有路径均相对本仓库根目录):

关注点 文件
SOP 总览与 API 分组 adguardhome/agent-harness/ADGUARDHOME.md
CLI 入口、命令树、全局选项、REPL、错误契约 adguardhome/agent-harness/cli_anything/adguardhome/adguardhome_cli.py
HTTP 客户端与 URL/认证/超时细节 adguardhome/agent-harness/cli_anything/adguardhome/utils/adguardhome_backend.py
配置解析优先级与持久化 adguardhome/agent-harness/cli_anything/adguardhome/core/project.py
server / filter / blocking / clients / rewrite / dhcp / stats / log 各 core 模块 adguardhome/agent-harness/cli_anything/adguardhome/core/
包内技能文档与 Agent 规约 adguardhome/agent-harness/cli_anything/adguardhome/skills/SKILL.md
分发到 skills 目录的技能副本 skills/cli-anything-adguardhome/SKILL.md
打包元数据与 console script 入口 adguardhome/agent-harness/setup.py
三层测试计划与实测结果 adguardhome/agent-harness/cli_anything/adguardhome/tests/TEST.md
登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.13 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
897
5.8 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
529
593
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
915
1.83 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.58 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.35 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.01 K
515
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
547
388