Scopri come AdGuard Home ci permette di creare un DNS filtrante, open source e controllato

Avete mai sentito parlare di DNS sinkhole? È una tecnica che consente a un server DNS di non limitarsi a risolvere gli indirizzi, ma di filtrarli basandosi su delle istruzioni che gli forniamo. A livello aziendale, possono essere utili per evitare la diffusione di malware e bloccare tentativi di phishing, ma recentemente si sono diffusi anche nel mondo consumer per bloccare pubblicità e traccianti, specialmente nelle app degli smartphone dove le limitazioni architetturali dei sistemi operativi mobili non permettono alternative accessibili.
Il funzionamento è semplice: il server DNS sinkhole viene impostato e inizia ad ascoltare per le richieste in entrata. Nel momento in cui questa arriva da un client, il nostro DNS sinkhole la rigirerà a un altro DNS (essendo ricorsivo), otterrà la risposta e sulla base di liste di blocco che configureremo deciderà se rispondere al client con l’indirizzo IP effettivo del sito, permettendoci di navigare, oppure darà come risposta l’IP 0.0.0.0 che risulterà in un errore.
Ci sono alcuni servizi commerciali come il famoso NextDNS o il più recente controlD, ma sono diffusi anche programmi che possono essere ospitati autonomamente, come Pi-Hole o AdGuard Home. Utilizzeremo proprio quest’ultimo perché ha numerosi vantaggi: oltre ad avere una gran quantità di funzioni native, si installa facilmente, è compatibile con una gran quantità di piattaforme (praticamente qualsiasi sistema operativo Unix-like, più Windows attraverso Docker) ed è scritto in Go, un linguaggio di programmazione memory-safe molto utilizzato nel mondo DevOps per la sua velocità e scalabilità.
In questa guida effettueremo un deploy utilizzando Docker, il web server Caddy e lo strumento ACME lego. Pensiamo che questa soluzione sia un buon compromesso tra numero di piattaforme (restano fuori solo FreeBSD e OpenBSD, salvo poter sperimentare col primo tramite podman adattando questa guida(1): date un occhio alle FAQ in basso). Abbiamo scelto Caddy anziché i più classici nginx o Apache perché è scritto anch’esso in Go, garantendoci leggerezza e prestazioni (importanti per un DNS) e ha una sintassi di configurazione semplice. Inoltre, supporta nativamente il protocollo DNS sicuro DNS over HTTPS (DoH) che andremo a implementare.
Procediamo nel deploy di AdGuard Home. I requisiti di cui abbiamo bisogno sono:
Procediamo ora all’installazione di Docker che ci permetterà di avviare i componenti necessari.
Nota: i comandi indicati useranno l’editor di testo nano, ma si può cambiare con vim o quello che preferite.
Su Ubuntu/Debian/Fedora/RHEL (e cloni): Vai alla guida ufficiale
Su Alpine Linux troviamo Docker nei repository community:
# nano /etc/apk/repositories
Togliamo il commento alla riga del repository community (generalmente la seconda), salviamo e usciamo.
Nota: vi consigliamo di attivare HTTPS per i repository: sarà sufficiente sostituire http con https negli URL presenti.
Aggiorniamo APK e installiamo Docker e il plugin compose:
# apk update
# apk add docker docker-cli-compose
Avviamo il servizio Docker e facciamo in modo che parta in automatico all’avvio del sistema:
# rc-service docker start
# rc-update add docker default
Su Windows e macOS: Installa Docker Desktop
Se non usiamo l’utente root (come buona pratica di sicurezza) possiamo aggiungere l’utente attuale al gruppo docker per far sì di poterlo controllare senza privilegi di amministratore:
Su Ubuntu/Debian/Fedora/RHEL (e cloni):
# usermod -aG docker ${USER}
Su Alpine Linux (ma anche su Ubuntu e Debian):
# adduser ${USER} docker
Una volta che abbiamo tutto pronto, utilizziamo lo strumento docker compose per creare un file in cui elencheremo le immagini che ci servono, su quali porte ascolteranno e la reti sulle quali operano. Docker, infatti, isola i container, perciò dovremo dirgli esplicitamente se vogliamo che abbiano accesso alla rete e/o debbano comunicare fra loro.
Creiamo una cartella che conterrà il nostro servizio ed entriamoci. Noi la chiameremo adguard-home:
$ mkdir adguard-home && cd adguard-home
Creiamo il nostro file che conterrà il compose:
$ nano compose.yml
E scriviamo le informazioni necessarie. Qui sotto trovate un esempio pronto all’uso da copiare. Potete personalizzare i parametri di lego, ad esempio per generare i certificati usando le API di un provider differente da Cloudflare come nella guida ufficiale, oppure potete eliminare la porta 53 per AdGuard Home se avete intenzione di usare solo DNS sicuri (consigliato se si userà solo su PC e smartphone).
Vi riportiamo qui un esempio di file compose funzionante. Ricordate di modificare i campi evidenziati: inserite la vostra email per generare i certificati di sicurezza e inserite il vostro dominio (sarà example.org e *.example.org per un certificato wildcard).
services:
lego:
image: goacme/lego:v4.27.0
container_name: lego
volumes:
- lego_certs:/.lego
env_file:
- lego.env
command: >
--email="mail@example.org"
--dns=cloudflare
--domains="example.org"
--domains="*.example.org"
--path="/.lego"
--accept-tos
run
restart: "no"
networks:
- internal
caddy:
image: caddy:2-alpine
container_name: caddy
ports:
- "80:80"
- "443:443"
- "443:443/udp"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- lego_certs:/certs:ro
- caddy_config:/config
networks:
- internal
restart: unless-stopped
depends_on:
- lego
adguard:
image: adguard/adguardhome:latest
container_name: adguard
ports:
- "53:53/tcp"
- "53:53/udp"
- "853:853/tcp"
- "853:853/udp"
volumes:
- adguard_work:/opt/adguardhome/work
- adguard_conf:/opt/adguardhome/conf
- lego_certs:/certs:ro
networks:
- internal
restart: unless-stopped
depends_on:
- lego
networks:
internal:
driver: bridge
volumes:
lego_certs:
caddy_config:
adguard_work:
adguard_conf:
data:
Salviamo il file. Ora creiamo nella stessa cartella il Caddyfile, il set di istruzioni di Caddy:
$ nano Caddyfile
E inseriamoci la nostra configurazione:
dns.example.org {
tls /certs/certificates/example.org.crt /certs/certificates/example.org.key
reverse_proxy adguard:3000
}
example.org {
tls /certs/certificates/example.org.crt /certs/certificates/example.org.key
@doh path /dns-query*
handle @doh {
reverse_proxy adguard:443 {
transport http {
tls
tls_insecure_skip_verify
}
}
}
handle {
respond "OK" 200
}
}
*.example.org {
tls /certs/certificates/example.org.crt /certs/certificates/example.org.key
@doh path /dns-query*
handle @doh {
reverse_proxy adguard:443 {
transport http {
tls
tls_insecure_skip_verify
}
}
}
}
Come potete vedere, in questo file Caddy è configurato per portarci al pannello di amministrazione di AdGuard Home all’indirizzo dns.example.org, a rispondere alle richieste DoH e a portarci alla pagina di status dal browser al dominio radice example.org e a rispondere ai sottodomini (motivo per cui ci serve un certificato wildcard) per tutto quello che sarà su *.example.org, per esempio casa.example.org, stefania.example.org etc. Più avanti spiegheremo questa funzionalità.
Ricordate di personalizzare il file usando il vostro dominio. Stiamo presupponendo che venga utilizzato esclusivamente per AdGuard Home.
Infine, creiamo il file lego.env che contiene le chiavi per connettersi a Cloudflare:
$ nano lego.env
E inseriamo questa stringa:
CLOUDFLARE_DNS_API_TOKEN=abcxyz
Dovrete sostituire "abcxyz" con una chiave API di Cloudflare. Per generarla:
Ora che è tutto pronto, tiriamo su la nostra infrastruttura:
$ docker compose up -d
Nota: Nelle versioni recenti di Docker il comando corretto è docker compose, non più docker-compose.
Lego genererà ora i nostri certificati. Appena sarà pronto, anche Caddy e AdGuard Home partiranno.
Da questo momento, potete recarvi su dns.example.org per visualizzare la pagina introduttiva di AdGuard Home:
Al passo due, dobbiamo configurare le interfacce di AdGuard Home. Alla sezione “Interfaccia Web dell’Admin”, cambiamo la porta da 80 a 3000 per rispecchiare la configurazione di Caddy:
ATTENZIONE: sotto la sezione “Server DNS” potrebbe apparire un errore relativo alla porta 53. Questo capita se il nostro sistema operativo sta usando un DNS locale in ascolto. Sulle versioni recenti di Ubuntu e Debian troveremo systemd-resolved che dovrebbe essere disattivato, sostituendogli AdGuard Home come DNS locale.
Al passo 3, inseriamo un nome utente e una password efficace per proteggere l’interfaccia di amministrazione:
AdGuard Home è pronto! Se inseriamo l’IP del server nelle impostazioni DNS di un dispositivo inizierà già a rispondere alle richieste in ingresso con la configurazione di default. Ovviamente, questo è possibile se avete lasciato la porta 53 aperta nel vostro docker compose. In caso contrario, continuate a leggere per configurare i DNS sicuri.
Procediamo quindi ad attivare i protocolli DNS sicuri, molto utili su smartphone e PC, oltre ad aumentare il livello di privacy cifrando le nostre richieste DNS:

Nella sezione “crittografia”, spuntiamo “Attiva crittografia” e inseriamo il nostro nome di dominio in “Nome server”. Disabilitando il DNS semplice in questa sezione, AdGuard Home non risponderà più alle richieste DNS su IP sulla porta 53. Vi consigliamo di farlo se non volete utilizzarlo su dispositivi diversi da smartphone e PC. Ovviamente, questa impostazione è indifferente se all’interno del compose non avete aperto la porta 53.
In basso invece, alla sezione “Certificati”, incolliamo il percorso dei certificati di lego:
/certs/certificates/example.org.crt
In chiave privata, invece:
/certs/certificates/example.org.key

Cambiando il dominio con quello scelto. Attendiamo che appaia la conferma in verde. Assicuriamoci che il certificato sia per example.org e *.example.org. Salviamo la configurazione.
È tutto pronto! AdGuard Home ora risponderà alle richieste DNS private su protocollo DNS over TLS (DoT) al dominio example.org oppure qualsiasi sottodominio che scegliamo (ad esempio livia.example.org, ufficio.example.org etc.). I sottodomini sono utili perché vengono riportati singolarmente nelle statistiche, permettendoci di monitorare quali richieste vengono effettuate e quali indirizzi sono filtrati.
Sul protocollo DNS over HTTPS, invece, AdGuard Home risponderà all’indirizzo https://example.org/dns-query/. Se vogliamo aggiungere un nome (client ID), come nei sottodomini di sopra, basta aggiungerlo dopo lo slash finale: https://example.org/dns-query/livia oppure https://example.org/dns-query/ufficio.
Su Android, usiamo la ricerca all’interno delle impostazioni e scriviamo “DNS privato”. Tocchiamo su “nome host del DNS privato” e inseriamo il dominio o sottodominio per il protocollo DoT (è l’unico supportato). Avremo ora un adblocker a livello di sistema!
Su iOS e macOS, la procedura è un po’ più complessa:
Su Windows, la configurazione invece è molto ostica. Vi consigliamo di attivarlo direttamente nel browser, anche se non vi garantisce benefici per l’intero sistema. Su Google Chrome, aprite le impostazioni e andate su “Privacy e sicurezza” e sulla sezione “Sicurezza”
Attiviamo in basso il DNS sicuro personalizzato e inseriamo il nostro indirizzo DoH:
È tutto! AdGuard Home ha già delle impostazioni di filtraggio ottimali di default, ma vi consigliamo di esplorarne le impostazioni per scoprire tutto quello che può fare. Possiamo infatti cambiare le liste di blocco, cambiare i DNS upstream a cui si appoggia (come detto all’inizio, è un DNS ricorsivo. Di default, raccoglie le richieste da Quad9 e le filtra). Possiamo anche impostare dei client ID fissi che possono collegarsi, limitando la quantità di sottodomini disponibili.
Fateci conoscere la vostra configurazione ideale di AdGuard Home!
# mkdir -p /etc/systemd/resolved.conf.d
E al suo interno, creiamo il file adguardhome.conf:
# nano /etc/systemd/resolved.conf.d/adguardhome.conf
E inseriamoci la configurazione:
[Resolve]
DNS=127.0.0.1
DNSStubListener=no
Salviamo e attiviamo un nuovo file resolv.conf:
# mv /etc/resolv.conf /etc/resolv.conf.backup
# ln -s /run/systemd/resolve/resolv.conf /etc/resolv.conf
Infine, riavviamo DNSStubListener:
# systemctl reload-or-restart systemd-resolved