用户工具

站点工具


xnix:nginx_doh_proxy

使用 Nginx 代理 DoH

本文简述用 Nginx 代理 DoH (DNS Over HTTPS)的实现方式.

先说说碰到的坑.

  • 根据 RFC, DoH 应该是承载在 HTTP2 上, 而 nginx 的 proxy_pass 是不支持 h2 的, 需要用 gRPC 模块 grpc_pass 来代理转发. 部分支持 http1 的可以继续使用 proxy_pass.
  • grpc_pass 不支持指定远端 URI, 如果两端 URI 不一致, 要用 rewrite.
  • 用 upstream 时, grpc_pass / proxy_pass 的 Host 头发送有问题, 需要指定. 而不用 upstream 则没问题:-?
  • nginx 不能直接记录 request body, 所以解包 DoH 的查询域名, 要靠其他方法. 这个会在Nginx + njs 记录 DoH 的查询域名介绍.

nginx.conf 配置

配置 upstream, 用于 keepalive.

http {
	# ... 省略设置
	upstream doh-google {
		zone		doh-google 64k;
		server		8.8.8.8:443;
		server		8.8.4.4:443;
		# keepalive 的数量不需要多, 建议为 CPU 数*2
		keepalive	16;
	}
	upstream doh-cloudflare {
		zone		doh-cloudflare 64k;
		server		1.1.1.1:443;
		server		1.1.1.1:443;
		keepalive	16;
	}
	server {
		# ... 省略设置
		grpc_socket_keepalive	on;
		# 与 grpcs ssl 的协议, 如果远端不支持, 注释该行
		grpc_ssl_protocols	TLSv1.3;
		location /dns-query {
			# grpcs 代表远端是 ssl 连接, 如果不是, 则使用 grpc
			grpc_pass		grpcs://doh-cloudflare;
			# 用 upstream 时, http 头中的 Host 会有问题, 一些服务商例如 cloudflare 需要依赖 Host, 所以要强制指定.
			# 同样, 有些服务器商需要指定 SNI, 则需要设置 grpc_ssl_name 和 grpc_ssl_server_name. 详情参看 nginx 文档.
			grpc_set_header		Host cloudflare-dns.com;
		}
		location /dns-query2 {
			# 两端 URI 不一致, 需要 rewrite
			rewrite			/ /dns-query break;
			grpc_pass		grpcs://doh-google;
		}
		# 该范例转发至不加密的 h2 DoH
		location /dns-query3 {
			rewrite			/ /dns-query break;
			grpc_pass		grpc://127.0.0.1:8053;
		}
	}
}
xnix/nginx_doh_proxy.txt · 最后更改: 2024/08/15 16:59 由 Hshh