自建DNS级广告拦截系统:局域网统一过滤与API批量管理实践

自建DNS级广告拦截系统:局域网统一过滤与API批量管理实践 “我拦截了1000000个广告”——如果你第一次看到这种标题大概率会以为是夸大其词。但实际上广告拦截面板里的计数不会骗人每拦截一条广告请求计数器就加一当一台常开设备全天候运行 DNS 级过滤再叠加浏览器端元素过滤累计拦截一百万条广告请求只是时间问题。这次我们聊的不是某个具体工具的一次点击安装而是把“广告拦截”做成一套可观测、可维护、可扩展的本地技术体系DNS 层过滤 浏览器端兜底 自定义规则 日志统计 API 批量管理。这篇文章会直接给出部署方式、验证方法、常见问题和工程化建议看完你可以在自己的局域网里复现这套系统不会只停留在概念层面。不管你是个人用户想在家庭网络里屏蔽开机广告和 App 内广告还是技术人员需要维护一套面向多设备的过滤服务这篇文章都适合你。下面直接进入正题。1. 核心能力速览广告拦截系统通常不是单一软件而是分层组合。最核心的能力有以下几项能力项说明项目类型本地广告拦截服务 客户端过滤插件组合方案主要功能DNS 层广告域名过滤、浏览器页面元素清理、自定义拦截规则、拦截日志统计、批量规则管理网络作用范围局域网内所有手动配置 DNS 的设备无需逐台安装软件浏览器兜底能力过滤页面内广告位、弹窗、视频贴片广告等无法用 DNS 完全覆盖的元素启动方式Docker Compose 或二进制启动浏览器插件安装即可是否支持 API控制面板自带接口可通过 Token 调用用于规则管理和日志查询是否支持批量任务支持规则文件批量导入、日志批量导出、脚本批量校验推荐运行环境低功耗常开设备、云服务器、树莓派、闲置 PC具体配置需按规则量和请求量评估平台支持Windows、Linux、macOS、部分路由器固件均可运行服务端适合场景家庭网络去广告、小型局域网统一过滤、多设备隐私保护从材料看这套系统最核心的卖点是“统一入口”只要把设备的 DNS 指向自建服务就把广告拦截从单台设备扩展到了整个网络。2. 适用场景与使用边界广告拦截不是什么黑科技但使用边界必须提前说清楚。适合的场景很明确家庭环境下路由器或设备设置自定义 DNS让手机、平板、电脑、电视盒子一起生效。小型办公网络里为不方便逐台安装插件的前端设备提供基础广告过滤能力。开发测试场景里需要快速模拟“无广告干扰”的页面环境。关注隐私的用户希望通过阻断已知追踪域名来减少跨站追踪请求数量。不适合的场景同样需要知道专业网络安全审计、企业级流量审计广告屏蔽工具不是替代方案。需要访问某些依赖特定广告域名才能正常登录或播放的站点如果一刀切拦截会产生误伤。网站内容本身的授权访问控制不属于广告拦截范畴。合规和安全边界方面有几点必须注意部署和使用广告拦截系统只应该针对自己拥有或有权管理的网络设备和设备流量。如果给他人设备配置过滤规则需要提前获得对方知情同意。DNS 日志会记录设备的域名查询记录属于敏感数据。保存周期、访问权限、是否外传都要有明确约束。不要通过修改 HTTPS 证书的方式做流量劫持式拦截这类做法会破坏加密信任链造成严重安全隐患。涉及业务系统、测试环境的域名要提前加白名单防止过滤规则影响正常功能。3. 环境准备与前置条件部署这套系统不需要很高的硬件配置但环境检查不能省。3.1 操作系统与运行设备服务端推荐选择 Linux 或 Windows 上长期运行的设备。如果只是个人学习测试Windows 本机也可以完成全部部署。生产级使用建议准备一台独立低功耗设备例如树莓派、软路由、云服务器或闲置笔记本。3.2 内存与磁盘运行轻量级 DNS 过滤服务内存占用取决于规则数量和并发请求量。作为参考互联网上的常见公共规则列表总量很大但服务端会对规则做索引和压缩。稳妥的做法是准备至少 1GB 内存和 10GB 磁盘空间再按实际日志增长情况调整。3.3 端口占用DNS 服务标准端口是53控制面板默认是3000或其他自定义端口。部署前要检查这些端口是否被占用# Linux / macOS sudo lsof -i :53 sudo lsof -i :3000 # Windows netstat -ano | findstr :53 netstat -ano | findstr :3000如果 53 端口被系统自带的 DNS 解析服务占用需要先停止或禁用该系统服务否则自建服务起不来。3.4 Docker 环境如果选择容器化部署需要确保 Docker 已安装。安装完成后确认服务正常docker --version docker compose version4. 安装部署与启动方式下面给出一套通用部署模板。实际使用时需要根据服务端版本、目录结构和端口设置替换对应路径。4.1 方式一Docker Compose 部署创建目录结构mkdir -p adguard/{work,conf}编写docker-compose.ymlversion: 3 services: adguard: image: adguard/adguardhome:latest container_name: adguard restart: unless-stopped ports: - 53:53/tcp - 53:53/udp - 3000:3000/tcp - 80:80/tcp volumes: - ./work:/opt/adguardhome/work - ./conf:/opt/adguardhome/conf启动服务docker compose up -d启动后通过浏览器访问http://localhost:3000进入初始化配置页面。首次配置时需要设置监听端口和管理员账号。4.2 方式二二进制安装如果不想用 Docker可以直接下载服务端二进制文件到服务器执行安装命令。通用的手工启动方式是# 进入程序所在目录执行服务端二进制 ./AdGuardHome -s start-s参数用于控制服务的启动、停止和重启状态。具体参数以你下载的版本帮助说明为准。4.3 浏览器端插件补位服务端负责 DNS 层过滤浏览器端还需要安装内容过滤插件。常见的方案是 uBlock Origin它可以在浏览器扩展商店里搜索安装也可以从开源发布渠道下载离线包手动加载。安装后启用默认规则列表即可。4.4 确认服务运行状态启动完成后在浏览器访问控制面板应能看到首页状态、DNS 查询统计和拦截统计。如果页面显示查询数在增长说明流量已经正常进入服务。5. 功能测试与效果验证服务启动不意味着拦截生效。下面这些测试场景用来验证每一层功能是否真正工作。5.1 DNS 拦截测试测试目的确认通过本机或其他设备发起的 DNS 解析请求能被服务端接收并过滤。操作步骤将测试设备的 DNS 地址手动设置为运行服务端的 IP。Windows 下通过命令刷新 DNS 缓存ipconfig /flushdns使用nslookup查询一个已知广告域名nslookup ads.example.com回到控制面板打开查询日志搜索刚才查询的域名。预期结果查询日志中能看到这条记录。状态显示为“已过滤”或“已拦截”。查询结果返回0.0.0.0或空地址或者不返回真实广告服务器地址。判断是否成功日志出现这条查询记录并标记为拦截状态说明 DNS 层过滤链路已打通。常见失败原因测试设备还在使用路由器下发的默认 DNS需要手动修改。服务端 53 端口没有正常监听。本地缓存未清理查询没有到达服务端。5.2 页面元素过滤测试测试目的验证浏览器端插件能否清除页面内广告位。操作步骤打开一个带有明显广告位的测试网站。观察广告区域是否被隐藏或标记为“已拦截”。打开插件面板查看当前页面拦截请求数量。预期结果页面广告区域消失或显示占位空白。插件面板中的拦截计数增加。判断是否成功刷新页面后广告位置不再出现且插件日志中能找到对应的过滤规则。5.3 自定义规则测试测试目的验证管理员添加的自定义规则是否立即生效。操作步骤在控制面板中找到“自定义过滤规则”入口。添加一条测试规则||ads.example.com^保存规则。重新查询该域名。预期结果该域名被拦截。日志中显示命中规则 ID 为自定义规则。判断是否成功拦截状态和日志能明确对应到刚添加的规则说明自定义规则链路正常。6. 接口 API 与批量任务本地广告拦截系统的工程化提升在于把规则管理从手工点击变成脚本流程。控制面板本身是 Web 服务底层有对应的 HTTP 接口。下面给出通用的接口调用思路和批量操作示例实际接口路径以你的服务端版本提供的能力为准。6.1 获取接口访问凭据在控制面板里找到“设置”或“用户管理”区域创建或获取一个用于 API 访问的 Token。该 Token 会在请求头或请求参数中传递用于标识管理员身份。6.2 通用请求模板使用 curl 调用时通常的格式是curl -X POST http://127.0.0.1:3000/control/接口路径 \ -H Authorization: Bearer 你的Token \ -H Content-Type: application/json \ -d { name: 自定义规则名称, rules: ||ads.example.com^ }注意上面的接口路径必须替换为实际服务端提供的能力。若接口使用的是其他认证方式如用户名密码也需要对应调整请求头。6.3 Python 批量导入规则实际维护中你会有一个规则目录里面按用途拆分了多个规则文件。用 Python 脚本统一读取合并再逐条写入服务端能有效提高维护效率。下面是一个通用脚本模板import os import requests API_URL http://127.0.0.1:3000/control/接口路径 TOKEN 你的Token RULE_DIR ./rules def collect_rules(): rules [] for filename in os.listdir(RULE_DIR): if not filename.endswith(.txt): continue with open(os.path.join(RULE_DIR, filename), r, encodingutf-8) as f: rules.extend(line.strip() for line in f if line.strip()) return rules def push_rules(rules): headers { Authorization: fBearer {TOKEN}, Content-Type: application/json } # 分块提交避免单次规则量过大 chunk_size 100 for i in range(0, len(rules), chunk_size): chunk rules[i:i chunk_size] payload { name: fbatch_{i // chunk_size}, rules: \n.join(chunk) } response requests.post(API_URL, headersheaders, jsonpayload, timeout30) print(response.status_code, response.text) if __name__ __main__: rules collect_rules() print(f共 {len(rules)} 条规则) push_rules(rules)这个脚本的价值在于规则文件可以纳入版本管理脚本负责同步避免在网页端逐条敲规则。实际使用时请将接口路径、Token 和规则目录替换成你自己的配置。6.4 日志统计脚本拦截统计的本质是读取查询日志过滤出状态为“已拦截”的记录。你可以在控制面板导出日志也可以用脚本巡检接口数据。下面是一个按关键词统计拦截数量的模板import json from collections import Counter # 假设日志文件是 JSON 行格式 log_file querylog.json counter Counter() with open(log_file, r, encodingutf-8) as f: for line in f: try: item json.loads(line.strip()) except json.JSONDecodeError: continue # 判断拦截状态的字段名需要以实际导出格式为准 if item.get(status) blocked: domain item.get(domain, unknown) counter[domain] 1 print(拦截总数:, sum(counter.values())) for domain, count in counter.most_common(10): print(domain, count)注意日志导出的字段结构不同脚本中的status和domain字段名需要按实际日志调整。6.5 批量任务设计建议批量导入规则时建议按以下顺序执行先备份当前规则配置。在测试环境或测试设备上验证新规则。分批次提交每批 100 到 500 条。每批提交后检查服务端是否正常响应。若出现大面积误拦截立即用备份回滚。7. 资源占用与性能观察本地部署的服务资源占用直接影响运行稳定性尤其是当设备配置不高时需要重点观察以下几项。7.1 内存与 CPU服务进程常驻内存具体占用取决于规则数量和查询负载。启动初期内存占用较低随着日志积累会逐渐增加。可以通过系统监控命令实时观察# 查看服务进程资源占用 ps aux | grep AdGuardHome # 持续观察 top -p $(pgrep -f AdGuardHome)Windows 上可以直接打开任务管理器按进程名查看内存和 CPU 占用。7.2 日志增长与磁盘查询日志是磁盘占用的大头。默认记录所有查询时高流量的局域网一天可能产生几万到几十万条日志。建议定期清理日志或配置自动轮转控制日志保留周期。不要等到磁盘写满才发现问题。7.3 DNS 查询延迟服务端拦截模式会增加一次规则匹配过程但本地匹配耗时远小于网络请求耗时。可以通过dig或nslookup测一下查询耗时正常情况下增加的时间应该非常有限。如果发现查询明显变慢优先检查 DNS 上游服务器是否稳定。7.4 规则数量与匹配性能规则数量越大匹配时间越长但常规数量级下影响并不明显。真正影响性能的是超长正则表达式和过于复杂的通配规则。维护规则时尽量使用精确域名或标准通配语法少写高开销正则。7.5 降低资源占用的方法关闭不用的日志类别减少日志写入量。定期清理过期规则文件。控制上游 DNS 服务器数量避免每次查询同时请求多个上游。在非调试阶段关闭详细日志。8. 常见问题与排查方法问题现象可能原因排查方式解决方案控制面板打不开端口被占用或服务未启动查看日志、检查端口监听更换端口或重启服务DNS 查询日志为空设备没有使用本服务作为 DNS查看设备网络设置手动修改设备 DNS 地址拦截计数不增长规则未生效或浏览器缓存刷新页面、查询测试域名更新规则列表、清理缓存某些正常网站打不开规则误拦截了 CDN 或接口域名查看日志中被拦截的正常域名添加白名单启动时提示 53 端口占用系统自带的 DNS 服务在运行检查 53 端口监听状态停止系统 DNS 服务规则导入后不生效规则语法错误或格式异常核对规则语法、查看服务端日志修正规则后重新导入API 请求返回 401/403Token 错误或权限不足检查 Token 是否过期重新创建访问凭据批量导入卡住单次规则量过大查看服务端响应时间分块提交日志磁盘占用过高日志保留周期过长查看日志目录大小配置自动轮转和定期清理以上排查方法同样适用于其他同类 DNS 过滤服务核心思路是先确认服务在跑再确认流量到了最后确认规则命中。9. 最佳实践与使用建议9.1 规则源分类管理不要把所有规则塞进一个大文件。建议按功能拆分基础广告规则过滤常见的广告联盟域名。隐私追踪规则过滤已知统计和追踪域名。自定义白名单保存不可拦截的关键业务域名。临时规则用于调试和短期验证。这样分类后出现问题时可以快速定位是哪一类规则引起的。9.2 先测试再推广在正式环境下不要先把所有规则推到全网设备。先在单台测试设备上验证观察一两天确认没有误拦截后再推广。9.3 定期备份配置服务配置和规则列表是长期积累的资产。建议定期导出备份并纳入版本管理。备份内容包括服务配置文件自定义规则文件白名单列表用户账号信息9.4 观察拦截日志的规律拦截日志不仅能用于统计数量还能反映设备的异常流量特征。定期查看“被拦截域名排行”和“查询频次最高的设备”可以帮助发现异常流量和潜在风险。9.5 合法合规使用广告拦截的本质是用户对自身网络流量的自主控制。不要在未经授权的情况下为他人设备强制配置过滤规则不要利用拦截功能破坏网站的正常商业逻辑也不要绕过付费墙或登录鉴权。对于在线内容应遵守平台服务条款。10. 总结与下一步回到标题里的“我拦截了1000000个广告”这个数字的意义不在于“一百万”本身而在于它背后的完整链路——一条广告请求从设备发出经过本地 DNS 服务时被规则命中拦截状态写入日志统计数字增加。整个过程不需要人工干预每天 24 小时连续运行。这套系统最值得尝试的点是把广告拦截从“浏览器插件”升级成了“网络基础服务”。你只需要维护一处规则就能让整个局域网内所有设备共同受益。最先应该验证的功能是 DNS 拦截链路手动把设备 DNS 指过来查询一个已知广告域名看日志里是否出现拦截记录。这一步通了后续的规则管理和 API 批量操作才有意义。最容易踩的坑有两个一个是 53 端口被系统服务占用导致服务无法启动另一个是规则误拦截了正常 CDN 或接口域名造成网址打开异常。提前做好白名单机制可以大幅降低第二个问题的影响。后续可以继续扩展的方向把规则维护改成自动化流水线定时拉取公开规则源并同步更新。把日志统计接入可视化面板实时展示拦截趋势。结合自建监控服务在服务异常或磁盘写满时自动告警。将规则库拆分到独立的仓库管理版本回滚和多人协作会更方便。如果你正好有一台常开的设备又不想让每台设备都装一遍插件这个方案值得从今天开始尝试。建议收藏备用遇到问题时可以直接对照排查表格处理。