Introduction
Traditional DNS queries and responses are sent over UDP or TCP without encryption. This is vulnerable to eavesdropping and spoofing (including DNS-based Internet filtering). Responses from recursive resolvers to clients are the most vulnerable to undesired or malicious changes, while communications between recursive resolvers and authoritative name servers often incorporate additional protection. (Google)
To simplify, anybody on your network, your ISP, etc … can easily spoof DNS response and decide to send you to a different website than the one you desired. Also, it has some privacy implication where anybody between you and the DNS server can know what website you visit.
Guide
The guide is divided in multiple part. The first one covers how to setup a DNS-over-HTTPS (DoH) as Backend to serve the query.
The second part explains how to make couple of changes to that configuration to have PiHole (dns server that block ads) as DNS server behind DoH.
The third part explains how to add DNS-over-TLS to your setup. Useful if you own Android 9 (Pie) devices.
The last part will provide you with a list of client for Windows, Linux, Android and iOS that supports DoH natively to be able to use it on all your devices.
Server
I advise you to setup VPS at Vultr or Upcloud (Get free credit). You can setup anywhere you want, I only advise there because they have a good image for Ubuntu 18.04.
Architecture
DNS-over-HTTPS server
First, install the server that implement the DoH protocol to get an HTTP request and do a DNS request.
I provide 2 ways to install it, either you download the deb I provide or you compile the program (in golang) yourself.
Download
For this tutorial, I’ve taken the time to compile and package DNS-over-HTTPS (Golang) and provide a deb file easily installable.
Disclaimer
Antoine Aflalo is furnishing this item “as is”. Antoine Aflalo does not provide any warranty of the item whatsoever, whether express, implied, or statutory, including, but not limited to, any warranty of merchantability or fitness for a particular purpose or any warranty that the contents of the item will be error-free.
In no respect shall Antoine Aflalo incur any liability for any damages, including, but limited to, direct, indirect, special, or consequential damages arising out of, resulting from, or any way connected to the use of the item, whether or not based upon warranty, contract, tort, or otherwise; whether or not injury was sustained by persons or property or otherwise; and whether or not loss was sustained from, or arose out of, the results of, the item, or any services that may be provided by Antoine Aflalo.
Compile
If you prefer to build it yourself, you can follow the guide provided in the GitHub repository. After compiling you can use FPM to build the package. fpm repository
fpm -s dir -t deb -n doh-server --config-files /etc/dns-over-https/doh-server.conf -v 2.0.1 \ --deb-systemd systemd/doh-server.service \ doh-server/doh-server=/usr/local/bin/ \ doh-server/doh-server.conf=/etc/dns-over-https/
Install
If you compile it yourself, you won’t need to do this, the make install
will have already taken care of it.
sudo dpkg -i doh-server_*_amd64.deb
This will install and start the service for you.
Configuration
Open the file /etc/dns-over-https/doh-server.conf
in your favorite editor. Keep somewhere the listen IP/Port. We’ll need it when we’ll setup Nginx.
Change upstream
variable.
# HTTP listen port listen = [ "127.0.0.1:8053", "[::1]:8053", ] # TLS certification file # If left empty, plain-text HTTP will be used. # You are recommended to leave empty and to use a server load balancer (e.g. # Caddy, Nginx) and set up TLS there, because this program does not do OCSP # Stapling, which is necessary for client bootstrapping in a network # environment with completely no traditional DNS service. cert = "" # TLS private key file key = "" # HTTP path for resolve application path = "/dns-query" # Upstream DNS resolver # If multiple servers are specified, a random one will be chosen each time. upstream = [ "127.0.0.1:53", ] # Upstream timeout timeout = 60 # Number of tries if upstream DNS fails tries = 10 # Only use TCP for DNS query tcp_only = false # Enable logging verbose = false
This will tell DoH-server to use our dnscrypt-proxy to do its DNS requests.
Once done, restart the service.
sudo systemctl restart doh-server
Nginx
This section focus on installing and configuring Nginx to take care of the HTTPS part of DNS-over-HTTPS. To do this, we configure it as a reverse proxy and use let’s encrypt to generate a certificate.
Install
We add the PPA with TLS 1.3 of Nginx to get the latest stable version with TLS 1.3.
sudo add-apt-repository ppa:ondrej/nginx sudo apt install nginx-full
Configuration
This is an example of a configuration. You need to change the server_name
to the domain you’ll use for DoH. Also check that the uptream server point to doh-server ip and port. If you didn’t change anything in the configuration of doh-server, it’s already configured correctly.
For now, we don’t enable SSL, this will be done after with certbot & let’s encrypt.
upstream dns-backend { server 127.0.0.1:8053; } server { listen 80; server_name dns.example.com; root /var/www/html/dns; access_log /var/log/nginx/dns.access.log; location /dns-query { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_set_header X-NginX-Proxy true; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_redirect off; proxy_set_header X-Forwarded-Proto $scheme; proxy_read_timeout 86400; proxy_pass http://dns-backend/dns-query ; } }
Put the content of the configuratione into /etc/nginx/sites-available/dns-over-https
.
Then do a symlink to the enabled folder. Ask Nginx to check that to configuration works, and reload nginx.
sudo ln -s /etc/nginx/sites-available/dns-over-https /etc/nginx/sites-enabled/dns-over-https sudo nginx -t sudo systemctl reload nginx
And there you go, you have now Nginx that will takes care of serving HTTP request to doh-server.
Stapling
The idea is to make Nginx take care of checking if the certificate is expired and keep that information in cache. This is to avoid doing too many requests on the Certificate Authority (CA) of the certificate. Definition
OCSP stapling, formally known as the TLS Certificate Status Request extension, is an alternative approach to the Online Certificate Status Protocol (OCSP) for checking the revocation status of X.509 digital certificates.[1] It allows the presenter of a certificate to bear the resource cost involved in providing OCSP responses by appending (“stapling”) a time-stamped OCSP response signed by the CA to the initial TLS handshake, eliminating the need for clients to contact the CA.[2][3] (Wikipedia)
Create a new file into /etc/nginx/conf.d/stapling.conf
with the following content:
ssl_stapling on; ssl_stapling_verify on; resolver 127.0.2.1;
This will activate the stapling for all your website hosted with Nginx and using HTTPS.
Feel free to change the resolver
variable. By default I made it use the dnscrypt-proxy we configured, but you can change it to any other DNS server.
Certbot
Certbot is the tool developed by EFF to help you request SSL certificate using let’s encrypt. Not only it will generate a certificate for your domain, it will also configure Nginx for you and take care of renewing the certificate.
Install
Usually the version available in the distribution is a little old. We’re going to use the official PPA.
sudo add-apt-repository ppa:certbot/certbot sudo apt install python-certbot-nginx
Configuration
Certbot provides a variety of ways to obtain SSL certificates, through various plugins. The Nginx plugin will take care of reconfiguring Nginx and reloading the config whenever necessary:
sudo certbot --nginx -d dns.example.com
This runs certbot
with the --nginx
plugin, using -d
to specify the names we’d like the certificate to be valid for.
If this is your first time running certbot
, you will be prompted to enter an email address and agree to the terms of service. After doing so, certbot
will communicate with the Let’s Encrypt server, then run a challenge to verify that you control the domain you’re requesting a certificate for.
If that’s successful, certbot
will ask how you’d like to configure your HTTPS settings.
Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access. ------------------------------------------------------------------------------- 1: No redirect - Make no further changes to the webserver configuration. 2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for new sites, or if you're confident your site works on HTTPS. You can undo this change by editing your web server's configuration. ------------------------------------------------------------------------------- Select the appropriate number [1-2] then [enter] (press 'c' to cancel):
I advise to choose redirect to be sure it use only HTTPS.
SSL Defaults
Certbot comes with “good-enough” SSL defaults, but they haven’t been updated in a while. It keeps support for TLS1.0 which has been deprecated for years. No device should use it anymore. Moreover the chosen cypher list contains weak cyphers. To resolve this issue, I compiled a new configuration file for you to replace the weak defaults of Certbot.
Edit the file /etc/letsencrypt/options-ssl-nginx.conf
and replace its content by this.
# This file contains important security parameters. If you modify this file # manually, Certbot will be unable to automatically provide future security # updates. Instead, Certbot will print and log an error message with a path to # the up-to-date file that you will need to refer to when manually updating # this file. ssl_session_cache shared:le_nginx_SSL:1m; ssl_session_timeout 1440m; ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3; # Enable modern TLS cipher suites ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256'; # The order of cipher suites matters ssl_prefer_server_ciphers on; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
Then reload nginx.
sudo systemctl reload nginx
Renewal
By design, the certificate will expire in 90 days. Certbot will take care of renewing it 30 days before expiry. In the case you want to test the renewal process you can run this command.
If you remove the --dry-run
, you’ll actively ask Certbot to renew the certificate.
sudo certbot renew --dry-run
Conclusion
Congratulation you have now a DNS-over-HTTPS server running that can accept request at https://dns.example.com/dns-query
.
This conclude the first part of the guide. The second convers the differents clients available, like dnscrypt-proxy (windows/linux) and Intra (Android). And the third one how to make this DoH block advertising.
Original Post by : aaflalo.me
Leave a Reply