Docker 部署 AdGuard Home 与 Nginx Proxy Manager:从 DNS 拦截到反向代理的一站式家庭服务器方案

为什么要把 AdGuard Home 和 Nginx Proxy Manager 放在一起聊?

很多玩 Docker 的朋友,最终都会走向一条“自建全家桶”的路。折腾过一阵子你就会发现,DNS 解析和反向代理是无论如何都绕不开的两个核心环节。AdGuard Home 负责在源头拦截广告和恶意域名,Nginx Proxy Manager(下文简称 NPM)则负责把家里或 VPS 上乱七八糟的端口服务,统一收敛到 80/443 上,配上 HTTPS 证书,干净又安全。

这两者搭配起来,一个管“入口”的纯净度,一个管“出口”的统一性。今天笔者就把这两套服务的 Docker 部署配置、初始化细节以及常见坑位一次讲透。如果你对服务器基础配置还有疑问,建议先看看我们之前写的云服务器网卡带宽到底怎么选?全网拉测性能指标的一次深度拆解,别让带宽瓶颈拖了后腿。

环境准备与网络规划

在敲命令之前,我们建议先理清网络拓扑。假设你有一台云服务器或者家里的小主机(Debian/Ubuntu),Docker 和 Docker Compose 已经装好。我们需要规划两个关键点:

  • IP 与端口:AdGuard Home 默认监听 53(DNS)、80(初始化面板)、3000(安装向导)。NPM 默认监听 80、443、81(管理面板)。强烈建议把 AdGuard 的 80 端口映射到宿主机的其他端口(如 8080),避免与 NPM 的 80 冲突。
  • Bridge 网络:为了让两个容器能通过内部域名互相访问,我们创建一个自定义 Docker 网络。
docker network create webnet

第一步:部署 AdGuard Home(DNS 拦截核心)

AdGuard Home 的部署本身不复杂,但映射端口时要注意。我们用 docker-compose.yml 来定义服务,方便后续维护。

services:
  adguardhome:
    image: adguard/adguardhome:latest
    container_name: adguardhome
    restart: unless-stopped
    networks:
      - webnet
    ports:
      - "53:53/tcp"
      - "53:53/udp"
      - "3000:3000/tcp"   # 初始化向导端口
      - "8080:80/tcp"     # 将面板映射到宿主机的 8080
    volumes:
      - ./adguard/work:/opt/adguardhome/work
      - ./adguard/conf:/opt/adguardhome/conf

networks:
  webnet:
    external: true

执行 docker compose up -d 后,访问 http://服务器IP:3000 进行初始化。这里有个细节:初始化向导里填写的“Web 管理界面端口”和“DNS 服务端口”要填写容器内部的端口,即 80 和 53,不要填宿主机映射后的 8080 和 53(53 没变,但 80 一定要填 80)。否则你会发现面板打不开。

初始化完成后,管理界面地址就变成了 http://服务器IP:8080。进入面板后,在“设置 – DNS 设置”里,建议勾选“速度限制”并设置一个合理的值,防止被恶意利用做 DNS 放大攻击。在“过滤器 – DNS 拦截清单”里,添加几个知名的广告规则列表,这里就不一一列举地址了,网上搜“AdGuard Home 规则”一大把,挑维护活跃的加即可。

第二步:部署 Nginx Proxy Manager(反向代理与 SSL 终结)

NPM 的存在就是为了让我们告别手写 Nginx 配置的繁琐。它提供 Web 界面,点点鼠标就能完成域名转发和 Let’s Encrypt 证书申请。同样,我们用 Compose 部署:

services:
  npm:
    image: jc21/nginx-proxy-manager:latest
    container_name: npm
    restart: unless-stopped
    networks:
      - webnet
    ports:
      - "80:80"
      - "443:443"
      - "81:81"           # 管理面板端口
    environment:
      DB_MYSQL_HOST: "db"
      DB_MYSQL_PORT: 3306
      DB_MYSQL_USER: "npm"
      DB_MYSQL_PASSWORD: "npm_pass"
      DB_MYSQL_NAME: "npm"
    volumes:
      - ./npm/data:/data
      - ./npm/letsencrypt:/etc/letsencrypt
    depends_on:
      - db

  db:
    image: mariadb:10.8
    container_name: npm-db
    restart: unless-stopped
    networks:
      - webnet
    environment:
      MYSQL_ROOT_PASSWORD: "root_pass"
      MYSQL_DATABASE: "npm"
      MYSQL_USER: "npm"
      MYSQL_PASSWORD: "npm_pass"
    volumes:
      - ./npm/mysql:/var/lib/mysql

networks:
  webnet:
    external: true

登录 http://服务器IP:81,默认账号 admin@example.com,密码 changeme。首次登录会强制修改密码。

关键配置:让 NPM 反代 AdGuard Home 面板

我们以“把 AdGuard Home 面板绑定到 ad.yourdomain.com”为例。在 NPM 中点击 “Add Proxy Host”:

  • Domain Names:填 ad.yourdomain.com
  • Forward Hostname / IP:这里填容器内部名称 adguardhome(因为我们用了同一个网络 webnet)。
  • Forward Port:填 80(注意是容器端口,不是宿主机的 8080)。
  • Block Common Exploits:勾选。
  • SSL 选项卡:选择 “Request a new SSL Certificate”,勾选 “Force SSL” 和 “HTTP/2”。

保存后,访问 https://ad.yourdomain.com 就能看到 AdGuard 面板,且自动跳转 HTTPS。这套逻辑同样适用于反代你部署的其他任何 Web 服务,比如后续想折腾 WordPress,可以参考我们之前写的网站慢如蜗牛?用Redis缓存加静态资源优化,让你的WordPress飞起来,通过 NPM 反代后配合 Redis 缓存,速度会有质的飞跃。

进阶:让 AdGuard Home 作为上游 DNS

如果你希望 NPM 所在的主机或内网设备都通过 AdGuard 过滤,需要修改宿主机的 DNS 指向。但这里要注意,AdGuard 的 53 端口映射在宿主机上,如果你把宿主机的 DNS 也指向 127.0.0.1,会导致 Docker 容器内 DNS 解析死循环。这是一个非常经典的坑。

正确的做法是:在 AdGuard 的设置里,将 “Upstream DNS Servers” 设置为公共 DNS(如 1.1.1.1 或 223.5.5.5),然后在宿主机防火墙规则中,只允许内网网段访问 53 端口。对于 Docker 容器本身,我们更推荐在 NPM 的 Compose 文件里,给每个容器单独指定 dns 配置,指向 AdGuard 的容器 IP。

services:
  npm:
    ...
    dns:
      - 172.18.0.2   # 替换为 adguardhome 容器的实际 IP,可用 docker inspect 查看

这样既能让容器流量经过广告过滤,又不会干扰宿主机的网络栈。

常见问题与排查思路

症状 原因 解决方案
AdGuard 初始化后 80 端口无法访问面板 向导中填了宿主机映射端口 重新初始化或修改 conf 文件中的端口为 80
NPM 申请证书失败 域名 DNS 未解析到本机,或 80 端口被占用 确认 A 记录指向,检查宿主机的 80 端口是否被其他进程占用
容器间无法通过服务名互通 未加入同一外部网络 确保两个 Compose 文件都声明了 external: true 的 webnet
DNS 解析延迟高 上游 DNS 选择不当 国内建议使用 223.5.5.5 或 119.29.29.29

安全加固与一点延伸建议

服务跑起来后,安全这根弦不能松。AdGuard Home 的管理面板和 NPM 的管理面板千万不要直接暴露在公网,只监听内网或通过防火墙限制来源 IP。如果你对防火墙配置不熟悉,强烈推荐阅读我们这篇实战踩坑记录:别再裸奔了!Linux服务器安全加固与UFW防火墙配置,这些坑我替你踩过了。另外,如果你用的是云服务器,建议在安全组层面就把 81 端口(NPM 管理)和 3000 端口(AdGuard 初始化)封锁掉,只保留 80、443 和 53 的对外访问。

至于服务器选择,如果你打算长期跑这两个服务,加上后续可能折腾其他容器,内存最好在 2GB 以上。带宽方面,DNS 请求虽然占用极小,但如果你用 NPM 反代大流量应用,务必关注月流量包是否够用。之前我们深度拆解过云服务器网卡带宽到底怎么选?全网拉测性能指标的一次深度拆解,选购前不妨参考一下。

最后提醒一句,SSH 登录千万别再用密码,赶紧换成密钥对登录,这是底线。具体操作可以看这篇:黑客天天扫你的服务器?关掉密码登录,用 SSH 密钥对一把锁死暴力破解

这套组合拳打下来,你的服务器基本就具备了广告拦截、统一入口、自动 HTTPS 三大能力。剩下的,就是慢慢往里面加服务了。祝折腾愉快。

延伸阅读推荐

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部