If you have a Pi-hole installation in your home network and want to use it on your phone or other devices when you’re out of home, using a VPN is the recommended solution by PiHole Team. You can install OpenVPN in your Raspberry Pi using something like PiVPN, connect your phone to it and use your DNS securely across the world.
I don’t like this setup, keeping a VPN alive on my phone does not seem ideal. In this tutorial, I’ll show another way to use PiHole on your Android Phone by relying on the Private DNS Feature.
Private DNS
If you go to your phone settings, Network and Internet, you’ll see a Private DNS section. Private DNS is the name that Android gives for DNS over TLS (DOT), a type of DNS server that allows you querying DNS using a secure connection. There are may around, and we’ll build our own using Nginx and Pihole. In Android, you have 3 options:
- Off
- Automatic (Using Google DOT service)
- Private DNS provider hostname
For this tutorial, we’ll generate this url to input in this field. You’ll need:
- A domain name (like
brenoflavio.com.br
) - A static ip that points to your router (some ISPs does not give that to you)
- Ability to do port forwarding in your router
Setting up
First of all, we’ll need to install Nginx in your Pihole. Assuming that you are using Raspbian, you can do that by running:
sudo apt install nginx
lighttpd
If you installed Pihole web interface using lighttpd
, nginx will conflict with it because both will listen to the port 80.
In this case you can forward port 80 in nginx to lighttpd
. Go to its config folder and edit the config file:
cd /etc/lighttpd/
sudo nano lighttpd.conf
Change
server.port = 80
To
server.port = 8080
Save, close and restart lighttpd
and nginx
:
sudo service lighttpd restart
sudo service nginx restart
router
In your router, you’ll need to open some ports to generate the certificate and listen to DNS queries. Each router is different, but you’ll want to open:
- Port 80 poiting to your nginx ip
- Port 443 poiting to your nginx ip
- Port 853 poingint to your nginx ip
domain
Once your ports are open, go to your domain provider and point your domain to your public IP. You want something like:
mydomain.example.com A <your public ipv4>
If everyting worked correctly, you’ll be able to access Nginx in your browser by going to:
http://<your public ip>
certificate
Again each setup can have its certificate generated differently. On mine for example I have another NGINX to mange port 80 and I copy the certificate from there to my raspberry pi. If you want to generate the cert in your Pi directly, you can use certbot for that. I’ll leave certbot documentation here:
https://certbot.eff.org/instructions?ws=nginx&os=debianbuster
Basically you want to install certbot and run its command to get a certificate for your domain configured above.
nginx
Now we can configure Nginx. Go to its folder and edit the configuration file:
cd /etc/nginx/
sudo nano nginx.conf
In the end of this file, you want to add something like this:
stream {
# DNS upstream pool
upstream dns {
zone dns 64k;
server 127.0.0.1:53; # If NGINX is running in another machine, change this
}
# DoT server for decryption
server {
listen 853 ssl;
ssl_certificate /etc/letsencrypt/live/<mydomain.example.com>/fullchain.pem; # Change to your certificate location
ssl_certificate_key /etc/letsencrypt/live/<mydomain.example.com>/privkey.pem; # Change to your certificate location
proxy_pass dns;
}
}
If you want to keep accessing Pihole Web Interface on port 80, you can do that by changing the default site location:
sudo nano sites-enabled/default
Inside it, there is a location to the /
path in the port 80
. Change it to be:
location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
# try_files $uri $uri/ =404;
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
proxy_set_header Connection keep-alive;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
Notice that this will open you Pihole web interface to the internet if you opened port 80 and pointed to your Pihole installation before, which is not secure, so you might want to skip this.
testing
You can test your solution by running:
kdig @<dot_server> +tls-host=<tls_hostname> <domain_name>
For example:
kdig @mydomain.example.com +tls-host=mydomain.example.com google.com
And that’s it! Go to your Private DNS settings and set the private dns as your domain. In Pihole, your phone queries will show
as localhost
(or the hostname of your nginx installation)