使用 Nginx 代理 DoH

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

先说说碰到的坑.

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;
		}
	}
}