Skip to content

Instantly share code, notes, and snippets.

@nginx-gists
Last active November 21, 2022 12:25
Show Gist options
  • Save nginx-gists/7364e8c1f557321e09badcc93376bd28 to your computer and use it in GitHub Desktop.
Save nginx-gists/7364e8c1f557321e09badcc93376bd28 to your computer and use it in GitHub Desktop.
Using NGINX as a DoT or DoH Gateway
stream {
# Key-value store for blocking domains (NGINX Plus only)
keyval_zone zone=dns_config:64k state=/etc/nginx/zones/dns_config.zone;
keyval $dns_qname $scrub_action zone=dns_config;
keyval "blocked_domains" $blocked_domains zone=dns_config;
keyval "blackhole_domains" $blackhole_domains zone=dns_config;
# The DNS response packet; if we're scrubbing the domain, this gets set
js_set $dns_response dns.get_response;
# Set upstream to the Google DNS server if $dns_response is empty, otherwise
# to 'blocked' or 'blackhole'
map $dns_response $upstream_pool {
"blocked" blocked;
"blackhole" blackhole;
default google;
}
# Upstream pool for blocked requests
upstream blocked {
zone blocked 64k;
server 127.0.0.1:9953;
}
# Upstream pool for blackholed requests
upstream blackhole {
zone blackhole 64k;
server 127.0.0.1:9853;
}
# Upstream pool for standard (Google) DNS
upstream google {
zone dns 64k;
server 8.8.8.8:53;
}
# DNS (TCP) server
server {
listen 53;
js_preread dns.preread_dns_request;
proxy_pass $upstream_pool;
}
# DNS (UDP) server
server {
listen 53 udp;
js_preread dns.preread_dns_request;
proxy_responses 1;
proxy_pass $upstream_pool;
}
# Server for responding to blocked/blackholed responses
server {
listen 127.0.0.1:9953;
listen 127.0.0.1:9853;
listen 127.0.0.1:9953 udp;
listen 127.0.0.1:9853 udp;
js_preread dns.preread_dns_request;
return $dns_response;
}
}
# vim: syntax=nginx
stream {
# DoT upstream pool
upstream dot {
zone dot 64k;
server 8.8.8.8:853;
}
# DNS server for upstream encryption
server {
listen 53;
proxy_ssl on;
proxy_pass dot;
}
}
# vim: syntax=nginx
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format dns '$remote_addr - $remote_user [$time_local] "$request" '
'[ $msec, $request_time, $upstream_response_time $pipe ] '
'$status $body_bytes_sent "-" "-" "$http_x_forwarded_for" '
'$upstream_http_x_dns_question $upstream_http_x_dns_type '
'$upstream_http_x_dns_result '
'$upstream_http_x_dns_ttl $upstream_http_x_dns_answers '
'$upstream_cache_status';
access_log /var/log/nginx/doh-access.log dns;
upstream dohloop {
zone dohloop 64k;
server 127.0.0.1:8053;
keepalive_timeout 60s;
keepalive_requests 100;
keepalive 10;
}
proxy_cache_path /var/cache/nginx/doh_cache levels=1:2 keys_zone=doh_cache:10m;
server {
listen 443 ssl http2;
ssl_certificate /etc/nginx/ssl/certs/doh.local.pem;
ssl_certificate_key /etc/nginx/ssl/private/doh.local.pem;
ssl_session_cache shared:ssl_cache:10m;
ssl_session_timeout 10m;
proxy_cache_methods GET POST;
location / {
return 404 "404 Not Found\n";
}
location /dns-query {
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_cache doh_cache;
proxy_cache_key $scheme$proxy_host$uri$is_args$args$request_body;
proxy_pass http://dohloop;
}
}
}
stream {
js_import /etc/nginx/njs.d/dns/dns.js;
# DNS upstream pool
upstream dns {
zone dns 64k;
server 8.8.8.8:53;
}
# DNS over TLS upstream pool
upstream dot {
zone dot 64k;
server 8.8.8.8:853;
}
# DNS over HTTPS (gateway) service
# This time we’ve used a DoT upstream
server {
listen 127.0.0.1:8053;
js_filter dns.filter_doh_request;
proxy_ssl on;
proxy_pass dot;
}
}
# vim: syntax=nginx
http {
# This is our upstream connection to the njs translation process
upstream dohloop {
zone dohloop 64k;
server 127.0.0.1:8053;
}
# This virtual server accepts HTTP/2 over HTTPS
server {
listen 443 ssl http2;
ssl_certificate /etc/nginx/ssl/certs/doh.local.pem;
ssl_certificate_key /etc/nginx/ssl/private/doh.local.pem;
# Return 404 for non-DoH requests
location / {
return 404 "404 Not Found\n";
}
# Here we downgrade the HTTP/2 request to HTTP/1.1 and forward it to
# the DoH loop service
location /dns-query {
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_pass http://dohloop;
}
}
}
stream {
# Import the JavaScript file that processes the DoH(?) packets
js_import /etc/nginx/njs.d/dns/dns.js;
# DNS upstream pool (can also be DoT)
upstream dns {
zone dns 64k;
server 8.8.8.8:53;
}
# DNS over HTTPS (gateway) translation process
# Upstream can be either DNS (TCP) or DoT
server {
listen 127.0.0.1:8053;
js_filter dns.filter_doh_request;
proxy_pass dns;
}
}
# vim: syntax=nginx
stream {
# DNS upstream pool
upstream dns {
zone dns 64k;
server 8.8.8.8:53;
}
# DoT server for decryption
server {
listen 853 ssl;
ssl_certificate /etc/nginx/ssl/certs/doh.local.pem;
ssl_certificate_key /etc/nginx/ssl/private/doh.local.pem;
proxy_pass dns;
}
}
# vim: syntax=nginx
@alessfg
Copy link

alessfg commented Nov 21, 2022

Heya @wutongskype! You will need to clone/download the NJS files found here https://github.com/TuxInvader/nginx-dns/tree/master/njs.d 😄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment