An extra layer of privacy: setting up a private, in-tunnel DNS-over-TLS proxy for your OpenVPN clients
As concerns over privacy and government surveillance become more and more relevant, the use of VPNs have become increasingly popular. While VPN software such as OpenVPN encrypts and protects "first-hop" client traffic from the prying eyes of ISPs and the increasingly widespread use of HTTPS protects interception and/or eavesdropping of "last-hop" server-to-server web traffic, the venerable DNS protocol has been slow to follow suit from a security standpoint, until recently. With the advent of DNS-over-TLS, one can now make DNS queries with a level of security and encryption analogous to that of HTTPS, more or less eliminating the possibility that a third party (i.e. your VPN provider or VPS host on which you run your own VPN) can intercept, monitor, or manipulate DNS traffic.
In this how-to, I'll walk through how to install the latest version of the Unbound DNS server (1.8.2 at the time of this writing) on Ubuntu 18.04, configure it as a forwarder to Cloudflare and Quad9 DNS, and configure your OpenVPN server to push the DNS server to clients. It is assumed that you already have a functioning OpenVPN server in place. If not, Digital Ocean provides an excellent tutorial on setting one up.
I know what you're thinking - let's just apt-get unbound and call it a day. Unfortunately, the version of Unbound in the Ubuntu 18.04 repos is 1.6.7, way too old to support some of the directives in the Unbound configuration below. So we'll have to download and compile from source. Visit https://nlnetlabs.nl/projects/unbound/download/ and download the latest source tarball, untar, and run ./configure
, make
, and make install
as root. Note that you'll need the libssl-dev
package installed first, as Unbound links against the OpenSSL library. Assuming you didn't change the installation location from the default, the Unbound binaries and configurations should all be under /usr/local
.
If you don't have the ca-certificates
package from the Ubuntu repos installed, now would be a good time to do so. Modify the unbound.conf
file so that it contains the following:
/usr/local/etc/unbound/unbound.conf
server:
interface: 0.0.0.0
interface: ::0
tls-cert-bundle: /etc/ssl/certs/ca-certificates.crt
prefetch: yes
verbosity: 1
access-control: 0.0.0.0/0 refuse
access-control: 127.0.0.0/8 allow
access-control: 10.0.0.0/8 allow
forward-zone:
name: "."
forward-tls-upstream: yes
# Cloudflare DNS
forward-addr: 2606:4700:4700::1111@853#cloudflare-dns.com
forward-addr: 1.1.1.1@853#cloudflare-dns.com
forward-addr: 2606:4700:4700::1001@853#cloudflare-dns.com
forward-addr: 1.0.0.1@853#cloudflare-dns.com
# Quad9
forward-addr: 2620:fe::fe@853#dns.quad9.net
forward-addr: 9.9.9.9@853#dns.quad9.net
forward-addr: 2620:fe::9@853#dns.quad9.net
forward-addr: 149.112.112.112@853#dns.quad9.net
This provides a basic but secure configuration of Unbound that tells it to listen on all interfaces (but limit access to localhost and the OpenVPN subnet), verify TLS certificates, and forward all DNS requests upstream to Cloudflare and/or Quad9 via DNS-over-TLS.
You'll also probably want to have Unbound start on boot as a service:
/etc/systemd/system/unbound.service
[Unit]
Description=Unbound DNS server
After=network.target
Before=nss-lookup.target
Wants=nss-lookup.target
[Service]
Environment="LD_LIBRARY_PATH=/usr/local/lib"
Type=simple
Restart=on-failure
ExecStartPre=-/usr/local/sbin/unbound-anchor -a /usr/local/etc/unbound/root.key -v
ExecStart=/usr/local/sbin/unbound -d
ExecReload=/usr/local/sbin/unbound-control reload
PIDFile=/usr/local/etc/unbound/unbound.pid
[Install]
WantedBy=multi-user.target
Once your service file is created, run systemctl daemon-reload
to refresh your systemd and have it pick up the new service you just created, followed by systemctl enable unbound
to have it start on boot and systemctl start unbound
to start the service now. If everything is configured correctly, systemctl status unbound
should show something like the following:
root@server:~# systemctl status unbound
● unbound.service - Unbound DNS server
Loaded: loaded (/etc/systemd/system/unbound.service; enabled; vendor preset: enabled)
Active: active (running) since Tue 2018-12-11 11:00:17 CST; 1 day 11h ago
Process: 23369 ExecStartPre=/usr/local/sbin/unbound-anchor -a /usr/local/etc/unbound/root.key -v (code=exited, status=0/SUCCESS)
Main PID: 23381 (unbound)
Tasks: 1 (limit: 2320)
CGroup: /system.slice/unbound.service
└─23381 /usr/local/sbin/unbound -d
Dec 11 11:00:15 server systemd[1]: Starting Unbound DNS server...
Dec 11 11:00:17 server unbound-anchor[23369]: /usr/local/etc/unbound/root.key has content
Dec 11 11:00:17 server unbound-anchor[23369]: success: the anchor is ok
Dec 11 11:00:17 server systemd[1]: Started Unbound DNS server.
Dec 11 11:00:17 server unbound[23381]: [23381:0] notice: init module 0: validator
Dec 11 11:00:17 server unbound[23381]: [23381:0] notice: init module 1: iterator
Dec 11 11:00:17 server unbound[23381]: [23381:0] info: start of service (unbound 1.8.2).
If you have a firewall running, e.g. iptables, or ufw, make sure to allow access to Unbound on port 53 from your OpenVPN subnet.
Finally, we need to update the OpenVPN server configuration to use our shiny new Unbound DNS server. Open up /etc/openvpn/server.conf
(or wherever your OpenVPN config is stored), and add the line push "dhcp-option DNS 10.8.0.1"
(or whatever the local gateway IP of your OpenVPN server is). If you have any existing DNS servers configured to be pushed to the client, remove these to ensure that the client will only use your Unbound DNS server.
If you're running OpenVPN version 2.3.9 or newer, it's highly recommended to push "block-outside-dns"
as well to prevent DNS leaks.
If OpenVPN has been configured correctly, you should be able to your new DNS server in action on your client.
Enjoy your extra-secure, extra-private VPN!