Introduction
One of the easiest ways to enhance your online privacy is to encrypt your DNS traffic. I believe that the best solution for a privacy minded individual user is DNS-Over-HTTPS (DOH), which is currently undergoing standardization by the IETF as RFC 8484. If you are like me and want the most privacy possible, you want your own DOH server. I believe that the best way to do this currently is an nginx module that can process DOH requests by extracting the DNS queries from the HTTP requests, passing the queries to a DNS resolver, and placing the DNS answers into the HTTP response. I believe this is currently the best approach because it allows DOH to be seamlessly integrated into an existing web server running nginx, making the DOH traffic less distinguishable from other HTTPS traffic. Fortunately, I have written an nginx module to do precisely this, and this blog post will guide you through the installation, configuration, and testing of your own nginx based DOH server. For this post, I assume you have a basic knowledge of the Linux command line, nginx, and DNS. I also assume you have a server with nginx and a DNS resolver like BIND, systemd-resolved, or unbound installed.
Installing The Module
The first step is to actually build the module, which can be found here: https://github.com/themagister/Nginx-DOH-Module. Place at least the config and ngx_http_doh_module.c into a directory of your choice, which will be referred to as <module-directory>. Next, obtain the source code of the nginx version you plan to use from here: https://nginx.org/en/download.html, and extract it into another directory, which will be referred to as <nginx-directory>. Now, on the system you wish to make into your DOH server, run the following command:
$ nginx -V
What you are interested in are the arguments that your version of nginx was built with. They are listed on the line that begins with the phrase “configure arguments: “. Copy these, they will be referred to as <arguments>. Next, change to your <nginx-directory> and run the following:
$ ./configure <arguments> --add-dynamic-module=<module-directory>
$ make -jN > /dev/null
where N is your CPU’s number of threads. The module will then be located at <nginx-directory>/objs/ngx_http_doh_module.so. Change the module’s ownership to root and move it to a directory like /etc/nginx or /etc/nginx/modules and add the following line to your nginx.conf file near the top and outside of any blocks:
load_module <your-module-location>/ngx_http_doh_module.so;
Module Configuration
The module only takes 4 directives, listed below:
doh;
doh_address <address_of_upstream_resolver>;
doh_port <upstream_resolver_listening_port>;
doh_timeout <connection_timeout_in_seconds>;
The directives MUST be placed within a location block. The doh directive is required while the rest are optional. The defaults are the following if they are not specified:
doh_address 127.0.0.1;
doh_port 53;
doh_timeout 5;
Applying Your Setup
The easiest way to test that your setup is working is to use curl with DOH like so:
$ curl -v --doh-url https://<your_server>.<your_domain>/<module_location> <website>
With the -v option curl will output the details of the DOH transaction so you can verify that your server is working as intended. The easiest way to use your server to protect your day-to-day web browsing is use Mozilla’s Firefox browser and set it up to use your server by: clicking the hamburger menu in the top right corner -> clicking Settings -> scrolling down to the Network Settings section and clicking the Settings button there – > clicking the Enable DNS over HTTPS button, selecting a Custom provider, and entering the same URL you used for the curl test above. You can verify that this is working by visiting dnsleaktest.com and running the test. If your server is the only one listed then everything is working as intended.