本篇文章,我将介绍下方便本地开发和调试的方案,本地 DNS 代理服务器。
不论是你做前端还是后端开发,本地调试带有域名的接口或页面是大概率绕不开的事情。甚至,如果你使用了自签名证书或者使用了“虚拟域名”进行 HomeLab 服务搭建,在某些不能使用网络默认 DNS 服务器时,也需要一些“灵活”的方案来动态切换一系列域名的指向。
不过,也不能因为手持锤子就看哪里都是钉子。简单的场景下,比如就修改一次的情况下,直接修改 hosts 文件解决问题会是更简单的方案,关于 “Hosts Editor” 类的工具的推荐,可以阅读文末章节。
言归正传,先来聊一个我使用了六个多月的方案。
dnsmasq 作为 DNS Server 被广泛用于 Linux 发行版。我们常见的 Ubuntu Server 版以及 Open WRT 路由器固件中,不少版本默认使用的都是它。
但是它是一个命令行软件,默认并不支持自动重载有修改后的配置文件,配置文件的编辑和我们常规修改 /etc/hosts
别无二致,国外有一个工程师为了解决这个问题,开发了一个简单的带有界面的配置工具 docker-dnsmasq,在配置文件被修改后,能够发送命令重启或重载 dnsmasq 主程序,达到“方便使用”的目的。
因为作者许久不更新软件,在今年二月的时候,我做了一个 fork 版本,soulteary/docker-dnsmasq,你可以使用下面的配置快速运行一个属于你的本地 DNS 服务器。
以往我们编辑 hosts 文件,会用下面的形式来进行域名绑定:
10.11.12.123 docker.lab.com
10.11.12.123 maven.lab.com
10.11.12.123 npm.lab.com
10.11.12.123 pypi.lab.com
...
所以当域名很多的时候,使用起来就会非常麻烦,相比之下 dnsmasq 的配置文件就会简单许多,因为它允许使用“泛解析”的方式,除此之外还能指定上游服务器,近一步扩展能力,下面就是一个 dnsmasq.conf
的配置文件的例子:
# HomeLab
## Use Home DNS Upstream
server=10.11.12.13
# HomeLab Domain Example:
address=/.lab.com/10.11.12.123
address=/*.lab.com/10.11.12.123
address=/*.demo.lab.com/10.11.12.123
address=/*.api.lab.com/10.11.12.123
address=/*.some.api.lab.com/10.11.12.123
# localhost
address=/.lab.io/127.0.0.1
address=/*.lab.io/127.0.0.1
在上面的例子中,将 lab.com 和一些子域名指向了内网的一台机器,而将 lab.io 全部指向了本机,将上面的内容保存为 dnsmasq.conf
,我们来编写容器编排文件:
version: "3"
services:
dns:
image: soulteary/docker-dnsmasq
restart: always
# 如果你需要一个简单的 Basic Auth 认证
#environment:
# - HTTP_USER=user
# - HTTP_PASS=pass
ports:
- "53:53/udp"
- "53:53/tcp"
- "8080:8080"
volumes:
- ./dnsmasq.conf:/etc/dnsmasq.conf:rw
将上面的内容保存为 docker-compose.yml
,然后使用 docker-compose up -d
启动服务,接着使用浏览器访问 8080 端口,就能看到控制面板了,开始使用啦。
一个简单的 dnsmasq 管理面板
需要额外注意的是,为了减少后续设置的复杂,我们默认使用 53 端口来提供服务,管理面板默认使用的端口是 8080,如果你有端口冲突,建议进行调整或修改。
软件界面比较简单,使用方式就是使用所见即所得的编辑器修改内容,然后点击保存等待配置生效。如果你在配置存放一些不同环境的配置,然后批量选中某个环境的记录,通过快捷键(CMD+/
)切换记录的注释状态,就能进行不同环境 DNS 记录的快速切换了。(最近半年里,我就是这么解决不同环境的 DNS 记录切换的,配置示例):
# HomeLab
## Use Home DNS
server=10.11.12.13
# Office
## Use Dev NS Servers
# server=219.141.136.10
# server=219.141.140.10
## Use CloudFlare NS Servers
# server=1.0.0.1
# server=1.1.1.1
# Local
address=/.lab.io/127.0.0.1
address=/*.lab.io/127.0.0.1
address=/.lab.com/10.11.12.123
address=/*.lab.com/10.11.12.123
address=/*.demo.lab.com/10.11.12.123
address=/*.api.lab.com/10.11.12.123
address=/*.some.api.lab.com/10.11.12.123
# address=/.lab.com/192.11.12.123
# address=/*.lab.com/192.11.12.123
# address=/*.demo.lab.com/192.11.12.123
# address=/*.api.lab.com/192.11.12.123
# address=/*.some.api.lab.com/192.11.12.123
当然,这个程序同时会读取容器内的 /etc/hosts
,你也可以通过左侧侧边栏切换编辑器打开 hosts
文件,用传统的方式添加修改 DNS 记录。
在软件使用过程中,也会有一些体验不好的地方,比如程序重载需要几秒的时间,过程中会有服务不可用的状态,编辑器只有最基础的功能,缺少快捷键等。
偶尔有的时候程序会出现一些异常的资源使用,经过查找,发现社区里也有人反馈,虽说重启一下容器就能解决问题,但是毕竟有瑕疵,所以我开始考虑对这个方案进行替换调整。
当我们启动了本地服务之后,默认请求并不会有任何改变,除非我们将这个配置应用到系统网络配置中。
以 macOS 为例,打开网络设置,选择当前网络,点击“高级”按钮,然后切换到 DNS 选项卡,在左侧的 DNS 服务器里,添加 “127.0.0.1”即可。
调整 macOS 的网络DNS配置
这里有一个小技巧,为了保证网络完全不间断(比如重启服务的时候),这里可以除了添加我们指定的 DNS 服务之外,将当前网络的 DNS 服务器也添加进去。
如果你是我的老读者,那么应该对 Traefik 不会感到陌生,这里提供一个简单的配置,方便你使用 Traefik:
version: "3"
services:
dns:
image: soulteary/docker-dnsmasq
restart: always
# 如果你需要一个简单的 Basic Auth 认证
# 使用 Traefik 推荐使用 Forward Auth 进行取代
#environment:
# - HTTP_USER=user
# - HTTP_PASS=pass
ports:
- "53:53/udp"
- "53:53/tcp"
- "8080:8080"
volumes:
- ./dnsmasq.conf:/etc/dnsmasq.conf:rw
labels:
- "traefik.enable=true"
- "traefik.docker.network=traefik"
- "traefik.http.routers.dnsmasq-web.entrypoints=http"
- "traefik.http.routers.dnsmasq-web.rule=Host(`dns.lab.io`)"
- "traefik.http.routers.dnsmasq-ssl.entrypoints=https"
- "traefik.http.routers.dnsmasq-ssl.tls=true"
- "traefik.http.routers.dnsmasq-ssl.rule=Host(`dns.lab.io`)"
- "traefik.http.services.dnsmasq-backend.loadbalancer.server.scheme=http"
- "traefik.http.services.dnsmasq-backend.loadbalancer.server.port=8080"
networks:
- traefik
networks:
traefik:
external: true
关于 “Traefik 鉴权”话题,之前有提到过,感兴趣可以自取(上篇/下篇),另外,最近有做一个小项目,可以进一步简化这个场景的操作。
接下来,来聊聊新的方案。
go-dnsmasq 是一个轻量到只有 1.2MB 的 DNS 缓存/转发工具,但是可惜的是作者在 16 年之后就没有继续进行项目维护了。在翻阅了几十个 fork 衍生版之后,我最终将两个国外的改进版本合并成了一个新的版本 https://github.com/soulteary/go-dnsmasq,并制作了一个 2.7 MB 左右的容器镜像。
使用方法其实比上面还要简单,先来看配置文件:
127.0.0.1 lab.com
127.0.0.2 *.lab.com
平凡无奇的 hosts 记录的语法中,支持了泛解析,比 dnsmasq.conf
少了不少符号记忆的负担。虽然日常使用肯定会使用复制粘贴,但是少一个字符,出错的可能就少了一分,不是吗?将上面的内容保存为 hosts.conf
,稍后使用。
先来继续编写容器配置文件:
version: "3"
services:
dns:
image: soulteary/go-dnsmasq
command: dnsmasq -l 0.0.0.0:53 -f /hosts.conf -p 1s --nameservers 10.11.12.13:53
restart: always
ports:
- "53:53/udp"
- "53:53/tcp"
volumes:
- ./hosts.conf:/hosts.conf:rw
相比较方案一,这个方案显然更“轻量环保”。至于切换环境配置,只需要准备多份不同环境的配置文件,使用 docker 挂载的时候切换文件就可以啦。
配置中的启动命令中,我定义了几个参数,只需要关注最后一个参数即可:
dnsmasq -l 0.0.0.0:53 -f /hosts.conf -p 1s --nameservers 10.11.12.13:53
参数中的 --nameservers
需要设定为你的网络环境中的默认 DNS,当然如果你参考上文中提到的“结合系统使用”的方式,不进行指定也不会影响使用。
接着,来聊聊文章开头聊到的编辑本地 Hosts 文件。
如果你只需要管理几个域名,也不太想启动一个服务(哪怕它只有2M),可以尝试编辑系统的 Hosts
文件来完成域名指向,如果你厌倦了命令行或者记事本修改文件,也可以考虑下载一些 Hosts Editor 类的工具。
最初的时候,我使用过 Gas Mask、HostsMan,以及一些类似的软件,在第一次去淘宝工作的时候,被安利了一个内网神器“iHosts”(不是搜索引擎搜索出的同名软件),除了多了清新的界面之外,还支持记录分组,以及本地 DNS 服务器,对于调试移动端场景、或者虚拟机场景还是挺方便的。
Switch Hosts 默认界面
在许多年前离开淘宝后,因为无法再从内网下载“ihosts”,于是就切换到了 “SwitchHosts!”(最新版本改名字去掉了“!”),虽然没有内置 DNS 服务、请求日志等功能,但是胜在功能简单够用,加上作者靠谱,也就一直用了下来。
为什么说作者靠谱呢?早些时候和刚从淘宝离开的作者季札大神一起吃饭,聊起招聘困难,当时玩笑的说要不要在 SwitchHosts README 里加个招聘广告,季札说希望这个软件能够一直纯粹下去,然后这些年这个软件,至今为止就一直这么干净纯粹着,还是挺难得的。
但是,在使用过程中难免会遇到需要做“泛解析”的场景,批量改动记录总归是比较麻烦的事情,以及我的电脑常年不关机,经常休眠唤醒,基于 Electron 的 SwitchHosts 经常会出现内存溢出的问题,所以只好忍痛把主力方案切换到了上文中的 DNS 方式。
其实解决的方案也很简单,和方案一一样,就是每次使用完 SwitchHosts 之后,把它的进程彻底关掉,再重启就好了。后续我应该会继续使用 SwitchHosts 这个功能,不过,应该不会再作为主力工具,毕竟泛解析能够省不少事儿。
HTTPS 时代中,本地调试有的时候也躲不开配置证书,关于如何方便的制作和使用自签名证书,我曾写过一篇文章进行介绍,如果你有这方面的需求,可以自行取用。
原本以为离职休假能够把草稿箱里的文章清理一下,没想到积累的草稿更多了,感谢令人头疼的好奇心,和追求最优解的倔强。
--EOF
如果你觉得内容还算实用,欢迎点赞分享给你的朋友,在此谢过。