Este es el tercer manual de una lista que debes poner en marcha en el siguiente orden.
- WireGuard en Raspberry PI, VPN casera, segura y gratuita.
- Pi-hole en Raspberry Pi: Instalación paso a paso.
- Configura tu propio servidor DNS recursivo con Pi-hole y Unbound
- El manual definitivo para navegar 100% seguro con WireGuard, Pi-hole y Unbound.
En el mundo actual, donde la privacidad en línea es cada vez más valiosa, confiar en servidores DNS de terceros puede ser un riesgo. Por eso, en esta guía te mostraré cómo convertir tu Pi-hole en una solución DNS completa y autónoma, instalando y configurando Unbound como servidor DNS recursivo local.
El problema: ¿en quién confiar?
Pi-hole incluye su propio servidor DNS (FTLDNS) que, después de aplicar las listas de bloqueo, reenvía las consultas de los clientes a los servidores DNS upstream configurados.
Sin embargo, esto plantea un problema de privacidad: cuando confías tus consultas DNS a un proveedor externo, estás delegando información sobre qué sitios visitas. Y aunque muchos proveedores prometen ser «privados y gratuitos», ¿cómo puedes saber realmente que cumplen su palabra?.
Además, los servidores DNS de grandes proveedores son objetivos muy atractivos para los atacantes. Si logran envenenar la caché de uno de ellos, millones de usuarios podrían ser redirigidos a sitios de phishing sin saberlo.
Cuando ejecutas tu propio servidor DNS recursivo (pequeño y local), la probabilidad de verse afectado por este tipo de ataques se reduce drásticamente.
¿Qué es un servidor DNS recursivo?
La primera distinción importante es entre un servidor autoritativo y uno recursivo:
- Un servidor autoritativo conoce la respuesta correcta para un dominio porque es el que lo gestiona (por ejemplo, el servidor autoritativo de
pi-hole.netsabe cuál es su IP real). - Un servidor recursivo, en cambio, resuelve cualquier consulta que recibe recorriendo la jerarquía del sistema DNS: pregunta a los servidores raíz, luego a los de nivel superior (TLD), y finalmente a los autoritativos, hasta obtener la respuesta.
¿Qué ofrece esta guía?
En pocos pasos, configuraremos tu propio servidor DNS recursivo en el mismo dispositivo donde ya tienes Pi-hole. No necesitas hardware adicional. La guía asume un sistema basado en Debian/Ubuntu relativamente reciente y utiliza los paquetes oficiales para simplificar el proceso.
Antes de empezar: prueba de acceso a los servidores raíz
Es fundamental verificar que tu ISP o router no esté interceptando o redirigiendo el tráfico DNS en el puerto 53. Si lo hace, Unbound no podrá comunicarse directamente con los servidores raíz y fallará de formas difíciles de diagnosticar.
Ejecuta estas pruebas en el sistema donde instalarás Unbound:
1. Prueba de reachabilidad UDP
Consulta directamente el servidor raíz a.root-servers.net (198.41.0.4) sin solicitar recursión:
dig @198.41.0.4 . NS +norec +time=3
Revisa la línea flags: en la respuesta. Si estás hablando directamente con un servidor raíz, verás aa (Authoritative Answer) y no verás ra (Recursion Available), ya que los servidores raíz no ofrecen recursión.
Ejemplo de respuesta correcta:
;; flags: qr aa; QUERY: 1, ANSWER: 13, AUTHORITY: 0, ADDITIONAL: 27
Si tu tráfico está siendo interceptado, aparecerá ra y probablemente faltará aa.
2. Prueba de reachabilidad TCP
Unbound también depende de TCP/53 para respuestas DNSSEC grandes y para reintentos:
dig @198.41.0.4 . NS +norec +tcp +time=3
Si esta prueba falla (timeout) pero la anterior funcionó, puede que tu red esté bloqueando tráfico DNS sobre TCP, lo que causará fallos crípticos en Unbound.
3. Confirmación de identidad vía CHAOS
Los servidores raíz responden a consultas de clase CHAOS con identificadores únicos. La mayoría de los proxies de ISP no manejan este tipo de consultas:
dig @198.41.0.4 version.bind CH TXT +time=3
Si te conectas directamente al servidor raíz, la respuesta será un registro TXT con «ATLAS»:
version.bind. 0 CH TXT "ATLAS"
Si el tráfico está siendo interceptado, obtendrás otra cadena, timeout o SERVFAIL.
Si alguna de estas pruebas falla, no es recomendable continuar con la instalación hasta investigar y resolver la causa (redirección del ISP, bloqueo de TCP DNS, filtros de seguridad en el router, etc.).
Configurando Pi-hole como servidor DNS recursivo
Vamos a utilizar Unbound, un servidor DNS recursivo seguro y de código abierto desarrollado por NLnet Labs, VeriSign, Nominet y Kirei.
1. Instalación de Unbound
sudo apt install unbound
Si instalas desde el gestor de paquetes, el archivo root.hints se instalará automáticamente con la dependencia dns-root-data y se actualizará con el gestor de paquetes.
Opcional: Si no instalas desde un gestor de paquetes, puedes descargar manualmente la lista de servidores raíz (actualízala cada seis meses aproximadamente):
wget https://www.internic.net/domain/named.root -qO- | sudo tee /var/lib/unbound/root.hints
Si haces esto, tendrás que descomentar la línea root-hints: en el archivo de configuración.
2. Configuración de Unbound
Crea o edita el archivo /etc/unbound/unbound.conf.d/pi-hole.conf con el siguiente contenido:
server:
# Si no se especifica logfile, se usa syslog
# logfile: "/var/log/unbound/unbound.log"
verbosity: 0
interface: 127.0.0.1
port: 5335
do-ip4: yes
do-udp: yes
do-tcp: yes
# Puedes cambiarlo a no si no tienes conectividad IPv6
do-ip6: yes
# Déjalo en no a menos que tengas IPv6 nativo
prefer-ip6: no
# Usa esto solo si descargaste manualmente la lista de servidores raíz
# root-hints: "/var/lib/unbound/root.hints"
# Confía en la información de glue solo si está dentro de la autoridad del servidor
harden-glue: yes
# Requiere datos DNSSEC para zonas con trust-anchors; si faltan, la zona se marca como BOGUS
harden-dnssec-stripped: yes
# No uses randomización de mayúsculas (puede causar problemas con DNSSEC)
use-caps-for-id: no
# Reduce el tamaño del buffer de reensamblaje EDNS (recomendado por DNS Flag Day 2020)
edns-buffer-size: 1232
# Precarga entradas de caché próximas a expirar (solo para dominios consultados frecuentemente)
prefetch: yes
# Un hilo suele ser suficiente; aumenta solo en máquinas potentes
num-threads: 1
# Asegura que el buffer del kernel sea lo suficientemente grande para no perder mensajes
so-rcvbuf: 1m
# Protege la privacidad de rangos IP privados
private-address: 192.168.0.0/16
private-address: 169.254.0.0/16
private-address: 172.16.0.0/12
private-address: 10.0.0.0/8
private-address: fd00::/8
private-address: fe80::/10
# Evita consultas inversas a rangos IP no públicos (RFC6303)
private-address: 192.0.2.0/24
private-address: 198.51.100.0/24
private-address: 203.0.113.0/24
private-address: 255.255.255.255/32
private-address: 2001:db8::/32
Nota: En algunas distribuciones basadas en Red Hat (incluyendo CentOS hasta v10), la ruta del archivo puede ser /etc/unbound/conf.d/pi-hole.conf.
3. Iniciar y probar Unbound
Reinicia el servidor:
sudo service unbound restart
Comprueba que funciona:
~ $ dig pi-hole.net @127.0.0.1 -p 5335
; <<>> DiG 9.20.23-1~deb13u1-Debian <<>> pi-hole.net @127.0.0.1 -p 5335
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 20038
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;pi-hole.net. IN A
;; ANSWER SECTION:
pi-hole.net. 300 IN A 162.244.93.14
;; Query time: 36 msec
;; SERVER: 127.0.0.1#5335(127.0.0.1) (UDP)
;; WHEN: Fri Jun 26 22:02:55 CEST 2026
;; MSG SIZE rcvd: 56
La primera consulta puede ser algo lenta, pero las siguientes (incluso para otros dominios bajo el mismo TLD) deberían ser bastante rápidas.
4. Prueba de validación DNSSEC
Para verificar que DNSSEC funciona correctamente pasa este comando:
~ $ dig fail01.dnssec.works @127.0.0.1 -p 5335 #copia este comando
; <<>> DiG 9.20.23-1~deb13u1-Debian <<>> fail01.dnssec.works @127.0.0.1 -p 5335
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 28659
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;fail01.dnssec.works. IN A
;; Query time: 1008 msec
;; SERVER: 127.0.0.1#5335(127.0.0.1) (UDP)
;; WHEN: Fri Jun 26 21:58:14 CEST 2026
;; MSG SIZE rcvd: 48
Debería devolver SERVFAIL y sin dirección IP.
y luego verifica con este otro:
~ $ dig +ad dnssec.works @127.0.0.1 -p 5335 #Copia este comando
; <<>> DiG 9.20.23-1~deb13u1-Debian <<>> +ad dnssec.works @127.0.0.1 -p 5335
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 62528
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;dnssec.works. IN A
;; ANSWER SECTION:
dnssec.works. 3600 IN A 46.23.92.212
;; Query time: 152 msec
;; SERVER: 127.0.0.1#5335(127.0.0.1) (UDP)
;; WHEN: Fri Jun 26 21:59:03 CEST 2026
;; MSG SIZE rcvd: 57
Debería devolver NOERROR, una dirección IP y la bandera ad (Authentic Data) en la sección flags:, indicando que la respuesta ha sido autenticada y validada mediante DNSSEC.
5. Configurar Pi-hole
Ve a la interfaz web de Pi-hole: Settings > DNS.
En la sección Custom DNS servers, especifica:
127.0.0.1#5335
Asegúrate de desmarcar todos los demás servidores upstream.

No olvides hacer clic en Save & Apply.
6. Deshabilitar entrada de resolvconf (requerido para Debian Bullseye+)
En Debian Bullseye y versiones posteriores, se instala automáticamente el paquete openresolv con una configuración que puede causar comportamientos inesperados en Pi-hole y Unbound.
El servicio unbound-resolvconf.service escribe nameserver 127.0.0.1 (sin el puerto 5335) en /etc/resolv.conf, lo que afecta a los servicios locales.
Paso 1: Deshabilitar el servicio
Comprueba si está activo:
systemctl is-active unbound-resolvconf.service
Si responde que inactivo, ve al punto 7, de lo contrario deshabilítalo.
Deshabilítalo así:
sudo systemctl disable --now unbound-resolvconf.service
Paso 2: Deshabilitar el archivo de configuración
sudo sed -Ei 's/^unbound_conf=/#unbound_conf=/' /etc/resolvconf.conf
sudo rm /etc/unbound/unbound.conf.d/resolvconf_resolvers.conf
Reinicia Unbound:
sudo service unbound restart
7. (Opcional) Añadir logs a Unbound
Advertencia: No se recomienda aumentar la verbosidad para uso diario, ya que Unbound genera muchos logs. Puede ser útil para depuración.
Niveles de verbosidad:
- 0: Solo errores
- 1: Información operativa
- 2: Información operativa detallada
- 3: Información a nivel de consulta
- 4: Información a nivel de algoritmo
- 5: Registro de identificación de cliente para fallos de caché
Edita el archivo con:
sudo nanno /etc/unbound/unbound.conf.d/pi-hole.conf
y añade en la sección server:
server:
logfile: "/var/log/unbound/unbound.log"
log-time-ascii: yes
verbosity: 1
Crea el directorio y archivo de log, y establece permisos:
sudo mkdir -p /var/log/unbound
sudo touch /var/log/unbound/unbound.log
sudo chown unbound /var/log/unbound/unbound.log
⚠️ Una nota importante sobre AppArmor en Raspberry Pi OS
Es muy probable que AppArmor no esté activo en tu Raspberry Pi. (ni falta que hace)
Raspberry Pi OS no lo habilita por defecto, y muchos usuarios tienen que activarlo manualmente.
sudo aa-status
Si al ejecutar el comando anterior, ves un error como comando no encontrado, No such file or directory, apparmor module is loaded, apparmor filesystem is not mounted, significa que AppArmor no está instalado o no está activo.
En ese caso, el paso de la guía para añadir una excepción en AppArmor no es necesario y puedes ignorarlo con tranquilidad.
Solo en el caso de que estuviese activo, sigue estos pasos:
Añadir una excepción en AppArmor
En sistemas modernos Debian/Ubuntu, añade una excepción en AppArmor:
Crea o edita /etc/apparmor.d/local/usr.sbin.unbound y añade:
/var/log/unbound/unbound.log rw,
Recarga AppArmor:
sudo apparmor_parser -r /etc/apparmor.d/usr.sbin.unbound
sudo service apparmor restart
Reinicia Unbound:
sudo service unbound restart
8. Verificar que Pi-hole está usando Unbound
Realiza una consulta DNS:
dig en.wikipedia.org @127.0.0.1
Luego revisa el log de Pi-hole:
sudo tail /var/log/pihole/pihole.log
Deberías ver líneas como:
Nov 24 11:57:47 dnsmasq[973]: query[A] en.wikipedia.org from 127.0.0.1
Nov 24 11:57:47 dnsmasq[973]: forwarded en.wikipedia.org to 127.0.0.1#5335
Nov 24 11:57:47 dnsmasq[973]: reply en.wikipedia.org is <IP>
Si ves que las respuestas vienen de 127.0.0.1#5335, ¡enhorabuena! Pi-hole está usando Unbound como upstream.
Para otros clientes de la red
La configuración de la Raspberry solo afecta a la propia Raspberry. Para que el resto de dispositivos (móviles, portátiles, etc.) usen tu Pi-hole, configura tu router DHCP para que entregue 192.168.1.18 como único servidor DNS (y no entregue ningún secundario). Así, toda la red estará protegida.
Desinstalar Unbound
Si en algún momento quieres revertir los cambios:
sudo apt remove unbound
Recuerda volver a configurar otro servidor DNS upstream en Pi-hole.
Conclusión
Has configurado exitosamente tu propio servidor DNS recursivo con Pi-hole y Unbound. Ahora:
- Tu privacidad mejora: ninguna entidad externa registra todas tus consultas DNS.
- Tu seguridad aumenta: al ser un servidor pequeño y local, es un objetivo mucho menos atractivo para ataques de envenenamiento de caché.
- Tienes control total: decides cómo se resuelven tus consultas DNS, sin depender de terceros.
Comprobaciones, errores y soluciones
🛑 Advertencia so-rcvbuf en Unbound
La configuración establece so-rcvbuf: 1m para manejar altas tasas de consultas. Puedes ver esta advertencia:
so-rcvbuf 1048576 was not granted. Got 425984.
¿Dónde se puede ver esta advertencia? En dos sitios principales:
1. En los logs de Unbound
Esta es la forma más común de encontrar la advertencia. Unbound la escribe en sus propios registros cuando no puede establecer el tamaño de búfer que ha solicitado en su configuración (so-rcvbuf: 1m).
Puedes comprobar los logs de Unbound con el siguiente comando:
sudo journalctl -u unbound | grep "so-rcvbuf"
Si la advertencia está presente, verás un mensaje similar a este:
unbound[110586:0] warning: so-rcvbuf 1048576 was not granted. Got 425984.[reference:0]
Este mensaje indica que Unbound pidió un búfer de recepción de 1048576 bytes (1 MB), pero el sistema solo le concedió 425984 bytes.
2. Al iniciar Unbound manualmente (en primer plano)
Si ejecutas Unbound en primer plano (por ejemplo, para depuración), la advertencia aparecerá directamente en la terminal:
sudo unbound -d
¿Qué significa esta advertencia?
- No es un error crítico: Unbound seguirá funcionando, pero podría tener un rendimiento ligeramente inferior en momentos de mucho tráfico.
- Es un problema de límites del sistema: Unbound está pidiendo un búfer de red más grande para manejar mejor picos de tráfico, pero el límite del kernel (
net.core.rmem_max) es más bajo.
Para solucionarlo, tendrías que aumentar el límite del kernel de forma permanente, por ejemplo, creando un archivo en /etc/sysctl.d/ (especialmente importante en sistemas más nuevos como Debian 13, donde /etc/sysctl.conf ya no se usa por defecto).
¿Como se soluciona?
- Comprueba el límite actual:
sudo sysctl net.core.rmem_max
- Aumenta temporalmente:
sudo sysctl -w net.core.rmem_max=1048576
- Hazlo permanente. Edita
sudo nano /etc/sysctl.d/99-unbound.conf
y añade:
net.core.rmem_max=1048576
- Aplica los cambios:
- En sistemas actualizados (ej. Debian 13):
sudo systemctl restart systemd-sysctl
- Reinicia Unbound:
sudo service unbound restart
🛑 Error en la prueba de DNSSEC
Durante la configuración de Pi-hole + Unbound como servidor DNS recursivo con validación DNSSEC, nos encontramos con un problema aparente, al realizar consultas con la bandera +dnssec, el sistema mostraba timeouts y terminaba resolviendo a través del router (fallback) en lugar de nuestro propio Pi-hole.
Síntoma
Desde el cliente, al ejecutar:
dig +dnssec sigfail.verteiltesysteme.net
obteníamos:
;; communications error to 192.168.1.18#53: timed out
...
;; SERVER: 192.168.1.1#53 (el router)
La consulta funcionaba sin +dnssec (respuesta inmediata desde Pi-hole), pero al pedir validación DNSSEC, el cliente se quedaba sin respuesta de Pi-hole y recurría al router, que sí devolvía SERVFAIL (porque también valida DNSSEC). Esto enmascaraba el problema real: Pi-hole no estaba respondiendo a tiempo.
Causa raíz
Presencia del router como DNS secundario en /etc/resolv.conf:
Al tener nameserver 192.168.1.1 como fallback, el sistema operativo, al no obtener respuesta de Pi-hole en el primer intento, acude al router, que responde rápidamente. Esto hacía que pareciera que «funcionaba» (porque se veía el SERVFAIL correcto), pero en realidad no estábamos usando nuestro propio Unbound para validar DNSSEC, sino el router.
Solución, eliminar el router como DNS secundario
Para asegurar que todas las consultas pasen por nuestro Pi-hole, es buena práctica dejar únicamente la IP de Pi-hole en /etc/resolv.conf (o configurar el DHCP del router para que entregue solo esa IP). Así, si Pi-hole falla, el sistema no tendrá un fallback y el error será evidente, pero en condiciones normales todas las consultas usarán nuestro propio resolver.
A continuación expongo 3 formas de hacer esto:
1. De forma gráfica.
Solo tienes que hacer clic derecho sobre el icono de red en la esquina superior derecha de la pantalla (el que parece dos monitores o unas barras de WiFi) y seleccionar «Wireless & Wired Network Settings» o una opción similar. Allí se abrirá una ventana para configurar tu conexión de red.
Para asegurarte de que los cambios son permanentes y no se sobrescriben, lo más fiable es usar el editor gráfico de conexiones de NetworkManager. Para ello, en lugar de la opción anterior, haz clic en «Advanced Options» y luego en «Edit Connections…». Se abrirá la ventana «Network Connections».

Aquí verás una lista de tus conexiones (por ejemplo, «Wired connection 1» para Ethernet o tu red WiFi). Selecciona la que estés usando y haz clic en el botón «Edit» (o «Configurar»). En la nueva ventana, ve a la pestaña «IPv4 Settings» (o «Ajustes IPv4»).
En esta pestaña, cambia el «Method» (Método) de Automatic (DHCP) a «Manual». Ahora se habilitarán los campos para que introduzcas tu configuración:
- Address (Dirección): La IP fija de tu Raspberry Pi (ej.
192.168.1.18). - Netmask (Máscara de red): Normalmente
255.255.255.0. - Gateway (Puerta de enlace): La IP de tu router (ej.
192.168.1.1). - DNS servers (Servidores DNS): Aquí es donde pones
127.0.0.1.
Finalmente, haz clic en «Save» (Guardar) y luego cierra las ventanas. Para que los cambios surtan efecto, puedes reiniciar la interfaz de red o, simplemente, reiniciar la Raspberry Pi.

Luego reiniciamos Pi-hole:
sudo systemctl restart pihole-FTL
2. Desde la terminal.(usando nmcli)
1. Identifica tu conexión de red
sudo nmcli connection show
Anota el nombre de tu conexión activa (ej. eth0, Wired connection 1).
2. Ignora los DNS entregados por DHCP
sudo nmcli connection modify "eth0" ipv4.ignore-auto-dns yes
3. Asigna 127.0.0.1 como único DNS
sudo nmcli connection modify "eth0" ipv4.dns "127.0.0.1"
4. Aplica los cambios
sudo nmcli connection up "eth0"
5. Verifica que se ha aplicado
cat /etc/resolv.conf
Debe mostrar únicamente:
nameserver 127.0.0.1
3. Alternativa: nmtui (Interfaz gráfica en terminal)
Si no tienes el escritorio completo pero sí una interfaz de texto, puedes usar nmtui:
- Ejecuta
sudo nmtui edit "Wired connection 1"(cambia el nombre de la conexión si es necesario). - Navega con las flechas del teclado hasta «IPv4 CONFIGURATION» y cámbialo de
<Automatic>a<Manual>. - Selecciona
<Show>para ver los campos y rellénalos con tu IP, puerta de enlace y el DNS127.0.0.1. - Guarda los cambios y reinicia NetworkManager con
sudo systemctl restart NetworkManager.
Es un método igual de válido, pero a través de la línea de comandos y con una interfaz más amigable que nmcli puro.
Verificación final
Tras aplicar los cambios:
~ $ dig +dnssec sigfail.verteiltesysteme.net
; <<>> DiG 9.20.23-1~deb13u1-Debian <<>> +dnssec sigfail.verteiltesysteme.net
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 42460
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 1232
;; QUESTION SECTION:
;sigfail.verteiltesysteme.net. IN A
;; Query time: 772 msec
;; SERVER: 127.0.0.1#53(127.0.0.1) (UDP)
;; WHEN: Fri Jun 26 20:10:10 CEST 2026
;; MSG SIZE rcvd: 57
Resultado correcto:
- Sin mensajes de timeout.
SERVER: 192.168.1.18#53(nuestro Pi-hole).status: SERVFAILconEDE: 6 (DNSSEC Bogus).
Y para un dominio válido:
dig +dnssec +time=10 dnssec.works
status: NOERRORflags: qr rd ra ad(banderaad= Authentic Data, validación DNSSEC correcta).
Conclusión
Conclusión sobre el fichero resolv.conf:
- Nunca pongas un DNS externo (ni el router) como secundario en la máquina que ejecuta Pi-hole.
- La mejor práctica es fijar
127.0.0.1como único nameserver. - Usa
nmcli(osystemd-resolvedsi lo prefieres) para que los cambios sean permanentes. - Verifica que ningún otro servicio sobrescriba el fichero.
Esta simple corrección cierra la puerta a fugas de privacidad y garantiza que todas las consultas de tu servidor pasen por tu propio filtro y resolver DNSSEC.
¡Disfruta de una navegación más privada y segura!