A containerized DNS privacy solution combining AdGuard Home, Unbound, and DNSCrypt-proxy for enhanced privacy and ad-blocking. This project was inspired by AdGuard-WireGuard-Unbound-DNScrypt. The goal is to streamline the original multi-step manual installation into a single, easy-to-deploy container while maintaining compatibility with standard AdGuard Home volume mappings.
- Ad & tracker blocking with AdGuard Home
- DNS caching and DNSSEC validation via Unbound recursive resolver
- Encrypted DNS through DNSCrypt-proxy with ODoH (Oblivious DNS-over-HTTPS)
- Anonymized routing through relay servers for enhanced privacy
- Automatic root hints updates every 6 months via cron
- Ready-to-deploy with Podman/Docker Compose
Install Podman and Podman Compose:
sudo apt install podman podman-compose- Enable privileged port binding (required for DNS port 53): By default, rootless Podman doesn't allow exposing a privileged port (<1024). Unless you are happy to use an unconventional DNS port to avoid an error, run:
echo "net.ipv4.ip_unprivileged_port_start=53" | sudo tee /etc/sysctl.d/20-dns-privileged-port.conf- Optimize kernel buffers:
Unbound is configured with a larger kernel buffer so that no messages are lost during spikes in the traffic. To match the parameters in
unbound/unbound.confrun:
echo "net.core.rmem_max=4194304" | sudo tee /etc/sysctl.d/99-unbound-buffers.conf
echo "net.core.wmem_max=4194304" | sudo tee -a /etc/sysctl.d/99-unbound-buffers.conf- Apply changes
sudo sysctl --systemDownload this repo and spin up a container:
git clone https://github.com/igoresso/aduncrypt.git
cd aduncrypt
podman-compose up -d- Access AdGuard Home at
http://<host-ip>:3000, replacing<host-ip>withlocalhostif youβre running AdUnCrypt locally - Follow the setup wizard - when asked which interface to listen on, keep All interfaces
-
Delete everything from both Upstream and Bootstrap DNS servers options and add the following addresses to point at the Unbound resolver:
127.0.0.1:5053(Unbound)127.0.0.1:5353(Direct fallback to Oblivious DNS over HTTPS)
-
Put a tick β next to Parallel Request option.
-
In DNS settings, uncheck Enable cache or set DNS cache size to
0(caching is handled by Unbound) -
Add blocklists in Filters β DNS blocklists:
Disable systemd-resolved (if running):
sudo nano /etc/systemd/resolved.conf
# Set:
# DNS=127.0.0.1
# DNSStubListener=no
sudo systemctl restart systemd-resolvedUpdate system resolver:
# Check current configuration
cat /etc/resolv.conf
# Should contain: nameserver 127.0.0.1
# If not, update it:
echo "nameserver 127.0.0.1" | sudo tee /etc/resolv.confAfter completing initial setup, switch to the systemd deployment using Podman Quadlet (needs podman version >= 4.4).
Important
The provided Quadlet container file assumes that the AdUnCrypt project directory is located in your home folder, i.e. ~/aduncrypt/. If you cloned it elsewhere, update all volume paths in aduncrypt.container accordingly β for example, replace %h/aduncrypt/... with the absolute path to your local copy.
# Stop compose (no longer needed)
podman-compose down
# Create systemd directory
mkdir -p ~/.config/containers/systemd
# Copy the quadlet container file to the systemd directory
cp aduncrypt.container ~/.config/containers/systemd/aduncrypt.container
# Reload systemd to recognize the new quadlet
systemctl --user daemon-reload
# Start the service
systemctl --user start aduncrypt.service
# Enable lingering for auto-start on boot
sudo loginctl enable-linger $USER
# Enable auto-updates
systemctl --user enable --now podman-auto-update.timerIf you prefer manual management:
# Just restart when needed
podman-compose up -dNote
Manual restart required after system reboot.
# Check service status (if using Quadlet)
systemctl --user status aduncrypt.service
# Check container is running
podman ps
# View container logs
podman logs -f aduncrypt
# Test DNS resolution
dig @127.0.0.1 google.com
# Test auto-update capability
podman auto-update --dry-run
# Monitor systemd logs (if using Quadlet)
journalctl --user-unit=aduncrypt.service -bTest your DNS setup with these tools:
- 1.1.1.1 Help - Basic connectivity test
- BrowserLeaks DNS - Should show "Cloudflare" if nothing is changed
- DNSCheck Tools - Comprehensive DNS analysis
| Port | Protocol | Service | Description |
|---|---|---|---|
| 53 | TCP/UDP | DNS | Primary DNS resolver |
| 80 | TCP | HTTP | AdGuard Home web panel |
| 3000 | TCP | HTTP | Initial setup (disable after setup) |
| 5053 | TCP/UDP | Internal | Unbound DNS resolver |
| 5353 | TCP/UDP | Internal | DNSCrypt-proxy |
Note
The Quadlet container doesn't expose port 3000. Complete the initial AdGuard Home setup using the compose method first, then switch to quadlet for production deployment.
The following ports are commented out in compose.yml but can be enabled as needed. For quadlet users, add them to your aduncrypt.container file using PublishPort= directives:
| Port | Protocol | Service | Description |
|---|---|---|---|
| 443 | TCP/UDP | HTTPS | AdGuard Home web panel HTTPS |
| 784 | UDP | DNS-over-QUIC | Modern encrypted DNS protocol |
| 853 | TCP | DNS-over-TLS | Encrypted DNS over TLS |
| 67 | UDP | DHCP Server | Dynamic IP assignment |
| 68 | UDP | DHCP Client | DHCP client responses |
Unbound is configured to use Oblivious DNS-over-HTTPS via dnscrypt-proxy. DNS over TLS is querying Cloudflare upstream endpoints. All configuration files are mounted as volumes for easy customization:
unbound/unbound.conf- Unbound DNS resolver settingsdnscrypt/dnscrypt-proxy.toml- DNSCrypt-proxy configurationadguard/adguard/opt-adguard-conf- AdGuard Home configurationadguard/adguard/opt-adguard-work- AdGuard Home data
You have full control to adjust the configuration as you see fit.
This project is inspired by and builds upon:
- AdGuard-WireGuard-Unbound-DNScrypt by trinib - Original comprehensive DNS privacy setup
- adguard-unbound by lolgast1987 - Containerization approach
AdUnCrypt aims to make the original's excellent privacy-focused DNS configuration accessible through simplified container deployment.