步骤/目录:
1.背景介绍
2.adguardhome
    (1)安装
    (2)配置
3.pihole
    (1)安装
    (2)配置
附录:
    (1)macvlan
    (2)macvlan下的网段
    (3)macvlan的其它操作
    (4)pihole配置详解

本文首发于个人博客https://lisper517.top/index.php/archives/476/,转载请注明出处。
本文的目的是介绍自建DNS、过滤广告的两款软件。
本文写作日期为2024年1月29日,在Ubuntu 22.04LTS系统演示。

1.背景介绍

在用电脑、手机平板浏览网页时,经常能看到网页上各种广告。这些广告最常见的形式是一些图片或视频,而图片和视频资源一般是通过网址加载的。如果在路由器中屏蔽这些广告网址,就能实现去广告。

路由器默认设置下,会自动选择本地运营商的DNS,而运营商有时候会劫持DNS,情节轻时在返回的内容中加上广告,严重时则返回错误的内容。在这种情况下也有必要自建DNS。

2.adguardhome

adguardhome最初应该是国人做的一款去广告DNS。

(1)安装

根据其 docker网址 的引导,在Ubuntu上如下操作:

mkdir -p /docker/adguardhome/data/adguardhome
mkdir -p /docker/adguardhome/conf/adguardhome
cd /docker/adguardhome
vim docker-compose.yml

写入如下内容:

version: '3.8'
services:
  adguardhome:
    image: 'adguard/adguardhome'
    container_name: adguardhome
    ports:
      - '53:53' #DNS端口
      - '3000:3000' #网页UI,初始配置端口
      - '8500:80' #网页UI,后续配置端口
    volumes:
      - ./data/adguardhome:/opt/adguardhome/work
      - ./conf/adguardhome:/opt/adguardhome/conf
    restart: unless-stopped

以上设置仅将adguardhome作为DNS服务器使用,其实它还可用用来做DHCP服务器(动态分配内网ip)、HTTPS/DNS-over-HTTPS服务器(DNS的过程用HTTPS加密)、DNS-over-TLS服务器(用TLS加密DNS)、DNS-over-QUIC服务器(QUIC加密DNS)、DNSCrypt服务器(不太清楚,应该也是加密),详见原文,需要注意的是HTTPS、TLS、QUIC好像都需要公网ip+域名+HTTPS证书(所以需要在云服务器部署adguardhome),而DNSCrypt虽不需要证书、却需要客户端(电脑,手机平板等使用adguardhome进行DNS的设备)配置软件。

另外需要注意,3000端口是adguardhome初始配置的端口,后续WebUI则会在80端口,已被占用的话可以改到其它端口(此处改到8500端口)。

最后打开端口,运行即可(其实docker会自动打开,笔者用ufw是为了方便查看):

ufw allow 53 comment "DNS-adguardhome"
ufw allow 3000 comment "WebUI-adguardhome-initial"
ufw allow 8500 comment "WebUI-adguardhome"
docker-compose config
docker-compose up

如果提示53端口被占用,可以把53改到其它端口,前提是你的路由器支持DNS服务器使用非53端口;或者使用笔者更推荐的macvlan,见附录。

(2)配置

访问 本地ip:3000 端口,设置登录用户名密码,其它一路默认,完成初始化配置;然后到8500端口进行进一步配置。在adguardhome配置前,或者配置完成后,到你的路由器管理页面,将ipv4的DNS改到adguardhome的ipv4地址。

以下配置参考了 这篇文章

a.DNS服务器

设置 - DNS设置 - 上游 DNS 服务器 中,填入cloudflare和google的DNS:

1.1.1.1
1.0.0.1
2606:4700:4700::1111
2606:4700:4700::1001
8.8.8.8
8.8.4.4
2001:4860:4860::8888
2001:4860:4860::8844

后备 DNS 服务器 使用adguardhome提供的DNS:

94.140.14.14
94.140.15.15
2a10:50c0::ad1:ff
2a10:50c0::ad2:ff

笔者实验时用不了ipv6的DNS,这是因为docker没有给adguardhome容器分配ipv6地址,自然也用不了ipv6。开启的方法见 参考文章一 (讲解较乱)或者 参考文章二 (使用macvlan,见附录)。

b.DNS 黑名单

过滤器 - DNS 黑名单 里,添加DNS过滤规则。有人整理出来某些广告域名,添加到黑名单后adguard就会拦截这些请求。可以添加自带的,也可以自己找一些黑名单,比如 配置参考文章 中提供的:

halflife
https://raw.githubusercontent.com/o0HalfLife0o/list/master/ad.txt

anti-AD
https://anti-ad.net/easylist.txt

neoHosts
https://cdn.jsdelivr.net/gh/neoFelhz/neohosts@gh-pages/full/hosts.txt

大圣净化 - 针对国内视频网站
https://raw.githubusercontent.com/jdlingyu/ad-wars/master/hosts

adgk手机去广告规则
https://raw.githubusercontent.com/banbendalao/ADgk/master/ADgk.txt

广告终结者
http://sub.adtchrome.com/adt-chinalist-easylist.txt

Adbyby
https://raw.githubusercontent.com/adbyby/xwhyc-rules/master/lazy.txt

EasyList China+EasyList
https://easylist-downloads.adblockplus.org/easylistchina+easylist.txt

EasyPrivacy
https://easylist-downloads.adblockplus.org/easyprivacy.txt

不用太多,只添加一两个即可,太多了容易误杀,也拖慢DNS速度。

c.DNS 白名单

为了防止错杀,还可以添加白名单,白名单的优先级高于黑名单。比如google analytics就容易被错杀。

anti-ad白名单
https://raw.githubusercontent.com/privacy-protection-tools/dead-horse/master/anti-ad-white-list.txt

filter_whitelist
https://raw.githubusercontent.com/hl2guide/Filterlist-for-AdGuard/master/filter_whitelist.txt

LWJ's white list
https://raw.githubusercontent.com/liwenjie119/adg-rules/master/white.txt

DNS允许白名单
https://raw.githubusercontent.com/ChengJi-e/AFDNS/master/QD.txt

白名单也不需要太多。

如果正常的网页加载不出来,到adguardhome的后台查看是否误杀,手动加白名单。

d.DNS 重写

如果想通过域名访问一些局域网ip,可以在这里配置。一些路由器如AX9000也可以在路由器里配置(小米路由器需要在同名app配置,找到hosts设置)。

e.自定义过滤规则

一些网站的广告需要其它设置才能去除,比如油管的视频广告(笔者未验证):

/googleads.$~script,domain=~googleads.github.io
/pagead/lvz?
||google.com/pagead/
||static.doubleclick.net^$domain=youtube.com
||youtube.com/get_midroll_
||safebrowsing.googleapis-cn.com
||doubleclick.net

自定义规则需要有一定的网络基础才能玩的转,至少要会用chrome的开发者模式,或者也可以搜索别人的规则试试。

3.pihole

pihole最初是给树莓派做的广告拦截,但是也能用于其它电脑。pihole没有中文界面,需要的可自行找汉化版,但是笔者还是更推荐英文原版。

(1)安装

根据 docker-pihole 的介绍,在 Ubuntu 22.04 LTS 上操作(同样使用macvlan的方法)。
创建docker-net(之前创建过的话这里就不用建了):

docker network create -d macvlan \
--subnet=192.168.31.0/24 \
--gateway=192.168.31.1 \
--ipv6 \
--subnet=fe80:7eb5:2afd::/64 \
--gateway=fe80:7eb5:2afd::1 \
-o parent=eth0 \
macvlan_net

然后是熟悉的步骤:

mkdir -p /docker/pihole/etc-pihole
mkdir -p /docker/pihole/etc-dnsmasq.d
cd /docker/pihole
vim docker-compose.yml

写入如下内容:

version: "3"

services:
  pihole:
    container_name: pihole
    image: pihole/pihole:latest
    environment:
      TZ: 'Asia/Shanghai'
      WEBPASSWORD: '123456' #网页密码
    volumes:
      - './etc-pihole:/etc/pihole'
      - './etc-dnsmasq.d:/etc/dnsmasq.d'
    restart: unless-stopped
    networks:
      macvlan_net:
        ipv4_address: 192.168.31.31
        ipv6_address: fe80:7eb5:2afd::31

networks:
  macvlan_net:
    external: true

运行:

docker-compose config
docker-compose up

然后到 [fe80:7eb5:2afd::31]/admin 或者 192.168.31.31/admin 登录,密码为yml中设置的密码。

后面如果把pihole作为DNS,则也能从 http://pi.hole/admin 登录。如果忘记或者想更改登录密码,可以 docker exec -it pihole pihole -a -p (或者进入宿主机后 pihole -a -p )。

(2)配置

pihole没有中文界面,配置起来稍微难一点。pihole配置中的高级选项会在附录中解释。另外,目前的pihole管理白名单不是很方便,大概是21年某次更新之前的网页UI还有黑白名单的设计,现在则是用groups代替了。

Adlists 里,可以添加别人的屏蔽列表。添加完后, docker exec -it pihole pihole -g 来更新列表;或者到 Tools - Update Gravity 里更新。黑名单在这里添加,白名单见后;

Settings - DNS 里,把Google、OpenDNS、Cloudflare的IPv4、IPv6的DNS服务器都勾选上。旁边也可以自己填;

下方有一个 Rate-limiting ,默认应该是某个客户端在60s内请求1000次DNS时就封禁该客户端。玩多线程爬虫的话会有影响;或者用路由器作为pihole的客户端也容易被封。都设置为0可关闭该功能。

其它配置见附录。

附录:

(1)macvlan

macvlan是一种网络虚拟化技术,可以用同一张物理网卡获得不同的局域网ip。在docker中可以调用macvlan,将容器作为一个单独设备、分配局域网ip,使得局域网内的机器(除了宿主机)几乎都能通过局域网ip来访问容器。比如将adguardhome绑定到 192.168.1.30 ,那么 192.168.1.30:80192.168.1.30:3000 就分别变成了adguardhome的配置页面、初次配置页面。由于还要使用ipv6访问adguardhome,也需要给它一个v6地址。

回到adguardhome容器启动前,如下设置(参考之前提到的 参考文章二 和之前未提到的 参考文章三 ,后者讲的比较详细):

docker network create -d macvlan \
--subnet=192.168.1.0/24 \
--gateway=192.168.1.1 \
--ipv6 \
--subnet=fe80:7eb5:2afd::/64 \
--gateway=fe80:7eb5:2afd::1 \
-o parent=eth0 \
macvlan_net

-d macvlan--driver macvlan ,指定docker-net的驱动。最后的 macvlan_net 是docker-net名;

ipv4网关为 192.168.1.1 ,网段为 192.168.1.0/24 。由于笔者使用小米路由器,网关和网段都要改到 192.168.31 下;

ipv6网关为 fe80:7eb5:2afd::1 , 网段为 fe80:7eb5:2afd::/64 。这个 fe80:7eb5:2afd 局域网v6地址可以按 fe80:xxxx:xxxx 的格式随便写;

指定物理网卡为 eth0 对应的网卡。如果网卡不存在,在linux上用 ifconfig 查看物理网卡,局域网ip对应的那张,类似 enp2s0f1en0ovs_eth0 这种。

另外需要注意,macvlan是独立于docker的,docker需要调用macvlan进行网络虚拟化,所以你需要先安装macvlan包。一般linux发行版是自带的,少数情况则需要手动下载,比如用 树莓派4B + Ubuntu21.10系统 时需要 apt install linux-modules-extra-raspi + reboot (见 reddit提问 );或者有些openwrt系统下,需要 opkg update && opkg install kmod-macvlan

创建完docker-net后,将yml文件更改为:

version: "3"
services:
  adguardhome:
    image: adguard/adguardhome
    container_name: adguardhome
    volumes:
      - ./data/adguardhome:/opt/adguardhome/work
      - ./conf/adguardhome:/opt/adguardhome/conf
    restart: unless-stopped
    networks:
      macvlan_net:
        ipv4_address: 192.168.1.30 #用小米路由器则改成192.168.31.30
        ipv6_address: fe80:7eb5:2afd::30

networks:
  macvlan_net:
    external: true

这里没有端口映射的设置。通过以上步骤,已经给容器组中的adguardhome容器分配了v4、v6地址,访问 192.168.1.30 或者 [fe80:7eb5:2afd::30] 的3000、80端口都能设置adguardhome,也可以正常访问ipv6的DNS。设置完adguardhome后,在路由器管理页把v4和v6的DNS分别改到 192.168.1.30[fe80:7eb5:2afd::30] 即可。

必须尝试通过 [fe80:7eb5:2afd::30]:3000 或者 [fe80:7eb5:2afd::30]:80 访问adguardhome。如果不行,可以看下面的方法。

(2)macvlan下的网段

无法从路由器或者局域网的其它机器内访问 [fe80:7eb5:2afd::30] ,可能是因为网段不对。在windows的cmd中 ipconfig默认网关 ,或者linux下 ip -6 route show 最后一行 default via ... 确认一下ipv6的网关。如果网关以其它开头,比如不是 fe80 而是 f123 ,那么就把上文教程中所有的 fe80 换成 f123 即可。当然,一般网关都是 fe80 开头的,因为 fe80 默认是内网v6,类似于 192.168 在v4中的地位。

如果不能通过以上方法确认v6网关,你也可以进入容器:

docker exec -it adguardhome sh
ifconfig

其部分输出内容为:

eth0      Link encap:Ethernet  HWaddr XX:XX:XX:XX:XX:XX
          inet addr:192.168.1.30  Bcast:192.168.1.255  Mask:255.255.255.0
          inet6 addr: fe80::xx:xxxx:xxxx:xxxx/64 Scope:Link
          inet6 addr: fe80:7eb5:2afd::30/64 Scope:Global
          inet6 addr: 240e:xxx:xxx:xx:xx:xxxx:xxxx:xxxx/64 Scope:Global
...

这里出现了3个v6地址,它们的顺序可能调换。
第一个 fe80 开头的是随机分配的局域网v6,即使无法通过 fe80:7eb5:2afd::30 访问adguardhome,也一定能通过这个v6访问;
第二个 fe80:7eb5:2afd::30 是yml中设置的,是静态公网v6(实际上是内网);
第三个 240e 开头的,是真正的公网v6地址,但是ping不到(应该是出于安全考虑)。如果你的头两个v6地址开头不同,比如说:

          inet6 addr: f123::xx:xxxx:xxxx:xxxx/64 Scope:Link
          inet6 addr: fe80:7eb5:2afd::30/64 Scope:Global

同样把所有的 fe80 换成 f123 即可。

在几乎所有其它的docker-macvlan教程中,创建的网段都非 fe80 开头,比如 fd0d:7eb5:2afd 。此时容器虽然能访问外部的v6地址,但v6网段不同,导致局域网的其它机器只能访问到容器的v4地址,却访问不到容器的v6地址。

(3)macvlan的其它操作

使用macvlan的容器,无法直接 docker restart ,会提示ip地址已被占用。你可以重启docker service docker restart 或者重启宿主机,以释放容器的ipv4、ipv6地址。

192.168.1.0/24 下虽然有256个ip地址,但也有可能用完。好在macvlan还能对物理网卡进一步分层,见 参考文章四 。分层后需要注意不同macvlan网络之间的通信问题。

最后,在参考文章四作者的下一篇文章中提到了overlay,也可以达到给容器以局域网ip的效果,见 参考文章五

(4)pihole配置详解

这里都是笔者个人的理解,部分参考了 pihole的官方文档 。由于文档都是英文的,笔者没时间细看,难免可能有疏漏错误,请参考原文。

a.Groups与Clients

从主页面左侧边栏的 Groups 可进入Groups management(屏蔽规则的分组)。根据 官方文档 ,组可用于管理域名黑名单、白名单、客户端。但是注意目前版本pihole的白名单域名管理起来不是很方便(网页中只能一个个显示,没有白名单列表)。

可以对屏蔽规则分组,也可以对客户端分组(侧边栏的 Groups 下方的 Clients )。比如 电脑1 需要访问所有网站, 电脑2 则需要屏蔽掉不健康的网站,就可以对此类网站拉一个组,在 电脑2(客户端2) 的屏蔽规则中单独加上该组,守护少年儿童的心理健康。

每个新的屏蔽规则和客户端都会加到各自的0号组(default)中。

要对客户端分组,首先需要有不同的客户端,这就要求不能在路由器里统一把DNS设置到pihole,但是给每台电子设备分别改DNS又太麻烦了。笔者建议成人用一个路由器,少年儿童用另一个路由器,这样简单一些。

创建组名时如果有空格,则需要用英文双引号将组名括起来。

组的操作:

对某个客户端取消所有屏蔽:
在 Clients - Group assignment 里,把该客户端适用的所有组移除。

对屏蔽规则(黑名单)分组:
在 Groups 里创建屏蔽规则组后,在 Adlists - Group assignment 里,对屏蔽规则分组。新增的所有规则都会加到0组(default),可以手动调整。

添加单独的域名(黑名单或白名单)到组:
在 Domains 里新增一个域名(或者正则)规则,添加到屏蔽规则的组里。目前的pihole不能添加白名单的列表,只能在这里一个个添加,因此笔者建议这里只添加白名单域名。

另外,pihole中白名单的优先级也高于黑名单( 官方文档 )。

对客户端和屏蔽规则都分组后,就能很方便地管理。比如刚才的例子,有域名黑名单A,域名黑名单B(成人能访问,儿童不能访问),域名白名单C,成人客户端1,儿童客户端2,那么进行以下操作:

在 Groups 里,添加 adult_rule 和 kid_rule 两个屏蔽规则组;
在 Clients 里,添加两个客户端,分别为成人和儿童使用的客户端,分别使用 adult_rule 和 kid_rule 两个屏蔽规则组(去掉default组);
在 Domains 里,一个个添加白名单C中的域名,注意选择 Add to Whitelist,并把所有白名单域名的 Group assignment 中勾选两个屏蔽规则组(default组随便);
在 Adlist 里,通过URL,添加黑名单A、B,将A添加到 adult_rule 和 kid_rule ,B则只添加到 kid_rule (default组随便);

b.Domains与Adlists

Domains 里可以手动单独添加域名到白名单或黑名单,还能用正则表达式。正式用RE之前最好用pihole检查一下,见 官方文档 (需要进入容器操作)。

Adlists 里可以用别人总结好的屏蔽列表(anti-ad之类的),用法同adguardhome。添加完屏蔽表后, docker exec -it pihole pihole -g 来更新列表;或者到 Tools - Update Gravity 里更新。

c.Disable Blocking

可以临时或者永久取消所有的屏蔽,用于测试。

d.Local DNS

自定义解析,一般用于把某个域名绑定到局域网ip上。

e.名词解释

笔者对于 Settings 里的一些高级功能进行解释,可能会有错误的地方。

ECS (Extended Client Subnet) :应该是DNS的弹性负载。

Content Delivery Networks (CDNs) :基于ip提供地理信息。

Never forward non-FQDN A and AAAA queries :如果不勾选的话,有时候Local DNS可能往上游服务器查找;如果开启下面的 Conditional Forwarding 又不勾选本功能,有时会导致DNS死循环。
Never forward reverse lookups for private IP ranges :本地ip如果没有对应的本地域名,不会向上游服务器查找。
这两个 Never forward 选项也许能增加隐私性,但勾选时最好同时把pihole设为DHCP服务器。

Use DNSSEC :即Domain Name System Security Extensions,验证DNS解析是否正确。如果验证失败或者上游服务器不支持DNSSEC,可能会出问题。另外该选项会显著增加log文件大小。

Rate-limiting :默认情况下,一个客户端在60s内发出1000次DNS请求后就封禁该客户端。玩多线程爬虫可能有影响,把两个值都改成0可以关闭此功能。

Conditional forwarding :如果不把pihole作为DHCP服务器,则pihole无法决定局域网内的设备名(注意这个不同于Local DNS),开启这个功能后,填入局域网段、DHCP服务器(一般是路由器)、选填本地域名,pihole会向你的路由器查询局域网内的设备名。选填的本地域名,意思是对该域名的DNS不会离开本地,并且这个本地域名要和路由器的设置一致。开启 Conditional forwarding 同时关闭 Never forward non-FQDN A and AAAA queries ,那么即使是本地域名,pihole也会交给上游的路由器处理。(所以要想用pihole解析本地域名,要么就都不开,要么就把 Conditional forwardingNever forward non-FQDN A and AAAA queries 都打开)

标签: docker, adguardhome, pihole

添加新评论