Update: DNSCrypt Server On Raspberry Pi B 2017-11-22
A half year ago when I wrote this it seemed to work well enough on a PC running Debian Jessie, but recently I setup a DNSCrypt server on a Raspberry Pi B and as I followed my own instructions there were a couple things that didn't fit quite right. So I have fairly heavily modified these instructions to fit my rpi install, but the information should be still quite useful for someone installing on plain old Jessie too.
Host A DNSCrypt Server On Jessie 2017-04-02
If you are planning to run your own DNSCrypt server because you are concerned about mass surveillance such as PRISM, then your DNSCrypt server will have to be public, or you are wasting your time. Having your own DNSCrypt server can't hide your DNS queries entirely (recursive lookups are in clear text), it can only help to blend your queries in with everyone else on the same server. Having said that, it might be educational to look through the process to learn more about how DNSCrypt servers are built and how they function.
I should also note that these instructions are [mostly] intended to be used when logged in as root. These instructions make your device act as a server and nobody should be fucking with a browser, downloading scripts/software, or running shit that has not already been examined on a server. Especially a server with any kind of public facing service. Anyone who still thinks these instructions should use sudo or su may leave now because I don't care.
Okay, if you're reading this you hopefully know enough about DNS that you don't need an explanation. So let's jump right in to the instructions. I started by using Raspbian Jessie mostly because the two attempts I made at upgrading [a PC] to Stretch were pretty miserable (and I have little/no patience). A fresh install may have been better, but if the upgrade is going to go that poorly, just don't offer it. I got my Raspbian Jessie Lite image from here, the last Jessie build offered in Raspbian. There's no need to use the full sized install, it is pretty bloated. You can use whatever distro you like of course, which may have slightly different applications installed by default. There are lots of instructions on how to write rpi images to [micro]SD cards, choose one that suits your needs.
Step 1: Startup
Boot the Raspbian image which should resize the partition automatically for you and reboot. When it comes back up, log in as "pi" with the default password "raspberry", then run:
to set a new password on the pi account. Then run:
$ sudo systemctl enable ssh
$ sudo reboot
You could also "sudo systemctl start ssh" to get it going, but I am a big fan of overkill and if you can't wait the 30 seconds it takes to reboot a fresh rpi, then running a DNSCrypt server may not be for you.
Step 2: Setup root Login Via SSH
Go to another PC, SSH in to your DNSCrypt server as pi, and run:
$ sudo passwd root
Which will of course confirm that SSH was properly enabled and will set the root password. If you really want to you can change "without-password" to "yes" in your /etc/ssh/sshd_config to let root log in by password but it might be a better idea to use a key to authenticate your logins. Create a /root/.ssh/authorized_keys file and add your key to it. Now logoff and SSH back in as root to make sure your key (or password) is working.
Step 3: Prepare Your OS First
Just get these out of the way first. It'll help to reduce the errors that get barfed up by subsequent commands.
# dpkg-reconfigure tzdata
# dpkg-reconfigure locales
Yes, wait the 30 seconds for the reboot, it won't kill you and it'll make the following apt-get commands happier.
# apt-get update
# apt-get install dnsutils automake libtool
# apt-get purge avahi-daemon alsa-utils bluez bluez-firmware cifs-utils lua5.1 luajit
# apt-get purge samba-common v4l-utils wireless-regdb wireless-tools
# apt-get autoremove --purge
# apt-get upgrade
Step 4: Setup Unbound As Your Recursive Resolver
Now that you have dumped a few unnecessary applications and prepared your OS, it is time to start putting some useful software on this thing:
# apt-get install unbound
# nano /etc/unbound/unbound.conf
Your unbound.conf should look pretty boring, just add these lines at the end:
access-control: 127.0.0.1 allow
Then download the current root-hints, restart unbound, and make sure it works:
# wget -O /etc/unbound/named.cache ftp://ftp.internic.net/domain/named.cache
# systemctl restart unbound
# nslookup snork.ca 127.0.0.1
That should give you the IP address of snork.ca, if it doesn't you might want to check to make sure you do not have an install of another DNS server already using port 53. Now that you have unbound resolving for you, move on to dnscrypt-wrapper.
Step 5: DNSCrypt And Dependencies
On a raspberry Pi these builds can take a while, be prepared to have a couple short naps along the way here. You could opt to pump all these commands in to a script or something but it is kind of a good idea to run them one at a time to make sure you haven't screwed anything up along the way.
# mkdir ~/src && cd ~/src
# wget -O libevent-wrapper-master.zip https://github.com/libevent/libevent/archive/master.zip
# wget -O libsodium-latest.tar.gz https://download.libsodium.org/libsodium/releases/LATEST.tar.gz
# wget -O dnscrypt-wrapper-master.zip https://github.com/cofyc/dnscrypt-wrapper/archive/master.zip
# unzip libevent-wrapper-master.zip
# tar xzf libsodium-latest.tar.gz
# unzip dnscrypt-wrapper-master.zip
# cd libevent-master
# make install
# cd ../libsodium-stable/
# make install
# cd ../dnscrypt-wrapper-master
# make configure
# make install
If you are getting a barf on dnscrypt-wrapper, I bet you missed running ldconfig after you built libsodium.
Step 6: Keys And Connecting
At this point you have all the required software, but you'll of course still need to setup keys.
# mkdir /etc/dnscrypt && cd /etc/dnscrypt
# dnscrypt-wrapper --gen-provider-keypair
# dnscrypt-wrapper --show-provider-publickey --provider-publickey-file public.key > public.asc
# dnscrypt-wrapper --gen-crypt-keypair --crypt-secretkey-file=1.key
# dnscrypt-wrapper --gen-cert-file --crypt-secretkey-file=1.key --provider-cert-file=1.cert --provider-publickey-file=public.key --provider-secretkey-file=secret.key --cert-file-expire-days=1
# dnscrypt-wrapper --resolver-address=127.0.0.1:53 --listen-address=YOURIP:5353 --provider-name=2.dnscrypt-cert.FANCYNAME --crypt-secretkey-file=/etc/dnscrypt/1.key --provider-cert-file=/etc/dnscrypt/1.cert &
In the commands above it is important to note that:
- public.asc is a text file that shows your provider-key. If you are going to make your server public you'll need to provide this in the public-resolvers.csv file.
- 127.0.0.1:53 is telling the wrapper to use your Unbound installation as its upstream provider. This means you are not using Google or your ISP as a resolver, your server will be doing fully recursive lookups.
- YOURIP is the IP address of your rpi (or whatever you're doing this on). The wrapper will bind to that IP address and port. If this IP address is a private address such as 192.168.1.66 then you'll have to forward a port to it through your router.
- FANCYNAME is a name for your server. It can be any name, but it must start with 2.dnscrypt-cert.
At this point you should have a working dnscrypt'ed server that is ready to take on your queries. To test it you'll want to grab the dnscrypt-proxy and use it from a client to do some queries. I used a Windows [XP] box to test mine, but the idea is generally the same on whatever OS you're using. Since your resolver is not listed in dnscrypt's public list, you'll have to connect to it like this:
> dnscrypt-proxy --local-address=127.0.0.1:53 --resolver-address=YOURSERVER:5353 --provider-name=2.dnscrypt-cert.FANCYNAME --provider-key=1111:2222:3333:4444:5555:6666:7777:8888:9999:0000:AAAA:BBBB:CCCC:DDDD:EEEE:FFFF
Here, when connecting with the proxy, it is important to note that:
- 127.0.0.1 means the PC you are running the proxy on.
- YOURSERVER is the IP address of the server you just setup.
- FANCYNAME has to be the same as the name you made up above.
- provider-key is the fingerprint you should find on the server in public.asc from the key generation above
You should see some information that tells you about your dnscrypt'ed connection to your server and you should now be able to open another command prompt and use nslookup to test a few queries:
nslookup snork.ca 127.0.0.1
Now, to make sure that you really are going through the proxy and wrapper, you should kill the wrapper process on the server and try your nslookups again on your test proxy machine.
# killall -v dnscrypt-wrapper
If the queries now fail, then you know the wrapper is being used for them.
Step 7: Key Rotation
If you haven't read it yet you should really look at the key rotation section of the wrapper install. In the commands above, when you created your initial query key/cert, they were set to expire after one day. Set them any longer and the proxy will barf up an error message when it connects to your server. It won't stop it from working, it'll just barf up the error message which looks bad. If you are planning to be the only one using this server, you can ignore the error message, but if you want to get rid of the error message (and you should), you'll need a script that generates new keys and kills/starts wrappers to use the new keys. Then you'll have to cron the script to run a few times daily. The guy who runs dnscrypt.pl has this post explaining a bit more about the error message, and how he setup his key rotation... but I kind of went my own way.
Have a look at my script.
If you followed my instructions pretty closely you can probably use the script with only a few modifications, see the comments at the top of the script for instructions. The idea of the script (if you didn't read the info at the link above) is that it will create a new set of keys and temporarily run two instances of the wrapper. Then after an hour it kills off the old wrapper and its keys, leaving only the new key set. The next time it runs it does the same thing except it will switch from 2.key and 2.cert back to 1.key and 1.cert. This basically allows time for any connected clients to update to the new key before dropping the old one. To use the script you'll need to give it execute permissions (after modifying the variables at the top):
# chmod +x /etc/dnscrypt/keyrotate.sh
I added the script to my crontab to run every four hours, I guess you could choose any schedule that suits your needs. As long as it rotates at least once a day it'll make dnscrypt-proxy clients happy.
# crontab -e 15 1,7,13,19 * * * /etc/dnscrypt/keyrotate.sh
Step 8: Make Your Server Public
Seriously, if anyone has the ability to record your DNS queries when you use your ISP's DNS servers, then they have the digital intelligence to figure out where your DNSCrypt server is, and will know that all DNS traffic is yours anyways. Using a dnscrypt'ed server is really only effective if you have numerous clients making queries to it, because even if the upstream queries are recorded, the person recording them doesn't know which client (behind the DNSCrypt server) is doing the requesting.
Some might agrue that [on a heavily used public DNSCrypt server] it might be possible to trap the outbound queries from it, as well as the traffic from your PC/network/VPN and be able to piece together who is making which queries. In all reality, that is kind of a stretch, because it doesn't take in to account the fact that many queries would be cached and would never have to go upstream. It would also be hard to essentially trap every bit of Internet traffic continuously in order to compare the packet times against. Don't get me wrong, if someone could trap just your traffic and the outbound traffic from your DNSCrypt provider, then maybe they could piece together which queries are yours, but that is a lot of trouble to go to for DNS queries, and if someone was that interested in your traffic, they'd be doing a lot more than just some DNS query sniffing.