LXC Secure DNS Stack for Cloudflare Using Unbound + Pihole + Tor(repressed) + Avahi

Version B

To swap between scripts, you do not need to re-run deploy1.sh UNLESS you wish to restore internet to your PI node. Conveniently, deploy1.sh is a great way to reset your Pihole:

sudo ./deploy1.sh

For the next script (below), don’t forget to set up permissions:

sudo chmod +x deploy8.sh

Our start command is still:

sudo ./deploy8.sh

For which the following is deploy8.sh:

#!/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

Here’s a breakdown of the differences between the two scripts, line by line:

1. Unbound Configuration (/etc/unbound/unbound.conf)

  • Script 1:harden-large-queries: yes

forward-addr: 1.1.1.1@853 forward-addr: 1.0.0.1@853 forward-addr: 2606:4700:4700::1111@853 forward-addr: 2606:4700:4700::1001@853

  • Script 2:harden-large-queries: no

forward-addr: 127.0.0.1@9053 # Force all queries through Tor's DNSPort forward-addr: ::1@9053 # Force all IPV6 queries through Tor's DNSPort forward-addr: 1.1.1.1@853 forward-addr: 1.0.0.1@853 forward-addr: 2606:4700:4700::1111@853 forward-addr: 2606:4700:4700::1001@853

  • The harden-large-queries setting is changed from yes to no.
  • The first two forward-addr lines are changed to force all IPv4 and IPv6 DNS queries through Tor’s DNSPort (9053).

2. Tor Configuration (/etc/tor/torrc)

  • Script 1:ExitNodes {us},{de},{nl} StrictNodes 0
  • Script 2:ExitNodes {us},{ca} StrictNodes 0
    • The Tor exit nodes are changed from {us},{de},{nl} (United States, Germany, Netherlands) to {us},{ca} (United States, Canada).

3. Unbound Tor routing (/etc/unbound/unbound.conf.d/tor.conf)

  • Both scripts contain the same information in this file. No changes were made.

Summary of Key Differences:

  • DNS Routing Through Tor: Script 2 forces all DNS queries through Tor’s DNSPort by changing the primary forwarders in Unbound’s main configuration. Script 1 uses cloudflare directly for the main forwarders.
  • Tor Exit Nodes: Script 2 uses different exit nodes for Tor.
  • Unbound hardening: Script 2 disables hardening of large queries.

which is better in terms of security? Distributed? In general?

When comparing the two scripts from a security and distribution perspective, here’s a breakdown:

Script 1:

  • Pros:
    • Direct DNS over TLS (DoT) to Cloudflare: This provides strong encryption for DNS queries between your system and Cloudflare’s servers.
    • Relatively straightforward configuration.
  • Cons:
    • Less anonymity: DNS queries go directly to Cloudflare, so they can see your DNS traffic.
    • Less distributed. The Cloudflare servers are the main point of contact for the DNS queries.

Script 2:

  • Pros:
    • Increased anonymity: Routing DNS queries through Tor’s DNSPort adds a layer of anonymity by obscuring your IP address and DNS traffic.
    • More distributed. Tor network is a distributed network.
  • Cons:
    • Potential performance impact: Tor can be slower than direct DoT due to the multiple hops involved.
    • Tor exit node risks: While Tor enhances anonymity, exit nodes can potentially see your traffic (though DNS queries are encrypted).
    • Increased complexity: The configuration is more complex, which can lead to potential errors.

In terms of security:

  • Both scripts implement DoT, which is a significant security improvement over plain DNS.
  • Script 2 prioritizes anonymity, which can be considered a security enhancement in certain threat models. However, Tor’s performance and exit node risks should be considered.
  • The change in the harden-large-queries setting in script 2, to “no”, is a reduction in hardening. So script 1 is more secure in that regard.

In terms of distribution:

  • Script 2 is more distributed because it utilizes the Tor network, which is designed to distribute traffic across a global network of relays.
  • Script 1 relies on the cloudflare servers, so is less distributed.

In general:

  • The “better” script depends on your specific needs and priorities.
  • If anonymity is your primary concern, Script 2 is preferable.
  • If you prioritize speed and simplicity, and are less concerned about extreme anonymity, Script 1 is a good option.
  • It is important to remember that using Tor does not guarantee absolute anonymity.

Key Considerations:

  • Threat model: Consider what threats you are trying to protect against.
  • Performance: Tor can introduce latency.
  • Complexity: More complex configurations can be harder to maintain.

Therefore, there is not a single answer to which script is “better”. It depends on the users individual needs.