自己搭建一个https的dns,让不同的浏览器使用不同的DNS,使用相同的域名访问到不同的主机上
我有一个web项目,使用域名访问,需要同时运行线上环境和测试环境,为了防止一些css、js缓存影响,在不同的浏览器里分别访问线上环境和测试环境,比如Chrome浏览器访问测试环境,而Safari浏览器访问线上环境。
通常,需要切换环境的时候,通过修改/etc/hosts进行切换,但是这样比较麻烦,有时候忘记切换了就会导致不同环境的cookie相互污染。
于是想到了这样一个可以一劳永逸的方案:
- 测试环境自己搭建一个dns,将域名解析到测试环境设备,未配置的域名则使用公网dns进行解析。
- 搭建一个http协议的dns服务,既DNS over HTTPs(DoH),用于提供https协议的dns查询服务。
- 修改 chrom 浏览器设置中的安全dns配置,使用自己搭建好的Doh服务地址。
1. 搭建dnsmasq,提供基础的dns服务
dnsmasq是一个轻量级的dns服务,支持配置指定域名的解析,未配置的域名解析请求支持转发到其他dns。
推荐使用jpillora/dnsmasq这个镜像,他提供了一个web接口,可以直接通过web修改dnsmasq的配置文件。
- 首先我们创建一个dnsmasq的配置,在里面指定一下需要解析的域名
最好创建一个目录,保存这个服务的配置文件和日志等。。。
mkdir /home/dnsmasq
cd /home/dnsmasq
touch dnsmasq.conf
touch dnsmasq_add_hosts
cat dnsmasq.conf
- dnsmasq.conf
#dns解析日志
log-queries
# 给不同的域,设置不同的dns
server=/github.com/8.8.8.8
server=/github.com/223.5.5.5
server=/google.com/8.8.8.8
server=/google.com/223.5.5.5
# Change this line if you want dns to get its upstream servers from
# somewhere other that /etc/resolv.conf
# 外部dns服务器地址,格式和 /etc/resolv.conf 一样,如果请求解析的域名没有在下面的列表中,就转发到这些dns进行查询
resolv-file=/usr/local/etc/resolv.dnsmasq.conf
# If you don't want dnsmasq to read /etc/hosts, uncomment the
# following line.
no-hosts
# or if you want it to read another file, as well as /etc/hosts, use
# this. 意思就是从这里读取自定义的域名解析,格式和/etc/hosts一样
addn-hosts=/usr/local/etc/dnsmasq_add_hosts
#域名与IP映射,支持配置多个
address=/zhangsan.sanzhang.com/192.168.100.233
address=/lisi.sanzhang.com/192.168.100.234
- 通过docker启动masq:
docker run -d --name dnsmasq -p 53:53/udp -p 8080:8080 -v /home/dnsmasq/dnsmasq.conf:/etc/dnsmasq.conf -v /home/dnsmasq:/usr/local/etc --log-opt "max-size=100m" -e "HTTP_USER=admin" -e "HTTP_PASS=123456" jpillora/dnsmasq
- 测试:
dnsmasq]# dig @127.0.0.1 sanzhang.zhangsan.com
; <<>> DiG 9.11.4-P2-RedHat-9.11.4-26.P2.el7_9.13 <<>> @127.0.0.1 sanzhang.zhangsan.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 61007
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;sanzhang.zhangsan.com. IN A
;; ANSWER SECTION:
sanzhang.zhangsan.com. 0 IN A 192.168.100.233
;; Query time: 1 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: 三 12月 13 20:58:38 CST 2023
;; MSG SIZE rcvd: 66
2. 搭建 Doh
我们使用开源项目github.com/m13253/dns-over-https来实现Doh服务。
- 获取最新的镜像
docker pull m13253/dns-over-https-server:latest
- 先搞个配置文件:
docker run --rm -ti doh-server cat doh-server.conf > doh-server.conf
- 修改下配置文件,将里面的dns地址修改为我们刚搭建的dnsmasq的地址(切记)
# Upstream DNS resolver
# If multiple servers are specified, a random one will be chosen each time.
# You can use "udp", "tcp" or "tcp-tls" for the type prefix.
# For "udp", UDP will first be used, and switch to TCP when the server asks to
# or the response is too large.
# For "tcp", only TCP will be used.
# For "tcp-tls", DNS-over-TLS (RFC 7858) will be used to secure the upstream connection.
upstream = [
"udp:192.168.100.233:53"
]
当然也可以修改下默认的端口,默认是8053:
# HTTP listen port
listen = [
":8053",
## To listen on both 0.0.0.0:8053 and [::]:8053, use the following line
# ":8053",
]
- 然后启动doh-server,并映射我们刚修改的文件到容器中
docker run -d --name doh-server --restart=always -v /root/doh-server.conf:/doh-server.conf --network host --privileged m13253/dns-over-https-server:latest
- 我们搞个python脚本来测试下这个doh:
import dns.message
import requests
import base64
import json
doh_url = "http://192.168.100.233:8053/dns-query"
domain = "sanzhang.zhangsan.com"
rr = "A"
result = []
cert = ()
ca_verify = True
message = dns.message.make_query(domain, rr)
dns_req = base64.b64encode(message.to_wire()).decode("UTF8").rstrip("=")
r = requests.get(doh_url + "?dns=" + dns_req,
headers={"Content-type": "application/dns-message"},
cert=cert,
verify=ca_verify)
for answer in dns.message.from_wire(r.content).answer:
dns = answer.to_text().split()
result.append({"Query": dns[0], "TTL": dns[1], "RR": dns[3], "Answer": dns[4]})
print(json.dumps(result))
# python3 -m pip install dns.message
# python3 q.py
[{"Query": "sanzhang.zhangsan.com.", "TTL": "0", "RR": "A", "Answer": "192.168.100.233"}]
测试没问题,但是chrome浏览器请求安全dns始终是通过https协议的,因此我们还需要在外面在搭建一个https服务,用来代理dos的http服务。
3. 自建证书,通过nginx搭建https服务
3.1 创建自签名证书
这里我们选择自签名证书,这样想搞多久就搞多久,反正都是自己用。
关于OpenSSL生成证书的问题很多,这里着重讲下容易踩坑的地方:
- 域名要提前确认,证书签名要设置域名;因为我们这个https服务是给dns服务准备的,因此域名字段我们就用IP地址好了。
- nginx可以视为
https服务的server端,其证书需要和运行server的ip地址一样。 - client端就是本机证书签名,要包含server端IP地址,但是貌似直接使用IP会报错,原因也不知道。
- 为了解决使用IP签名会报错,我们给dns的IP地址搞个“域名”,在/etc/hosts 中设置好。比如:
echo 192.168.100.233 zhangsan.de.dns >> /etc/hosts
整理了下生成证书的命令,按照这个shell脚本生成就可以了:
mkdir https_pem
cd http_pem
cat gen_pems.sh
大家在使用这个脚本的时候,注意下修改里面的zhangsan.de.dns、192.168.100.233为你server端的域名和IP,yzc为你client端(chrome浏览器所在设备)的hostname。
#!/bins/sh
echo "current datetime: `date +"%F %T"`"
if [ ! -f "ssl.conf" ];then
echo "start create ssl.conf"
echo -e "[v3_req]\nsubjectAltName=DNS:zhangsan.de.dns,DNS:192.168.100.233,DNS:localhost" > ssl.conf
fi
# 创建我们自己CA的私钥
# 创建我们自己CA的CSR,并且用自己的私钥自签署之,得到CA的身份证:
openssl genrsa -out ca.key 2048
if [[ $? != 0 ]];then echo "create ca.key failed."; exit 1; fi
openssl req -new -x509 -days 730 -key ca.key -subj "/C=CN/ST=GD/L=SZ/O=Acme, Inc./CN=ZhangSan De Root CA" -out ca.crt
if [[ $? != 0 ]];then echo "create ca.crt failed."; exit 1; fi
# 创建server的私钥,CSR,并且用CA的私钥自签署server的身份证:
CN_Names="CN=zhangsan.de.dns/CN=192.168.100.233/CN=localhost"
openssl req -newkey rsa:2048 -nodes -keyout server.key -subj "/C=CN/ST=GD/L=SZ/O=ZhangSan, Inc./${CN_Names}" -out server.csr
if [[ $? != 0 ]];then echo "create server.key failed."; exit 1; fi
openssl x509 -req -extfile ssl.conf -extensions v3_req -days 730 -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt
if [[ $? != 0 ]];then echo "create server.crt failed."; exit 1; fi
# 创建client的私钥,CSR,以及用ca.key签署client的身份证:
CN_Names="CN=localhost/CN=yzc"
openssl req -newkey rsa:2048 -nodes -keyout client.key -subj "/C=CN/ST=GD/L=SZ/O=Acme, Inc./${CN_Names}" -out client.csr
if [[ $? != 0 ]];then echo "create client.key failed."; exit 1; fi
openssl x509 -req -extfile ssl.conf -extensions v3_req -days 730 -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt
if [[ $? != 0 ]];then echo "create client.crt failed."; exit 1; fi
生成的证书列表里这些是有用的:
# 根证书
ca.crt
ca.key
# nginx使用的证书,提供https服务
server.crt
server.key
# pc端的证书,访问我们自己搭建的https服务要使用这个证书
client.crt
client.key
将client.crt,client.key 和根证书ca.crt拷贝到本机,一会修改下python脚本,验证https访问是否正确。
scp root@192.168.100.233:/root/https_pams/client* ./https_pams/
scp root@192.168.100.233:/root/https_pams/ca.crt ./https_pams/
3.2 配置nginx,启动https服务,并代理到本机的Doh端口(8053)
按照这个配置文件搞就可以了:
cat /root/https_pams/https-dns.conf
server {
listen 443 ssl http2 default_server;
listen [::]:443 ssl http2 default_server;
server_name 192.168.100.233;
ssl_client_certificate /root/https_pams/ca.crt;
ssl_certificate /root/https_pams/server.crt;
ssl_certificate_key /root/https_pams/server.key;
#ssl_ciphers HIGH:!aNULL:!MD5;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_session_timeout 10m;
ssl_session_cache shared:SSL:10m;
resolver 192.168.100.233 valid=300s; # Replace with your local resolver
resolver_timeout 5s;
# HTTP Security Headers
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header Strict-Transport-Security "max-age=63072000";
location /dns-query {
proxy_pass http://localhost:8053/dns-query;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
在nginx配置中,添加如下配置,引入我们的https配置:
include /root/https_pams/https-dns.conf;
然后执行nginx -s reload,使配置生效,正常是不会有什么报错的,我这里连waring信息都没有。
然后我们来修改下刚刚那个python脚本,增加证书设置:
其实,就是把代码里doh地址修改下,以及将cert 和 ca_verify ,修改为我们从远程拷贝而来的client证书和ca证书:
doh_url = "https://192.168.100.233/dns-query"
cert = ("./https_pams/client.crt", "./https_pams/client.key")
ca_verify = "./https_pams/ca.crt"
在测试下,如果python脚本报错:
- urllib3.util.ssl_match_hostname.CertificateError: hostname 'xxxx' doesn't match either of 'xxxx', 'xxxx'
- ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: certificate signature failure (_ssl.c:1125)
啊,那就检查下nginx证书配置那块,还有生成证书里的域名配置是否正确。
正常是不会有什么报错的。
4. 导入证书到系统中,并修改chrome浏览器的安全dns地址为我们的doh地址
在访达中找到证书位置,双击"ca.crt"和"client.crt",进入钥匙串后,我们找到导入的证书,在显示简介中信任一栏展开,并选择为始终信任即可。
不同版本chrome有不同设置方法,自行搜索安全dns设置即可。
找到后,将安全dns地址设置为:
chrome默认有几个安全dns地址,比如,也可以python脚本测试下,都是可以用的
然后我们在不同的浏览器访问 sanzhang.zhangsan.com,就访问到了不同的主机了,再也不用切换hosts了。
自己搭建一个https的dns,让不同的浏览器使用不同的DNS,使用相同的域名访问到不同的主机上的更多相关文章
- 怎么在阿里云搭建一个WordPress博客(超详细教程)
想以正确的方式启动一个 WordPress 博客吗?我知道,这可能是一个令人恐惧的想法 -- 其实你并不孤单.但是,在帮助很多用户创建博客之后,我决定编写一份详细的指南,让任何没有技术知识的人都能拥有 ...
- 局域网内搭建一个服务器,可以使用 https 吗
https://www.v2ex.com/t/472394 这是一个创建于 126 天前的主题,其中的信息可能已经有所发展或是发生改变. 局域网内通过嵌入式设备搭建一个轻量级 web 服务,可以仍然使 ...
- 用Docker搭建一个支持https的nginx代理服务
用Docker搭建一个支持https的nginx代理服务 说明:本文所提的服务只是作者平常测试使用,可能含有未知bug或不成熟的解决方案,仅供参考,请不要用于正式环境,当然,使用过程中有任何问题欢迎提 ...
- netty系列之:来,手把手教你使用netty搭建一个DNS tcp服务器
目录 简介 搭建netty服务器 DNS服务器的消息处理 DNS客户端消息请求 总结 简介 在前面的文章中,我们提到了使用netty构建tcp和udp的客户端向已经公布的DNS服务器进行域名请求服务. ...
- 基于hexo+github搭建一个独立博客
一直听说用hexo搭建一个拥有自己域名的博客是很酷炫的事情~,在这十一花上半个小时整个hexo博客岂不美哉. 使用Hexo吸引我的是,其简单优雅, 而且风格多变, 适合程序员搭建个人博客,而且支持多平 ...
- Dnsmasq安装与配置-搭建本地DNS服务器 更干净更快无广告DNS解析
默认的情况下,我们平时上网用的本地DNS服务器都是使用电信或者联通的,但是这样也导致了不少的问题,首当其冲的就是上网时经常莫名地弹出广告,或者莫名的流量被消耗掉导致网速变慢.其次是部分网站域名不能正常 ...
- 搭建一个免费的,无限流量的Blog----github Pages和Jekyll入门
喜欢写Blog的人,会经历三个阶段. 第一阶段,刚接触Blog,觉得很新鲜,试着选择一个免费空间来写. 第二阶段,发现免费空间限制太多,就自己购买域名和空间,搭建独立博客. 第三阶段,觉得独立博客的管 ...
- 如何搭建一个独立博客——简明Github Pages与Hexo教程
摘要:这是一篇很详尽的独立博客搭建教程,里面介绍了域名注册.DNS设置.github和Hexo设置等过程,这是我写得最长的一篇教程.我想将我搭建独立博客的过程在一篇文章中尽可能详细地写出来,希望能给后 ...
- 在家用机上搭建 Git https 服务器
今天主要叙述在家里台式机的虚拟机上搭建支持 https 的 ubuntu git 服务器. 实际上,从一个用户请求家里 git 服务器代码,最终完成代码的传输,主要是通过以下的过程: 首先,从外界寻找 ...
- 如何自行搭建一个威胁感知大脑 SIEM?| 硬创公开课
如何自行搭建一个威胁感知大脑 SIEM?| 硬创公开课 本文作者:谢幺 2017-03-10 10:09 专题:硬创公开课 导语:十年安全产品经验的百度安全专家兜哥,手把手教你用开源项目搭建SIEM安 ...
随机推荐
- AI 艺术工具通讯
创刊号 AI 领域的发展速度令人惊叹,回想一年前我们还在为生成正确手指数量的人像而苦苦挣扎的场景,恍如隔世 . 过去两年对开源模型和艺术创作工具而言具有里程碑意义.创意表达的 AI 工具从未像现在这般 ...
- 最优化算法动量法Momentum
动量法的结论: 1.动量方法主要是为了解决Hessian矩阵病态条件问题(直观上讲就是梯度高度敏感于参数空间的某些方向)的. 2.加速学习 3.一般将参数设为0.5,0.9,或者0.99,分别表示最大 ...
- SpringBoot - [04] 自动装配原理
题记部分 Spring Boot的自动装配(Auto-Configuration)原理是其简化Spring应用开发的关键特性之一,它能自动配置Spring框架及第三方库,极大地减少了手动配置的工作 ...
- 洛谷P11250 [GESP202409 八级] 手套配对 题解
题目传送门. 非常简单的组合数学题. 首先从 \(n\) 对手套中恰好选出 \(k\) 对手套的方案数为 \(C_n^k\),然后由于我们要取出 \(m\) 只手套,那么取了 \(k\) 对手套后还要 ...
- C#/.NET/.NET Core技术前沿周刊 | 第 28 期(2025年2.24-2.28)
前言 C#/.NET/.NET Core技术前沿周刊,你的每周技术指南针!记录.追踪C#/.NET/.NET Core领域.生态的每周最新.最实用.最有价值的技术文章.社区动态.优质项目和学习资源等. ...
- Matlab转python的索引问题
python 中numpy库可以实现类似matlab多维数组的运算.但两者在索引方式上存在一些差异.这是需要注意的.例如: % 定义一个4*4矩阵 A=1:16; A=reshape(A,[4,4]) ...
- ppt 文字 +图 样式 设计
1. 设计前 设计后 图 +文字排版 图多 字少
- linux shell用expect实现在scp时自动输入密码
文章目录 linux shell用expect自动输入密码 按行读取文件 expect 其他 linux shell用expect自动输入密码 最近有东西需要部署到很多服务器上去,一个服务器一个服务器 ...
- protobuf优缺点及编码原理
什么是protobuf protobuf(Google Protocol Buffers),官方文档对 protobuf 的定义:protocol buffers 是一种语言无关.平台无关.可扩展的序 ...
- halcon 入门教程(五) 缺陷检测
原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/18785484 有兴趣可以多看其他的halcon教程 halcon 学习教程目录 本篇主要讲一些 ...