AdGuard Home Docker Compose 部署指南
AdGuard Home v0.107.79 Docker Compose 部署指南:官方镜像选型、compose 编排(Web 8092/DNS 5331)、API 一键初始化、国内上游切换、数据持久化与升级运维,全流程在 Ubuntu 22.04 实测通过
AdGuard Home Docker Compose 部署指南
目标:本文面向希望在 Ubuntu 22.04 服务器上用 Docker Compose 一键部署 AdGuard Home 全网广告拦截 DNS 服务的读者,给出从创建部署目录、编写 compose 文件、首次初始化(含管理员账号配置)、切换国内上游到功能验证的完整流程,覆盖数据持久化、等价 docker run 对照、日常运维命令、版本升级与常见故障排障,全部命令与回显均已在 Ubuntu 22.04 + AdGuard Home v0.107.79 实测通过。
一、环境信息
本章列明实测环境的软件版本、端口规划与目录约定,所有后续命令与回显均基于此环境,读者可按同样配置复现。
- 操作系统:Ubuntu 22.04(内核 5.15,amd64 架构)
- AdGuard Home 版本:v0.107.79(0.107.x 系列最新稳定版)
- Docker Engine:
docker --version实测Docker version 27.5.1, build 470bca4 - Compose 插件:
docker compose version实测Docker Compose version v2.38.1 - 部署方式:Docker Compose(单服务 + bind mount 数据卷 + 自定义网络)
- 端口规划:宿主机
8092→ 容器内3000(Web 管理界面);宿主机5331→ 容器内53(DNS 服务,TCP/UDP) - 部署目录:
/opt/adguardhome/(内含docker-compose.yml、conf/配置目录、work/数据目录) - 数据网络:自定义网络
adguardhome-net,显式子网10.89.22.0/24,固定容器地址10.89.22.10 - 示例客户端:局域网客户机
10.89.22.1(用于解析验证)
⚠️ 端口说明:宿主机 53 端口通常已被系统自带的 systemd-resolved 占用(stub 监听
127.0.0.53:53,实测ss -lntp | grep :53输出见「十一、常见问题」11.1 节),因此本文 DNS 端口映射规划为5331:53。若你的服务器 53 端口空闲或已按 11.1 节方法释放,可直接改为53:53,让局域网设备无需指定端口即可使用。
二、镜像选型说明
AdGuard Home 官方在 Docker Hub 发布镜像 adguard/adguardhome,与 GitHub Releases 同步出版。本章给出 tag 选型依据与镜像规格实测。
2.1 版本 tag 对照
| tag 形态 | 当前指向(2026-10-18 实查) | 说明 |
|---|---|---|
v0.107.79 | 0.107.x 稳定通道最新版(2026-08-18 发布) | 本文采用,版本固定,升级可控 |
latest | 跟随最新稳定版 | 方便但版本漂移,up 时行为不可预期 |
beta | 0.108.0-b.x 测试通道(当前 v1.0 已进入 beta) | 功能激进,不建议生产 |
edge | 主干每日构建 | 仅用于问题验证 |
💡 技术拓展:镜像 tag 选型策略对比——
策略 特点 适用场景 固定版本 tag( v0.107.79)版本显式可控,升级即改 tag 生产推荐,本文采用 latest自动跟随最新稳定版 个人试验,追求免维护 digest 固定( image@sha256:...)精确到镜像内容不可变 强合规审计环境 本文采用固定版本 tag:DNS 是全网出口依赖的基础服务,升级节奏必须由管理员主动控制,而不是被
latest的自动漂移决定。
2.2 镜像规格实测
镜像拉取后实测(docker images):
docker images adguard/adguardhome --format '{{.Repository}}:{{.Tag}} {{.Size}} {{.ID}}'
实测输出:
adguard/adguardhome:v0.107.79 114MB aba9e3bf0613
镜像约 114MB(Go 静态编译二进制 + alpine 基础层),单机资源占用极小。多架构支持实测(Docker Hub Registry API 查询 tag v0.107.79,2026-10-18):
| 架构/系统 | 镜像压缩体积 |
|---|---|
| amd64/linux | 28 MB |
| arm64/linux | 27 MB |
| arm/linux(v6/v7 两个变体) | 27 MB |
| 386/linux | 27 MB |
| ppc64le/linux | 26 MB |
关键差异解读:x86 服务器选默认 amd64 即可;树莓派等 ARM 设备选 arm64 或 arm/v7,docker pull 会按宿主机架构自动选择,无需手动指定平台。
三、前置条件
部署前确认以下三项,每项均给出验证命令与实测输出。
3.1 Docker 与 Compose 插件已就绪
docker --version && docker compose version
实测输出:
Docker version 27.5.1, build 470bca4
Docker Compose version v2.38.1
3.2 端口占用检查
确认规划端口 8092、5331 未被占用:
ss -lntup | grep -E ':(8092|5331)\s' || echo "端口空闲"
实测输出:
端口空闲
同时查看系统 DNS 端口 53 的占用情况,作为端口规划依据:
ss -lntup | grep -E ':53\s'
实测输出:
udp UNCONN 0 0 127.0.0.53%lo:53 0.0.0.0:* users:(("systemd-resolve",pid=853,fd=13))
tcp LISTEN 0 4096 127.0.0.53%lo:53 0.0.0.0:* users:(("systemd-resolve",pid=853,fd=14))
输出表明 53 端口被 systemd-resolved 的 stub 监听器占用(仅绑定 127.0.0.53),这正是本文选择 5331:53 映射的原因,处理方案详见「十一、常见问题」11.1 节。
3.3 部署目录规划
约定部署目录为 /opt/adguardhome/,创建并确认:
mkdir -p /opt/adguardhome && cd /opt/adguardhome && pwd
实测输出:
/opt/adguardhome
四、部署步骤
本章为 0→1 主线:创建目录 → 编写 compose 文件 → 启动 → 初始化 → 配置上游 → 功能验证。
4.1 创建目录结构
conf/ 存放主配置文件 AdGuardHome.yaml,work/ 存放运行数据(过滤器缓存、查询日志、统计库):
cd /opt/adguardhome && mkdir -p conf work && ls -la
实测输出:
total 20
drwxr-xr-x 5 root root 4096 Oct 18 18:10 .
drwxr-xr-x 9 root root 4096 Oct 18 09:52 ..
drwxr-xr-x 2 root root 4096 Oct 18 18:10 conf
drwxr-xr-x 2 root root 4096 Oct 18 18:10 work
4.2 编写 docker-compose.yml
创建 /opt/adguardhome/docker-compose.yml,内容如下(整体照抄即可):
services:
adguardhome:
image: adguard/adguardhome:v0.107.79
container_name: adguardhome-v0107-web
restart: unless-stopped
ports:
- "8092:3000/tcp"
- "5331:53/tcp"
- "5331:53/udp"
volumes:
- ./conf:/opt/adguardhome/conf
- ./work:/opt/adguardhome/work
networks:
default:
ipv4_address: 10.89.22.10
networks:
default:
name: adguardhome-net
ipam:
config:
- subnet: 10.89.22.0/24
逐项说明:
| 配置项 | 取值 | 说明 |
|---|---|---|
image | adguard/adguardhome:v0.107.79 | 官方镜像固定版本 tag,见第二章选型 |
container_name | adguardhome-v0107-web | 固定名称,便于 docker logs/docker exec 定位 |
restart | unless-stopped | 开机自启、异常退出自动拉起;手动 stop 后不再自动启动 |
ports(8092:3000) | Web 管理界面 | 宿主机浏览器访问 http://服务器IP:8092 |
ports(5331:53) | DNS 服务 | TCP/UDP 必须同时映射(区域传输、超长响应走 TCP) |
volumes(conf) | 主配置 AdGuardHome.yaml | 初始化后自动生成,升级、重建均不丢 |
volumes(work) | 运行数据 | 过滤器缓存、查询日志、统计数据库 |
networks.ipv4_address | 10.89.22.10 | 固定内网地址,便于防火墙精确放行 |
networks.ipam.subnet | 10.89.22.0/24 | 显式声明子网,避免依赖随机分配造成网段冲突 |
⚠️ 子网声明为硬性要求:自定义网络必须显式指定
--subnet,且避开192.168.0.0/16(通常与物理局域网重叠)与100.64.0.0/16(运营商级 NAT 段)。本文取10.89.22.0/24。
💡 技术拓展:DNS 端口映射到 5331 后,局域网设备使用时需指定端口(如
dig @服务器IP -p 5331),路由器全局 DNS 设置通常无法指定端口。两种取舍:
做法 优点 代价 映射 53:53全网设备无感接入(路由器 DNS 直接指向服务器) 需先释放宿主机 53(见 11.1 节) 映射 5331:53(本文实测形态)与系统 DNS 服务零冲突,风险最低 下游设备需支持自定义端口 生产建议以
53:53为目标形态;本文环境因系统服务占用保留 5331。
4.3 启动服务
cd /opt/adguardhome && docker compose up -d
实测输出(首次启动,含网络与容器创建全过程):
Network adguardhome-net Creating
Network adguardhome-net Creating
Network adguardhome-net Created
Network adguardhome-net Created
Container adguardhome-v0107-web Creating
Container adguardhome-v0107-web Created
Container adguardhome-v0107-web Starting
Container adguardhome-v0107-web Started
确认运行状态:
docker compose ps
实测输出:
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
adguardhome-v0107-web adguard/adguardhome:v0.107.79 "/opt/adguardhome/Ad…" adguardhome 1 second ago Up Less than a second 80/tcp, 67-68/udp, 443/tcp, 443/udp, 853/udp, 853/tcp, 3000/udp, 5443/tcp, 5443/udp, 6060/tcp, 0.0.0.0:5331->53/tcp, 0.0.0.0:5331->53/udp, [::]:5331->53/tcp, [::]:5331->53/udp, 0.0.0.0:8092->3000/tcp, [::]:8092->3000/tcp
💡 说明:
PORTS列中80/tcp、67-68/udp、443/tcp、853/tcp等是镜像声明但未映射到宿主机的端口(HTTP 备用、DHCP、HTTPS、DoT/DoQ),只有标有0.0.0.0:5331->、0.0.0.0:8092->的才对外服务。容器启动日志(docker compose logs --tail 12 adguardhome实测节选)可确认监听就绪:adguardhome-v0107-web | 2026/10/18 10:18:25.120561 [info] webapi: serving url=http://10.89.22.10:3000 adguardhome-v0107-web | 2026/10/18 10:18:25.120573 [info] starting plain server server=plain addr=0.0.0.0:3000 adguardhome-v0107-web | 2026/10/18 10:18:25.122400 [info] dnsproxy: creating udp server socket addr=0.0.0.0:53 adguardhome-v0107-web | 2026/10/18 10:18:25.122488 [info] dnsproxy: listening to tcp addr=[::]:53
4.4 确认未初始化状态
首次访问 Web 端口会被重定向到安装向导:
curl -sI http://127.0.0.1:8092/ | head -4
实测输出:
HTTP/1.1 302 Found
Content-Type: text/html; charset=utf-8
Location: /install.html
Date: Sun, 18 Oct 2026 10:17:04 GMT
Location: /install.html 表明服务待初始化。此时也可用安装状态接口查看:
curl -s -w '\nHTTP:%{http_code}\n' http://127.0.0.1:8092/control/install/status
实测输出(未初始化时接口返回 302 跳转向导页):
<a href="/control/install/install.html">Found</a>.
HTTP:302
4.5 完成初始化(两种方式)
方式 A:浏览器向导(推荐首次部署使用)。浏览器打开 http://服务器IP:8092,按向导四步完成:① 欢迎页下一步 → ② 确认 Web/DNS 监听接口与端口(默认 0.0.0.0:3000、0.0.0.0:53)→ ③ 设置管理员账号密码 → ④ 完成并进入控制台。
方式 B:REST API 一键初始化(适合脚本化部署)。本节以 API 形态实测完整过程,管理员账号 admin、密码 q1w2e3r4:
curl -s -X POST http://127.0.0.1:8092/control/install/configure \
-H 'Content-Type: application/json' \
-d '{"web":{"ip":"0.0.0.0","port":3000,"status":""},"dns":{"ip":"0.0.0.0","port":53,"status":""},"username":"admin","password":"q1w2e3r4"}' \
-w '\nHTTP:%{http_code}\n'
实测输出:
OK
HTTP:200
初始化完成后验证三件事:
其一,Web 已从 install.html 切换为登录页:
curl -sI http://127.0.0.1:8092/ | head -3
实测输出:
HTTP/1.1 302 Found
Content-Type: text/html; charset=utf-8
Location: /login.html
其二,配置文件已在挂载目录自动生成(schema_version: 34,全文逐项解读见本专栏《AdGuard Home 0.107.79 配置参数详解》一篇):
ls -l /opt/adguardhome/conf/
实测输出:
total 4
-rw------- 1 root root 4094 Oct 18 10:16 AdGuardHome.yaml
其三,用管理员账号登录管理 API(后续所有 /control/ 接口都依赖该会话 Cookie):
curl -s -c /tmp/ah-cookie.txt -X POST http://127.0.0.1:8092/control/login \
-H 'Content-Type: application/json' \
-d '{"name":"admin","password":"q1w2e3r4"}' -w 'HTTP:%{http_code}\n'
实测输出:
OK
HTTP:200
4.6 配置国内上游 DNS(关键步骤)
⚠️ 新初始化的默认上游是国外 DoH 服务(Quad9),国内网络环境直连不可达,会导致所有解析超时。实测现象(初始化后立即查询,dig 三次重试全部超时):
;; communications error to 127.0.0.1#5331: timed out
;; communications error to 127.0.0.1#5331: timed out
;; communications error to 127.0.0.1#5331: timed out
; <<>> DiG 9.18.39-0ubuntu0.22.04.6-Ubuntu <<>> @127.0.0.1 -p 5331 doubleclick.net +noall +answer
; (1 server found)
;; global options: +cmd
;; no servers could be reached
先看当前上游配置:
curl -s -b /tmp/ah-cookie.txt http://127.0.0.1:8092/control/dns_info | \
python3 -c "import json,sys; d=json.load(sys.stdin); print(json.dumps({k:d[k] for k in ['upstream_dns','bootstrap_dns']}, indent=1))"
实测输出:
{
"upstream_dns": [
"https://dns10.quad9.net/dns-query"
],
"bootstrap_dns": [
"9.9.9.10",
"149.112.112.10",
"2620:fe::10",
"2620:fe::fe:10"
]
}
改用国内可达上游(阿里公共 DNS + 腾讯 DNSPod,明文 UDP 与 DoH 混合,普通 53 端口写法如 223.5.5.5,DoH 写法带完整 URL):
curl -s -b /tmp/ah-cookie.txt -X POST http://127.0.0.1:8092/control/dns_config \
-H 'Content-Type: application/json' \
-d '{"upstream_dns":["223.5.5.5","119.29.29.29","https://dns.alidns.com/dns-query"],"bootstrap_dns":["223.5.5.5","119.29.29.29"]}' \
-w 'HTTP:%{http_code}\n'
实测输出:
HTTP:200
💡 技术拓展:上游 DNS 协议不止一种,AdGuard Home 支持的上游写法对比——
协议 写法示例 端口 特点 明文 UDP/TCP 223.5.5.553 延迟最低,内容可被窥探/篡改 DoH https://dns.alidns.com/dns-query443 走 HTTPS,抗干扰强 DoT tls://dns.alidns.com853 专用端口,协议开销小 DoQ quic://dns.adguard-dns.com853(UDP) 基于 QUIC,握手快 本文混合采用「明文 + DoH」三个上游(两国内明文 + 一国内 DoH),兼顾低延迟与抗污染;
upstream_mode为默认load_balance(多上游并行取最快应答)。
验证解析恢复:
dig @127.0.0.1 -p 5331 www.baidu.com +noall +answer
实测输出:
www.baidu.com. 514 IN CNAME www.a.shifen.com.
www.a.shifen.com. 115 IN A 110.242.69.21
www.a.shifen.com. 115 IN A 110.242.70.57
4.7 验证拦截能力
默认已启用 AdGuard DNS filter 官方过滤列表(初始 186,044 条规则,启动后自动下载完成,日志实测 filtering: filter updated id=1 bytes_written=4458454 rules_count=186099)。再加一条自定义拦截规则演示全链路:
curl -s -b /tmp/ah-cookie.txt -X POST http://127.0.0.1:8092/control/filtering/set_rules \
-H 'Content-Type: application/json' \
-d '{"rules":["||doubleclick.net^","||zhihu.com^"]}' -w 'HTTP:%{http_code}\n'
实测输出:
HTTP:200
对比规则生效前后的解析结果。加规则前(正常解析出真实 IP):
dig @127.0.0.1 -p 5331 doubleclick.net +noall +answer
实测输出:
doubleclick.net. 300 IN A 142.251.45.142
加规则后(拦截为 0.0.0.0,TTL 10 对应 blocked_response_ttl 默认值):
dig @127.0.0.1 -p 5331 doubleclick.net +noall +answer
实测输出:
doubleclick.net. 10 IN A 0.0.0.0
在查询日志接口中也能看到这条被拦截的记录(reason 为 FilteredBlackList、命中规则原文回显):
curl -s -b /tmp/ah-cookie.txt \
'http://127.0.0.1:8092/control/querylog?limit=1&response_status=filtered' | \
python3 -c "import json,sys; d=json.load(sys.stdin)['data'][0]; print(json.dumps({k:d[k] for k in ['question','answer','reason','rule','client','status']}, ensure_ascii=False, indent=1))"
实测输出:
{
"question": {
"class": "IN",
"name": "doubleclick.net",
"type": "A"
},
"answer": [
{
"type": "A",
"value": "0.0.0.0",
"ttl": 10
}
],
"reason": "FilteredBlackList",
"rule": "||doubleclick.net^",
"client": "10.89.22.1",
"status": "NOERROR"
}
4.8 自定义网络与子网自查
创建后自查两件事:子网未落在禁用段、宿主机默认路由未被抢占。
docker network inspect adguardhome-net --format '{{range .IPAM.Config}}{{.Subnet}}{{end}}'
实测输出:
10.89.22.0/24
ip route get 192.168.1.62
实测输出(默认路由仍走物理网卡,未被新网桥抢占):
192.168.1.62 via 192.168.146.2 dev ens33 src 192.168.146.138
五、数据持久化说明
DNS 服务的数据(配置、规则、日志、统计)必须跨重启与升级保留。本章说明持久化机制并实测验证。
5.1 目录映射与数据构成
| 宿主机目录 | 容器内路径 | 内容 |
|---|---|---|
/opt/adguardhome/conf/ | /opt/adguardhome/conf | 主配置 AdGuardHome.yaml(含管理员密码哈希、全部设置) |
/opt/adguardhome/work/ | /opt/adguardhome/work | 运行数据目录 |
work/data/ 下的关键文件实测(docker exec adguardhome-v0107-web ls -la /opt/adguardhome/work/data/):
total 64
drwx------ 3 root root 4096 Oct 18 10:18 .
drwx------ 3 root root 4096 Oct 18 10:16 ..
drwx------ 2 root root 4096 Oct 18 10:17 filters
-rw------- 1 root root 890 Oct 18 10:18 querylog.json
-rw------- 1 root root 32768 Oct 18 10:17 sessions.db
-rw------- 1 root root 32768 Oct 18 10:18 stats.db
逐项说明:filters/1.txt 为过滤列表缓存(AdGuard DNS filter 实测 4,458,454 字节、186,099 行);querylog.json 为查询日志;stats.db 为统计数据库;sessions.db 为登录会话库。只要 conf/ 与 work/ 两个 bind mount 在,容器销毁重建、镜像升级均不丢数据。
💡 技术拓展:容器数据持久化方式对比——
方式 特点 适用场景 bind mount( ./conf:...)路径直观,可直接编辑、tar 备份 本文采用,配置需人工核对场景 named volume( adguard-conf:...)由 Docker 统一管理,迁移需 volume导出无需直接触碰文件的场景 tmpfs 内存盘,随容器消亡 仅缓存类临时数据 本文选 bind mount:AdGuard Home 的配置与数据都是需要定期备份、离线检视的核心资产,宿主机目录直接可见最稳妥。
5.2 重启持久化实测
重启服务并验证规则与配置保留:
cd /opt/adguardhome && docker compose restart
实测输出:
Container adguardhome-v0107-web Restarting
Container adguardhome-v0107-web Started
重启后立即验证拦截规则仍然生效(数据来自挂载目录而非容器层):
dig @127.0.0.1 -p 5331 doubleclick.net +noall +answer
实测输出:
doubleclick.net. 10 IN A 0.0.0.0
5.3 数据备份方法
最简备份即打包两个挂载目录(在 docker compose down 或服务运行时均可执行;运行时备份查询日志可能缺最后几秒,生产建议先 docker compose stop 再备份):
cd /opt/adguardhome && tar czf /opt/backup/adguardhome-$(date +%F).tar.gz conf work && ls -lh /opt/backup/
说明:$(date +%F) 生成 2026-10-18 形式的日期后缀;备份文件建议异地存放。恢复时解包回 /opt/adguardhome/ 后 docker compose up -d 即可,详见本专栏《AdGuard Home 日常运维手册》的备份恢复章节。
六、环境变量表
官方镜像不通过环境变量做业务配置,实测容器内环境仅含系统默认 PATH(docker inspect --format '{{json .Config.Env}}' 输出 ["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"])。全部配置通过命令行参数与挂载的配置文件完成。
镜像内置入口使用的命令行参数实测(docker exec adguardhome-v0107-web /opt/adguardhome/AdGuardHome --help 节选,全量参数以该命令输出为准):
Usage:
/opt/adguardhome/AdGuardHome [options]
Options:
-c, --config VALUE Path to the config file.
-w, --work-dir VALUE Path to the working directory.
--web-addr VALUE Address to serve the web UI on, in the host:port format.
-s, --service VALUE Service control action: status, install (as a service), uninstall (as a service), start, stop, restart, reload (configuration).
-l, --logfile VALUE Path to log file. If empty, write to stdout; if "syslog", write to system log.
--pidfile VALUE Path to a file where PID is stored.
--check-config Check configuration and exit.
--no-check-update Don't check for updates.
--update Update the current binary and restart the service in case it's installed.
--local-frontend Use local frontend directories.
-v, --verbose Enable verbose output.
--glinet Run in GL-Inet compatibility mode.
--no-permcheck Skip checking and migration of permissions of security-sensitive files.
--version Show the version and exit. Show more detailed version description with -v.
--help Print this help.
参数说明表:
| 参数 | 默认行为 | 说明 |
|---|---|---|
-c, --config | /opt/adguardhome/conf/AdGuardHome.yaml | 主配置文件路径,镜像默认已指向挂载目录 |
-w, --work-dir | /opt/adguardhome/work | 工作目录(日志、过滤器缓存) |
-s, --service | 无 | 服务控制(容器内不适用,原生安装时用于注册 systemd 服务) |
-l, --logfile | 输出到 stdout | 容器形态保持默认,由 docker compose logs 收集 |
--no-check-update | 不加则启动时检查更新 | 容器升级应走「换镜像 tag」,故镜像默认命令已带此参数 |
--check-config | — | 校验配置文件后退出,改配置后可先验证 |
--pidfile | 无 | 指定 PID 文件路径,常配合监控脚本 |
如需向容器追加参数,在 compose 服务下使用 command:,例如开启 verbose 日志:
command:
- --no-check-update
- -c
- /opt/adguardhome/conf/AdGuardHome.yaml
- -w
- /opt/adguardhome/work
- -v
版本号确认命令实测:
docker exec adguardhome-v0107-web /opt/adguardhome/AdGuardHome --version
实测输出:
AdGuard Home, version v0.107.79
七、配置参数说明
本章说明部署形态下「改配置的正确入口」,避免误改导致配置回滚。
7.1 两类配置的生效关系
| 配置层 | 文件/位置 | 修改方式 | 生效方式 |
|---|---|---|---|
| Compose 编排层 | docker-compose.yml | 手工编辑 | docker compose up -d(配置变化会自动重建容器) |
| 运行配置层 | conf/AdGuardHome.yaml | 推荐 Web 界面或 REST API | API 修改即时生效并自动回写文件 |
| 运行配置层(直接改文件) | conf/AdGuardHome.yaml | 手工编辑 | 需 docker compose restart 后生效,且运行期间修改会被界面覆盖 |
⚠️ 关键提醒:Web 界面/API 每次改动都会全量回写
AdGuardHome.yaml。若直接手工编辑该文件,务必先docker compose stop再编辑,否则运行中的服务退出时会用内存配置覆盖你的手工修改。
7.2 配置文件校验
手工修改配置后、重启前,用内置校验命令检查语法:
docker exec adguardhome-v0107-web /opt/adguardhome/AdGuardHome --check-config -c /opt/adguardhome/conf/AdGuardHome.yaml -w /opt/adguardhome/work
实测输出(配置正常时):
2026/10/18 10:24:51.814780 [info] AdGuard Home, version v0.107.79
2026/10/18 10:24:51.815044 [info] loading config from file /opt/adguardhome/conf/AdGuardHome.yaml
校验通过(无 error/fatal 行且进程正常退出)即可 docker compose restart 使配置生效;AdGuardHome.yaml 全部字段的逐项含义与默认值见本专栏《AdGuard Home 0.107.79 配置参数详解》一篇。
7.3 常用即时验证命令汇总
| 验证目标 | 命令 | 预期 |
|---|---|---|
| 服务版本 | docker exec adguardhome-v0107-web /opt/adguardhome/AdGuardHome --version | AdGuard Home, version v0.107.79 |
| 运行状态 | curl -s http://127.0.0.1:8092/control/status(带 Cookie) | JSON 中 "running": true |
| DNS 可用 | dig @127.0.0.1 -p 5331 www.baidu.com +short | 返回 IP 列表 |
| 拦截生效 | dig @127.0.0.1 -p 5331 doubleclick.net +short | 0.0.0.0 |
八、配置文件挂载
本章细化两个挂载目录的职责边界与运维注意事项。
8.1 conf 与 work 的职责边界
conf/ 只有一个 AdGuardHome.yaml,是「唯一事实来源」:管理员密码哈希、DNS 上游、过滤规则开关、查询日志策略等全部运行配置都在其中。work/ 是运行数据:过滤器列表缓存(work/data/filters/)、查询日志(work/data/querylog.json)、统计库(work/data/stats.db)、会话库(work/data/sessions.db)。
备份与迁移的最小集合是 conf/ + work/data/(work/ 下其余为临时文件)。
8.2 挂载目录权限
镜像内置权限自检(permcheck)会检查安全敏感文件权限。若宿主机目录权限过宽,启动日志会出现提示(实测日志行):
adguardhome-v0107-web | 2026/10/18 10:20:17.836102 [info] permcheck: warning: found unexpected permissions type=directory path=/opt/adguardhome/work perm=0755 want=0700
该提示为 info 级不阻断启动,但生产建议收紧:chmod 700 /opt/adguardhome/work /opt/adguardhome/conf,容器内进程以 root 运行不受影响。
8.3 修改配置的标准流程
以修改 DNS 缓存大小为例(先停服避免回写覆盖):
cd /opt/adguardhome && docker compose stop
实测输出:
Container adguardhome-v0107-web Stopping
Container adguardhome-v0107-web Stopped
编辑 /opt/adguardhome/conf/AdGuardHome.yaml 中 cache_size 后校验并启动:
docker exec -it adguardhome-v0107-web /opt/adguardhome/AdGuardHome --check-config -c /opt/adguardhome/conf/AdGuardHome.yaml -w /opt/adguardhome/work 2>&1 | tail -1
说明:容器已停止时 docker exec 不可用,此校验命令需在容器运行状态下先执行,或直接启动后观察日志是否有配置解析错误。标准流程为「stop → 编辑 → up -d → 看日志确认无 error」:
cd /opt/adguardhome && docker compose up -d
实测输出:
Container adguardhome-v0107-web Running
启动后 docker compose logs --tail 5 adguardhome 中出现 dnsproxy: cache enabled size=... 即配置已生效(实测日志行:dnsproxy: cache enabled size=4194304,对应默认 4MB 缓存)。
九、等价 docker run 对照
不使用 compose 时,等价的 docker run 命令如下(与第四章 compose 配置逐项对应):
docker run -d --name adguardhome-v0107-run \
--restart unless-stopped \
-p 8097:3000/tcp -p 5335:53/tcp -p 5335:53/udp \
-v /opt/adguardhome-run/conf:/opt/adguardhome/conf \
-v /opt/adguardhome-run/work:/opt/adguardhome/work \
adguard/adguardhome:v0.107.79 \
--no-check-update -c /opt/adguardhome/conf/AdGuardHome.yaml -w /opt/adguardhome/work
对照关系表:
| compose 写法 | 等价 docker run 写法 |
|---|---|
image: adguard/adguardhome:v0.107.79 | 末位镜像参数 |
container_name: adguardhome-v0107-web | --name adguardhome-v0107-run(对照实例独立命名) |
restart: unless-stopped | --restart unless-stopped |
ports: "8092:3000/tcp" 等 | -p 8097:3000/tcp -p 5335:53/tcp -p 5335:53/udp |
volumes: ./conf:... 等 | -v /opt/adguardhome-run/conf:... -v /opt/adguardhome-run/work:... |
networks(自定义网络/子网) | --network adguardhome-net(需先 docker network create --subnet 创建) |
| (无显式 command) | 镜像内置 CMD 即为 --no-check-update -c ... -w ...,两者实际等价 |
本环境另有一个按上述 run 形态部署的对照实例(Web 8097、DNS 5335),实测验证其与 compose 形态行为一致:
curl -s -o /dev/null -w 'Web_HTTP:%{http_code}\n' http://127.0.0.1:8097/ && \
docker exec adguardhome-v0107-run /opt/adguardhome/AdGuardHome --version && \
dig @127.0.0.1 -p 5335 www.baidu.com +noall +answer +stats | tail -5
实测输出:
Web_HTTP:302
AdGuard Home, version v0.107.79
;; Query time: 46 msec
;; SERVER: 127.0.0.1#5335(127.0.0.1) (UDP)
;; WHEN: Sun Oct 18 18:14:42 CST 2026
;; MSG SIZE rcvd: 146
选型建议:单机长期运行选 compose(声明式、可版本控制、升级一条命令);临时验证、CI 冒烟测试选 docker run;两者混用时注意端口与数据目录不能复用,否则会互相抢锁或报端口冲突。
十、常用运维命令
本章给出 compose 形态的日常运维命令与实测回显。
10.1 启停与状态
cd /opt/adguardhome && docker compose stop && docker compose start
实测输出:
Container adguardhome-v0107-web Stopping
Container adguardhome-v0107-web Stopped
Container adguardhome-v0107-web Starting
Container adguardhome-v0107-web Started
stop 保留容器与网络,start 秒级恢复;需要释放网络与容器时用 docker compose down(数据目录不受影响),再 up -d 即可完整重建。
10.2 日志查看
docker compose logs --tail 8 adguardhome
实测输出:
adguardhome-v0107-web | 2026/10/18 10:21:05.530948 [info] filtering: saving contents id=1 path=/opt/adguardhome/work/data/filters/1.txt
adguardhome-v0107-web | 2026/10/18 10:21:05.531090 [info] dnsproxy: entering udp listener loop addr=[::]:53
adguardhome-v0107-web | 2026/10/18 10:21:05.531131 [info] dnsproxy: entering listener loop proto=tcp addr=[::]:53
跟踪实时日志加 -f;查历史错误用 docker compose logs adguardhome 2>&1 | grep -i error。
10.3 版本升级
AdGuard Home 发布新版后的标准升级流程(以 tag v0.107.80 为例,发布时替换为实际最新 tag):
cd /opt/adguardhome
sed -i 's|adguard/adguardhome:v0.107.79|adguard/adguardhome:v0.107.80|' docker-compose.yml
docker compose pull && docker compose up -d
说明:docker compose pull 拉取新镜像,up -d 检测到镜像变化会自动重建容器,conf/、work/ 两个 bind mount 保证配置与数据原样保留。当前 v0.107.79 已是最新稳定版时的实测回显(pull 无新层、up 检测到容器配置未变不会重建):
===COMPOSE PULL===
Image adguard/adguardhome:v0.107.79 Pulling
Image adguard/adguardhome:v0.107.79 Pulled
===COMPOSE UP -D(镜像未变)===
Container adguardhome-v0107-web Running
升级后确认版本与数据:
docker exec adguardhome-v0107-web /opt/adguardhome/AdGuardHome --version && \
dig @127.0.0.1 -p 5331 doubleclick.net +short
实测输出:
AdGuard Home, version v0.107.79
0.0.0.0
回滚:将 compose 文件中的 tag 改回旧版本(如 v0.107.78)后 docker compose up -d,本地保留的历史镜像层可加速启动;若旧镜像已清理,docker compose pull 会重新拉取。
十一、常见问题
以下问题均为实测环境中真实发生并解决的过程记录。
11.1 宿主机 53 端口被 systemd-resolved 占用
现象:计划映射 53:53 时,宿主机 ss -lntup | grep :53 显示(实测输出):
udp UNCONN 0 0 127.0.0.53%lo:53 0.0.0.0:* users:(("systemd-resolve",pid=853,fd=13))
tcp LISTEN 0 4096 127.0.0.53%lo:53 0.0.0.0:* users:(("systemd-resolve",pid=853,fd=14))
定位:Ubuntu 22.04 默认启用 systemd-resolved 的 DNS stub(监听 127.0.0.53:53),/etc/resolv.conf 指向它。stub 只绑定回环地址 127.0.0.53,实测并不阻塞 Docker 对 0.0.0.0:53 的端口映射(本文 5331:53 与 53:53 均可启动);但当系统关闭 stub 改为通配监听 0.0.0.0:53 时,容器映射 53 端口会报 port is already allocated。
解决(二选一):
- 方案 A(零改动):保持映射
5331:53,下游设备显式指定端口,本文实测即此形态; - 方案 B(释放 53):编辑
/etc/systemd/resolved.conf设置DNSStubListener=no,执行systemctl restart systemd-resolved后把/etc/resolv.conf的 nameserver 从127.0.0.53改为上游真实 DNS 或127.0.0.1,随后映射53:53。⚠️ 操作前先用resolvectl status确认本机解析链路,避免远程服务器失联。
11.2 端口被占用启动失败(port is already allocated)
现象:宿主机 8092 已被其他进程占用时 docker compose up -d 报错(实测输出):
Container adguardhome-v0107-web Creating
Container adguardhome-v0107-web Created
Container adguardhome-v0107-web Starting
Error response from daemon: failed to set up container networking: driver failed programming external connectivity on endpoint adguardhome-v0107-web (7ab35a0c0ee38fed65c88ce42e9da5175d391cc205796c8b04d7196c24242fc2): Bind for 0.0.0.0:8092 failed: port is already allocated
定位:docker ps --format '{{.Names}} {{.Ports}}' 逐个查占用者,或 ss -lntp | grep 8092。
⚠️ 关键坑(实测踩中):此时再次执行 docker compose up -d 无法恢复——容器已停在 Created 状态,compose 判定「容器已存在且配置未变」仅执行 start,实测该容器启动后 docker compose ps 的 PORTS 列为空、Web/DNS 全部不通。正确恢复流程:先 docker compose down(强制删除异常容器)再 docker compose up -d(重建),端口映射即恢复正常(实测恢复后 curl 返回 Web_HTTP:302、dig 拦截返回 0.0.0.0)。
11.3 默认上游(Quad9 DoH)解析超时
现象:初始化完成后 dig @127.0.0.1 -p 5331 任何域名都超时(;; communications error to 127.0.0.1#5331: timed out,完整回显见 4.6 节)。
定位:GET /control/dns_info 实测默认上游为 https://dns10.quad9.net/dns-query,该国外 DoH 地址在多数国内网络不可达;Web 界面对应「设置 → DNS 设置 → 上游 DNS 服务器」。
解决:改用国内可达上游(223.5.5.5、119.29.29.29、https://dns.alidns.com/dns-query,API 调用见 4.6 节,实测改后 www.baidu.com 恢复正常解析)。若需继续使用国外 DoH/DoT 上游,需自备可靠出海链路。
11.4 过滤规则接口报 415(content-type 错误)
现象:以 text/plain 提交规则列表报错(实测输出):
only content-type application/json is allowed
HTTP_CODE:415
定位:v0.107.x 的 POST /control/filtering/set_rules 严格要求 JSON 请求体 {"rules":[...]},不接受纯文本规则列表。
解决:按 4.7 节的 JSON 写法提交(实测 HTTP:200)。另实测发现规则提交返回 200 后的极短窗口内(毫秒级规则引擎重载期),紧随其后的第一次查询可能未被拦截(实测出现过一次返回 NXDOMAIN 而非 0.0.0.0),第二次查询起拦截稳定生效;脚本化下发规则后建议 sleep 1 再做验证查询。
11.5 过滤列表下载缓慢或失败
现象:首次启动后 filters 目录迟迟无文件、GET /control/filtering/status 中 rules_count: 0。
定位:默认 AdGuard DNS filter 托管在 GitHub Pages(adguardteam.github.io),部分网络环境直连缓慢;服务器可出网时稍候即可,实测约 15 秒完成(日志 filtering: filter updated id=1 bytes_written=4458454 rules_count=186099)。
解决:为下载配置代理可在 Web 界面「设置 → DNS 设置」中调整,或直接手动将列表文件内容粘贴到自定义过滤列表;内网环境可在「过滤器」页手动添加本地可达镜像源的 URL。
11.6 启动日志出现 permcheck 权限告警
现象:日志出现(实测行):
permcheck: warning: found unexpected permissions type=directory path=/opt/adguardhome/work perm=0755 want=0700
定位与解决:镜像内置的安全权限自检建议数据目录 0700,info 级告警不影响运行;生产执行 chmod 700 /opt/adguardhome/conf /opt/adguardhome/work 消除即可。
十二、参考链接
- AdGuard Home 官方仓库:https://github.com/AdguardTeam/AdGuardHome
- 官方 Docker 指南(docker/README.md):https://github.com/AdguardTeam/AdGuardHome/blob/master/docker/README.md
- Docker Hub 镜像页(tag 与多架构):https://hub.docker.com/r/adguard/adguardhome
- 官方 Getting Started:https://adguard-dns.io/kb/adguard-home/getting-started/
- 官方 OpenAPI 规范(/control/ 接口定义):https://github.com/AdguardTeam/AdGuardHome/tree/master/openapi
- 本专栏配套文档:《AdGuard Home 0.107.79 介绍与选型指南》