You want to have your own ad-blocking DNS server but you're often going outside or you don't have wifi in your house but you have an unused domain and just signed up for aws free tier? Follow this tutorial to get pihole running on any cloud provider with DNS over TLS and DNS over HTTPS, while restricting port 53 so you have less risk for your server becoming an open resolver. Let's get going!
- Make sure you have port 80, 443, and 853 opened in your firewall settings, and login to your server via ssh.
- Install nginx:
apt install nginx
- Create a file on
/etc/nginx/conf.d/example.conf
with following contents:
server {
server_name example.com;
listen 80;
# only add the line below if you have public ipv6 in your server
listen [::]:80;
root /var/www/html;
}
- Reload nginx:
systemctl reload nginx
- Install python venv:
apt install python3-venv
- Create certbot venv:
python3 -m venv /opt/certbot
- Update pip:
/opt/certbot/bin/pip install --upgrade pip
- Install certbot and it's nginx plugin:
/opt/certbot/bin/pip install certbot certbot-nginx
- Issue tls certificate:
/opt/certbot/bin/certbot --nginx -d example.com
- Install pihole:
curl -sSL https://install.pi-hole.net | bash
and store pihole admin password in a safe place - Create directory for nginx javascript module:
mkdir /etc/nginx/njs.d
- Download dns.js and libdns.js and store them in /etc/nginx/njs.d
- Since we have nginx, we'll make sure to use that for web interface too. Install php-fpm:
apt install php-fpm
- Edit your domain's config file as follows:
server {
server_name example.com;
root /var/www/html/admin;
index index.php;
location ~\.php$ {
fastcgi_pass unix:/run/php/php-fpm.sock;
include snippets/fastcgi-php.conf;
}
location /dns-query {
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_pass http://localhost:8053;
}
listen 443 ssl http2;
listen [::]:443 ssl http2;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
}
server {
if ($host = example.com) {
return 301 https://$host$request_uri;
}
server_name example.com;
listen 80;
return 404; # managed by Certbot
}
- Open
/etc/nginx/snippets/fastcgi-php.conf
in your editor and insertfastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
at the end of the file. - In the nginx.conf file, after the http block, insert a stream block as follows:
stream {
js_import /etc/nginx/njs.d/dns.js;
server {
listen localhost:8053;
js_filter dns.filter_doh_request;
proxy_pass 127.0.0.1:53;
}
server {
listen 853 ssl;
listen [::]:853 ssl;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
proxy_pass 127.0.0.1:53;
}
}
- Try checking the changed configuration with
nginx -t
. Unknown directive "stream?"apt install libnginx-mod-stream
. Unknown directive "js_import?"apt install libnginx-mod-stream-js
. Finally, reload nginx:systemctl reload nginx
and disable lighttpd since we're not using it:systemctl disable --now lighttpd
- On your android 9+ device, locate the private dns setting, select hostname option, type your domain, and click ok
- On your browser, locate dns over https setting, and type
https://example.com/dns-query
on provider url field - To check pihole's status, open example.com in your browser.
- Enjoy the power of extension-less adblocking!