LXC TOR + Pihole + Unbound + DNSSEC - Anonymous Recursive Secure DNS

For all of the following, you can clear cache and restore internet fairly simply by running deploy1.sh (see latest version)

I recommend a naming scheme e.g. ‘deploy41.sh’ for version 4.1 so you can hotswap between this and other deploys.

sudo ./deploy1.sh

Please note: Your browser MUST support SNI to pass SNI test!

Version 4.0 is EXPERIMENTAL

Working towards no more Cloudflare :smiley:

#!/bin/bash
set -e

echo "[+] Updating system..."
apt update && apt upgrade -y

echo "[+] Installing dependencies..."
apt install -y curl unbound tor iptables-persistent

echo "[+] Configuring Unbound for DNS over Tor..."
cat > /etc/unbound/unbound.conf <<EOL
server:
    interface: 127.0.0.1
    port: 5335
    do-ip4: yes
    do-udp: yes
    do-tcp: yes
    hide-identity: yes
    hide-version: yes
    do-not-query-localhost: no
    harden-glue: yes
    harden-dnssec-stripped: yes
    harden-large-queries: yes
    harden-referral-path: yes
    harden-short-bufsize: yes
    harden-algo-downgrade: yes
    harden-below-nxdomain: yes
    use-caps-for-id: no
    aggressive-nsec: yes
    qname-minimisation: yes
    val-clean-additional: yes
    prefetch: yes
    prefetch-key: yes
    so-rcvbuf: 8m            
    so-sndbuf: 8m
    num-threads: 4
    target-fetch-policy: "5 5 0 0 0"
    val-permissive-mode: no
    cache-min-ttl: 5
    cache-max-ttl: 86401
    serve-expired: no
    rrset-roundrobin: yes
    val-clean-additional: yes
    tls-cert-bundle: /etc/ssl/certs/ca-certificates.crt
    tls-use-sni: yes  

    # Cached Queries: Encrypt local queries over DoT
    forward-zone:
        name: "."
        forward-tls-upstream: yes
        forward-addr: 127.0.0.1@853  # Local encryption for cached queries

    # Uncached Queries: Use an anonymous resolver inside Tor
    forward-zone:
        name: "."
        forward-addr: 127.0.0.1@9053  # Tor Hidden Service DNS resolver
        forward-addr: ::1@9053
EOL

echo "[+] Configuring Tor for Anonymous DNS Resolution..."
cat > /etc/tor/torrc <<EOL
SocksPort 9050
DNSPort 9053
AutomapHostsOnResolve 1
VirtualAddrNetworkIPv4 10.192.0.0/10
AutomapHostsSuffixes .onion,.exit

# Use a trusted DNS resolver inside Tor instead of Cloudflare
ClientDNSRejectInternalAddresses 1
ClientUseIPv6 1
ClientPreferIPv6ORPort 1
EOL

echo "[+] Restarting Tor and Unbound..."
systemctl restart tor unbound

echo "[+] Setting up permanent iptables rules for DNS..."
iptables -t nat -A OUTPUT -p udp --dport 53 -j REDIRECT --to-ports 5335
iptables -t nat -A OUTPUT -p tcp --dport 53 -j REDIRECT --to-ports 5335

echo "[+] Saving iptables rules..."
iptables-save > /etc/iptables/rules.v4
netfilter-persistent save
netfilter-persistent reload

echo "[+] Your DNS queries are now fully anonymous:"
echo "    - Uncached queries go through a Tor hidden service DNS."
echo "    - Cached queries are encrypted locally to prevent snooping."

sleep 5

reboot


Version 4.1 is EXPERIMENTAL

#!/bin/bash
set -e

echo "[+] Updating system..."
apt update && apt upgrade -y

echo "[+] Installing dependencies..."
apt install -y curl unbound tor iptables-persistent

echo "[+] Configuring Unbound for DNS over Tor with .onion Resolvers..."
cat > /etc/unbound/unbound.conf <<EOL
server:
    interface: 127.0.0.1
    port: 5335
    do-ip4: yes
    do-udp: yes
    do-tcp: yes
    hide-identity: yes
    hide-version: yes
    do-not-query-localhost: no
    harden-glue: yes
    harden-dnssec-stripped: yes
    harden-large-queries: yes
    harden-referral-path: yes
    harden-short-bufsize: yes
    harden-algo-downgrade: yes
    harden-below-nxdomain: yes
    use-caps-for-id: no
    aggressive-nsec: yes
    qname-minimisation: yes
    val-clean-additional: yes
    prefetch: yes
    prefetch-key: yes
    so-rcvbuf: 8m            
    so-sndbuf: 8m
    num-threads: 4
    target-fetch-policy: "5 5 0 0 0"
    val-permissive-mode: no
    cache-min-ttl: 5
    cache-max-ttl: 86401
    serve-expired: no
    rrset-roundrobin: yes
    val-clean-additional: yes
    tls-cert-bundle: /etc/ssl/certs/ca-certificates.crt
    tls-use-sni: yes  

    # Cached Queries: Encrypt using local DNS-over-TLS
    forward-zone:
        name: "."
        forward-tls-upstream: yes
        forward-addr: 127.0.0.1@853  # Local encryption for cached queries

    # Uncached Queries: Route through Tor Hidden Service resolvers
    forward-zone:
        name: "."
        forward-addr: 127.0.0.1@9053
        forward-addr: ::1@9053
        # Privacy-respecting .onion resolvers (replace with valid ones)
        forward-addr: 1234567890abcdef.onion@53
        forward-addr: abcdef1234567890.onion@53
EOL

echo "[+] Configuring Tor for Anonymous DNS Resolution with .onion Resolvers..."
cat > /etc/tor/torrc <<EOL
SocksPort 9050
DNSPort 9053
AutomapHostsOnResolve 1
VirtualAddrNetworkIPv4 10.192.0.0/10
AutomapHostsSuffixes .onion,.exit

# Use a trusted DNS resolver inside Tor instead of Cloudflare
ClientDNSRejectInternalAddresses 1
ClientUseIPv6 1
ClientPreferIPv6ORPort 1

# Map some commonly used public DNS providers to .onion resolvers
MapAddress 9.9.9.9 10.192.0.1  # Quad9
MapAddress 94.140.14.14 10.192.0.2  # AdGuard
MapAddress 77.88.8.8 10.192.0.3  # Yandex
EOL

echo "[+] Restarting Tor and Unbound..."
systemctl restart tor unbound

echo "[+] Setting up permanent iptables rules for DNS..."
iptables -t nat -A OUTPUT -p udp --dport 53 -j REDIRECT --to-ports 5335
iptables -t nat -A OUTPUT -p tcp --dport 53 -j REDIRECT --to-ports 5335

echo "[+] Saving iptables rules..."
iptables-save > /etc/iptables/rules.v4
netfilter-persistent save
netfilter-persistent reload

echo "[+] Your DNS queries are now fully anonymous:"
echo "    - Uncached queries go through privacy-focused .onion resolvers inside Tor."
echo "    - Cached queries are encrypted locally to prevent network snooping."

sleep 5

reboot


Version 3.0 is EXPERIMENTAL:

#!/bin/bash
set -e

echo "[+] Updating system and installing dependencies..."
apt update && apt upgrade -y
apt install -y curl unbound tor iptables-persistent dnsutils

echo "[+] Configuring Unbound for DNS over TLS with ECH support..."
cat > /etc/unbound/unbound.conf <<EOL
server:
    verbosity: 1                    # Increase logging for debugging
    interface: 127.0.0.1
    port: 5335
    do-ip4: yes
    do-ip6: yes
    do-udp: yes
    do-tcp: yes
    tls-use-sni: yes               # Enable SNI handling for ECH
    hide-identity: yes
    hide-version: yes
    do-not-query-localhost: no
    harden-glue: yes
    harden-dnssec-stripped: yes
    harden-large-queries: yes
    harden-referral-path: yes
    harden-short-bufsize: yes
    harden-algo-downgrade: yes
    harden-below-nxdomain: yes
    use-caps-for-id: no
    aggressive-nsec: yes
    qname-minimisation: yes
    prefetch: yes
    prefetch-key: yes
    so-rcvbuf: 4m            
    so-sndbuf: 4m
    num-threads: $(nproc)
    cache-min-ttl: 3600
    cache-max-ttl: 86400
    tls-cert-bundle: /etc/ssl/certs/ca-certificates.crt

forward-zone:
    name: "."
    forward-tls-upstream: yes      # Enable DNS over TLS for upstream
    forward-addr: 1.1.1.1@853      # Cloudflare DoT with ECH
    forward-addr: 1.0.0.1@853
    forward-addr: 2606:4700:4700::1111@853
    forward-addr: 2606:4700:4700::1001@853

remote-control:
    control-enable: no
EOL

echo "[+] Configuring Tor for SOCKS proxy and DNS..."
cat > /etc/tor/torrc <<EOL
SocksPort 9050
DNSPort 9053
AutomapHostsOnResolve 1
VirtualAddrNetworkIPv4 10.192.0.0/10
VirtualAddrNetworkIPv6 [fc00::/8]
AutomapHostsSuffixes .onion

ExitNodes {us},{de},{nl} StrictNodes 0
AvoidDiskWrites 1
HardwareAccel 1
TransPort 9040
TransListenAddress 127.0.0.1
EOL

echo "[+] Setting Tor as a systemd service..."
systemctl enable tor
systemctl restart tor

echo "[+] Configuring Unbound to route through Tor..."
cat > /etc/unbound/unbound.conf.d/tor.conf <<EOL
server:
    do-not-query-localhost: no

forward-zone:
    name: "."
    forward-tls-upstream: yes
    forward-addr: 127.0.0.1@9050   # Route via Tor SOCKS5
EOL

echo "[+] Validating Unbound configuration..."
unbound-checkconf || { echo "[-] Unbound config error detected!"; exit 1; }

echo "[+] Restarting Unbound..."
systemctl enable unbound
systemctl restart unbound

echo "[+] Setting up iptables rules..."
iptables -t nat -F  # Flush existing NAT rules to avoid conflicts
iptables -t nat -A OUTPUT -p udp --dport 53 -j REDIRECT --to-ports 5335
iptables -t nat -A OUTPUT -p tcp --dport 53 -j REDIRECT --to-ports 5335
iptables -t nat -A OUTPUT -p tcp --dport 853 -j REDIRECT --to-ports 9040
iptables -t nat -A OUTPUT -p udp --dport 853 -j REDIRECT --to-ports 9040
iptables -t nat -A OUTPUT -d 127.0.0.1 -p udp --dport 53 -j ACCEPT
iptables -t nat -A OUTPUT -d 127.0.0.1 -p tcp --dport 53 -j ACCEPT

echo "[+] Saving iptables rules..."
iptables-save > /etc/iptables/rules.v4
systemctl enable netfilter-persistent
systemctl restart netfilter-persistent

echo "[+] Verifying services..."
sleep 5
if systemctl is-active tor >/dev/null; then
    echo "[+] Tor is running"
else
    echo "[-] Tor failed to start. Check: journalctl -u tor"
    exit 1
fi
if systemctl is-active unbound >/dev/null; then
    echo "[+] Unbound is running"
else
    echo "[-] Unbound failed to start. Check: journalctl -u unbound"
    exit 1
fi

echo "[+] Testing DNS resolution..."
dig_result=$(dig @127.0.0.1 -p 5335 example.com +short)
if [ -n "$dig_result" ]; then
    echo "[+] DNS resolution successful: $dig_result"
else
    echo "[-] DNS resolution failed. Check logs and steps below."
fi

echo "[+] Configuration applied. Debugging steps if needed:"
echo "1. Check Unbound logs: journalctl -u unbound -b"
echo "2. Check Tor logs: journalctl -u tor -b"
echo "3. Test direct resolution: dig @1.1.1.1 -p 853 +tls example.com"
echo "4. Test Tor routing: torsocks dig @1.1.1.1 example.com"
echo "[!] If using Pi-hole, disable DNSSEC and set upstream to 127.0.0.1#5335"
echo "[!] Verify ECH: https://www.cloudflare.com/ssl/encrypted-sni/"

sleep 5

reboot

image
DNS Leak - Cloudflare (non-regional) Prevails over TOR

Version 3.1 Beta

#!/bin/bash
set -e

echo "[+] Updating system..."
apt update && apt upgrade -y

echo "[+] Installing dependencies..."
apt install -y curl unbound tor iptables-persistent

echo "[+] Configuring Unbound for DNS over Tor and Cloudflare..."
cat > /etc/unbound/unbound.conf <<EOL
server:
    interface: 127.0.0.1
    port: 5335
    do-ip4: yes
    do-ip6: yes
    do-udp: yes
    do-tcp: yes
    hide-identity: yes
    hide-version: yes
    do-not-query-localhost: no
    harden-glue: yes
    harden-dnssec-stripped: yes
    harden-large-queries: yes
    harden-referral-path: yes
    harden-short-bufsize: yes
    harden-algo-downgrade: yes
    harden-below-nxdomain: yes
    use-caps-for-id: no
    aggressive-nsec: yes
    qname-minimisation: yes
    val-clean-additional: yes
    prefetch: yes
    prefetch-key: yes
    so-rcvbuf: 8m            
    so-sndbuf: 8m
    num-threads: 4
    target-fetch-policy: "5 5 0 0 0"
    val-permissive-mode: no
    cache-min-ttl: 5
    cache-max-ttl: 86401
    serve-expired: no
    rrset-roundrobin: yes
    val-clean-additional: yes
    tls-cert-bundle: /etc/ssl/certs/ca-certificates.crt
    tls-use-sni: yes  # Enable SNI support for DoT requests

    # Route uncached DNS queries through Cloudflare's DoT, using Tor for security
    forward-zone:
        name: "."
        forward-tls-upstream: yes
        forward-addr: 1.1.1.1@853  # Cloudflare DoT
        forward-addr: 1.0.0.1@853  # Cloudflare DoT
        forward-addr: 2606:4700:4700::1111@853
        forward-addr: 2606:4700:4700::1001@853

    # Route cached DNS queries through Tor for privacy and anonymity
    forward-zone:
        name: "."
        forward-addr: 127.0.0.1@9053  # Tor DNS for cached queries
        forward-addr: ::1@9053  # IPv6 Tor DNS

remote-control:
    control-enable: no
EOL

echo "[+] Configuring Tor for DNS resolution..."
cat > /etc/tor/torrc <<EOL
SocksPort 9050
DNSPort 9053
AutomapHostsOnResolve 1
VirtualAddrNetworkIPv4 10.192.0.0/10
AutomapHostsSuffixes .onion,.exit

# Route Cloudflare's DNS-over-TLS requests via Tor for additional anonymity
MapAddress 1.1.1.1 10.192.0.1
MapAddress 1.0.0.1 10.192.0.2
MapAddress 2606:4700:4700::1111 10.192.0.3
MapAddress 2606:4700:4700::1001 10.192.0.4
EOL

echo "[+] Restarting Tor and Unbound..."
systemctl restart tor unbound

echo "[+] Setting up permanent iptables rules for DNS..."
iptables -t nat -A OUTPUT -p udp --dport 53 -j REDIRECT --to-ports 5335
iptables -t nat -A OUTPUT -p tcp --dport 53 -j REDIRECT --to-ports 5335

echo "[+] Saving iptables rules..."
iptables-save > /etc/iptables/rules.v4
netfilter-persistent save
netfilter-persistent reload

echo "[+] Your DNS queries are now routed through Tor for privacy (cached queries) and Cloudflare with SNI for secure DNS-over-TLS (non-cached queries)."

sleep 5

reboot


DNS LEAK- TOR PREVAILS

Version 2.1 BETA

#!/bin/bash
set -e

echo "[+] Updating system..."
apt update && apt upgrade -y

echo "[+] Installing dependencies..."
apt install -y curl unbound tor

echo "[+] Configuring Unbound for DNS over Tor..."
cat > /etc/unbound/unbound.conf <<EOL
server:
    interface: 127.0.0.1
    port: 5335
    do-ip4: yes
    do-ip6: yes
    do-udp: yes
    do-tcp: yes
    hide-identity: yes
    hide-version: yes
    do-not-query-localhost: no
    harden-glue: yes
    harden-dnssec-stripped: yes
    harden-large-queries: yes
    harden-referral-path: yes
    harden-short-bufsize: yes
    harden-algo-downgrade: yes
    harden-below-nxdomain: yes
    use-caps-for-id: no
    aggressive-nsec: yes
    qname-minimisation: yes
    val-clean-additional: yes
    prefetch: yes
    prefetch-key: yes
    so-rcvbuf: 8m
    so-sndbuf: 8m
    num-threads: 4
    target-fetch-policy: "5 5 0 0 0"
    val-permissive-mode: no
    cache-min-ttl: 5
    cache-max-ttl: 86401
    serve-expired: no
    rrset-roundrobin: yes
    val-clean-additional: yes
    tls-cert-bundle: /etc/ssl/certs/ca-certificates.crt
    tls-use-sni: yes

    # Route ALL Uncached Queries via Tor (Cloudflare through Tor)
    forward-zone:
        name: "."
        forward-tls-upstream: yes
        forward-addr: 127.0.0.1@853  # Force all queries through Tor's DNSPort
        forward-addr: ::1@853 # Force all IPV6 queries through Tor's DNSPort

remote-control:
        control-enable: no
EOL

echo "[+] Configuring Tor for DNS resolution..."
cat > /etc/tor/torrc <<EOL
SocksPort 9050
DNSPort 853
AutomapHostsOnResolve 1
VirtualAddrNetworkIPv4 10.192.0.0/10
AutomapHostsSuffixes .onion,.exit

# Route Cloudflare's DoH and DoT requests via Tor
MapAddress 1.1.1.1@853 10.192.0.1@853
MapAddress 1.0.0.1@853 10.192.0.2@853
#MapAddress 2606:4700:4700::1111@853 10.192.0.3@853
#MapAddress 2606:4700:4700::1001@853 10.192.0.4@853
EOL

echo "[+] Restarting Tor and Unbound..."
systemctl restart tor unbound

echo "[+] Setting up permanent iptables rules for DNS..."
iptables -t nat -A OUTPUT -p udp --dport 53 -j REDIRECT --to-ports 5335
iptables -t nat -A OUTPUT -p tcp --dport 53 -j REDIRECT --to-ports 5335

echo "[+] Saving iptables rules..."
iptables-save > /etc/iptables/rules.v4
netfilter-persistent save
netfilter-persistent reload

echo "[+] Your DNS queries are now being routed through Tor for privacy."

sleep 5

reboot

Version 2.2 BETA

#!/bin/bash
set -e

echo "[+] Updating system..."
apt update && apt upgrade -y

echo "[+] Installing dependencies..."
apt install -y curl unbound tor iptables-persistent

echo "[+] Configuring Unbound for DNS over Tor..."
cat > /etc/unbound/unbound.conf <<EOL
server:
    interface: 127.0.0.1
    port: 5335
    do-ip4: yes
    do-ip6: yes
    do-udp: yes
    do-tcp: yes
    hide-identity: yes
    hide-version: yes
    do-not-query-localhost: no
    harden-glue: yes
    harden-dnssec-stripped: yes
    harden-large-queries: yes
    harden-referral-path: yes
    harden-short-bufsize: yes
    harden-algo-downgrade: yes
    harden-below-nxdomain: yes
    use-caps-for-id: no
    aggressive-nsec: yes
    qname-minimisation: yes
    val-clean-additional: yes
    prefetch: yes
    prefetch-key: yes
    so-rcvbuf: 8m
    so-sndbuf: 8m
    num-threads: 4
    target-fetch-policy: "5 5 0 0 0"
    val-permissive-mode: no
    cache-min-ttl: 5
    cache-max-ttl: 86401
    serve-expired: no
    rrset-roundrobin: yes
    val-clean-additional: yes
    tls-cert-bundle: /etc/ssl/certs/ca-certificates.crt
    tls-use-sni: yes

    # Route ALL Uncached Queries via Tor (Cloudflare through Tor)
    forward-zone:
        name: "."
        forward-tls-upstream: yes
        forward-addr: 127.0.0.1@853  # Force all queries through Tor's DNSPort
        forward-addr: ::1@853         # Force all IPV6 queries through Tor's DNSPort

remote-control:
        control-enable: no
EOL

echo "[+] Configuring Tor for DNS resolution..."
cat > /etc/tor/torrc <<EOL
SocksPort 9050
DNSPort 853
AutomapHostsOnResolve 1
VirtualAddrNetworkIPv4 10.192.0.0/10
AutomapHostsSuffixes .onion,.exit

# Route Cloudflare's DoH and DoT requests via Tor
MapAddress 1.1.1.1@853 10.192.0.1@853
MapAddress 1.0.0.1@853 10.192.0.2@853
MapAddress 2606:4700:4700::1111@853 10.192.0.3@853
MapAddress 2606:4700:4700::1001@853 10.192.0.4@853
EOL

echo "[+] Restarting Tor and Unbound..."
systemctl restart tor unbound

echo "[+] Setting up permanent iptables rules for DNS..."
iptables -t nat -A OUTPUT -p udp --dport 53 -j REDIRECT --to-ports 5335
iptables -t nat -A OUTPUT -p tcp --dport 53 -j REDIRECT --to-ports 5335

echo "[+] Saving iptables rules..."
iptables-save > /etc/iptables/rules.v4
netfilter-persistent save
netfilter-persistent reload

echo "[+] Your DNS queries are now being routed through Tor for privacy."

echo "[+] Testing DNS resolution..."
dig_result=$(dig @127.0.0.1 -p 5335 example.com +short)
if [ -n "$dig_result" ]; then
    echo "[+] DNS resolution successful: $dig_result"
else
    echo "[-] DNS resolution failed. Check logs and steps below."
fi

echo "[+] Configuration applied. Debugging steps if needed:"
echo "1. Check Unbound logs: journalctl -u unbound -b"
echo "2. Check Tor logs: journalctl -u tor -b"
echo "3. Test direct resolution: dig @1.1.1.1 -p 853 +tls example.com"
echo "4. Test Tor routing: torsocks dig @1.1.1.1 example.com"

sleep 5

reboot