Unbound puede actuar como resolvedor recursivo con caché para un servidor Ubuntu: consulta la jerarquía DNS, conserva las respuestas durante su TTL y valida firmas DNSSEC antes de entregar los datos.

En esta guía, systemd-resolved mantiene el stub local de Ubuntu en 127.0.0.53:53, mientras que Unbound escucha en 127.0.0.1:5335. Esta separación evita que ambos servicios compitan por el puerto 53 y permite que las aplicaciones continúen utilizando la resolución normal del sistema.

Resultado esperado: las aplicaciones consultarán a systemd-resolved; este enviará las consultas DNS unicast a Unbound; las respuestas firmadas válidas serán aceptadas y un dominio deliberadamente roto por DNSSEC devolverá SERVFAIL.

Qué resuelve y qué no

Unbound realizará:

  • Recursión desde los servidores raíz hasta los servidores autoritativos.
  • Caché de respuestas respetando sus TTL.
  • Validación DNSSEC mediante el trust anchor de la raíz.
  • Minimización de QNAME para reducir la información enviada durante la recursión.

DNSSEC autentica la procedencia y la integridad de los datos DNS. No cifra las consultas ni oculta las direcciones de los servidores consultados.

Esta guía tampoco configura DNS-over-TLS, DNS-over-HTTPS, bloqueo publicitario ni zonas DNS autoritativas.

Requisitos previos

  • Ubuntu Server 24.04 LTS o compatible.
  • Acceso mediante sudo.
  • Una consola alternativa abierta durante el cambio.
  • Conectividad saliente UDP y TCP hacia el puerto 53.
  • Reloj sincronizado.
  • Backup de la configuración DNS actual.
  • Herramientas dig, resolvectl, ss y journalctl.
  • Para atender una LAN: IP privada fija, CIDR autorizado y firewall configurable.
Seguridad: el procedimiento principal escucha exclusivamente en loopback. No uses interface: 0.0.0.0 ni abras UDP/TCP 53 hacia Internet. Un resolvedor recursivo abierto puede utilizarse en ataques de amplificación.

Paso 1: inventariar la configuración actual

Registra el reloj, la resolución activa y los puertos ocupados:

date -u
timedatectl status
timedatectl show -p NTPSynchronized

resolvectl status
readlink -f /etc/resolv.conf
cat /etc/resolv.conf

sudo ss -lntup | grep -E ':(53|5335)\b' || true

dig @127.0.0.53 example.com A +stats

En Ubuntu 24.04 es habitual que /etc/resolv.conf apunte a /run/systemd/resolve/stub-resolv.conf y que systemd-resolved escuche en 127.0.0.53:53.

No reemplaces ese enlace ni desactives systemd-resolved como primera opción.

Revisa también los DNS asignados a cada interfaz:

resolvectl dns
resolvectl domain

Los servidores recibidos por DHCP, Netplan o una VPN podrían competir posteriormente con la ruta global.

Paso 2: instalar Unbound y crear un backup

Instala el servicio, la utilidad de trust anchors y las herramientas DNS:

sudo apt update
sudo apt install unbound unbound-anchor dnsutils

unbound -V
unbound-checkconf -h | head

En Ubuntu 24.04, unbound-anchor se distribuye como paquete independiente. Instalarlo explícitamente evita que la recuperación del trust anchor falle con command not found. Paquete oficial de Ubuntu.

El paquete puede iniciar Unbound automáticamente. Comprueba de nuevo los listeners antes de continuar.

Crea un backup privado:

STAMP=$(date -u +%Y%m%dT%H%M%SZ)
BACKUP_DIR="$HOME/unbound-backup-$STAMP"
install -d -m 0700 "$BACKUP_DIR"

sudo cp -a /etc/unbound "$BACKUP_DIR/"
sudo cp -a /etc/systemd/resolved.conf "$BACKUP_DIR/"

if [ -d /etc/systemd/resolved.conf.d ]; then
  sudo cp -a /etc/systemd/resolved.conf.d "$BACKUP_DIR/"
fi

readlink -f /etc/resolv.conf \
  > "$BACKUP_DIR/resolv-conf-target.txt"

sudo chown -R "$USER":"$USER" "$BACKUP_DIR"

printf '%s\n' "$BACKUP_DIR" \
  > "$HOME/.unbound-backup-last"

chmod 0600 "$HOME/.unbound-backup-last"

El archivo ~/.unbound-backup-last conserva la ruta seleccionada y permite recuperarla después de una desconexión o en otra sesión.

El backup contiene configuración, pero no garantiza el acceso a la red del proveedor. Mantén abierta una consola alternativa durante el cambio.

Paso 3: comprobar el trust anchor

Los paquetes Debian y Ubuntu suelen incluir un archivo dentro de /etc/unbound/unbound.conf.d/ que declara:

auto-trust-anchor-file: "/var/lib/unbound/root.key"

Comprueba primero la configuración instalada:

sudo grep -RnsE \
  '^[[:space:]]*(auto-)?trust-anchor-file:' \
  /etc/unbound/unbound.conf \
  /etc/unbound/unbound.conf.d \
  2>/dev/null || true

sudo -u unbound test -r /var/lib/unbound/root.key
sudo -u unbound test -w /var/lib/unbound/root.key
sudo -u unbound test -w /var/lib/unbound

Unbound debe poder leer y actualizar el archivo y su directorio para realizar el seguimiento definido por RFC 5011.

No declares dos veces auto-trust-anchor-file. La duplicación de trust anchors para la misma zona puede impedir el inicio del servicio.

Si la configuración declara /var/lib/unbound/root.key, pero el archivo no existe, inicialízalo mediante el usuario del servicio:

sudo -u unbound unbound-anchor \
  -a /var/lib/unbound/root.key

ANCHOR_RC=$?

printf 'unbound-anchor exit=%s\n' "$ANCHOR_RC"

En unbound-anchor, el código de salida 1 también puede indicar que el anchor fue instalado o actualizado. No debe interpretarse automáticamente como un fallo: revisa el archivo, sus permisos y ejecuta después unbound-checkconf.

Unbound dispone de root hints internos. No es obligatorio descargar un archivo root.hints. Si decides administrarlo manualmente, deberás verificar su origen y mantenerlo actualizado.

Paso 4: crear la configuración local

Comprueba si IPv6 loopback está disponible:

ip -6 address show dev lo

Crea /etc/unbound/unbound.conf.d/20-local-recursive.conf mediante sudoedit:

server:
    interface: 127.0.0.1@5335
    interface: ::1@5335

    access-control: 127.0.0.0/8 allow
    access-control: ::1/128 allow

    do-udp: yes
    do-tcp: yes

    hide-identity: yes
    hide-version: yes

    qname-minimisation: yes
    aggressive-nsec: yes
    harden-dnssec-stripped: yes
    prefetch: yes

Si IPv6 está deshabilitado y no aparece ::1, omite estas dos líneas:

interface: ::1@5335
access-control: ::1/128 allow

No añadas auto-trust-anchor-file si el paquete ya lo declaró.

Tampoco expongas remote-control mediante una interfaz TCP. El paquete puede proporcionar control local seguro; no hace falta reemplazarlo ni regenerar claves si no utilizarás unbound-control.

La configuración realiza recursión directa. Unbound consultará servidores raíz, TLD y autoritativos mediante UDP o TCP 53.

Paso 5: validar antes de reiniciar

Valida toda la configuración:

sudo unbound-checkconf

Resultado esperado:

unbound-checkconf: no errors in /etc/unbound/unbound.conf

Si aparece un trust anchor duplicado, una ruta inaccesible, una interfaz inexistente o un error de sintaxis, corrígelo antes de modificar systemd-resolved.

Reinicia Unbound:

sudo systemctl restart unbound

sudo systemctl --no-pager --full status unbound
sudo ss -lntup | grep ':5335'

sudo journalctl \
  -u unbound \
  --since '-5 minutes' \
  --no-pager

Durante el recorrido local debe escuchar exclusivamente en:

127.0.0.1:5335
[::1]:5335

Paso 6: probar Unbound directamente

No cambies todavía la resolución del sistema. Prueba primero el nuevo servicio:

dig @127.0.0.1 -p 5335 \
  cloudflare.com A +dnssec +multi

dig @127.0.0.1 -p 5335 \
  cloudflare.com A +dnssec +tcp

dig @127.0.0.1 -p 5335 \
  . DNSKEY +dnssec +multi

Para una respuesta firmada y validada, busca:

status: NOERROR
flags: ... ad ...

La prueba con +tcp confirma que el resolvedor no depende exclusivamente de UDP.

Prueba ahora el dominio deliberadamente roto recomendado por ICANN:

dig @127.0.0.1 -p 5335 \
  dnssec-failed.org A +dnssec

Resultado esperado:

status: SERVFAIL

Para observar la respuesta subyacente desactivando la comprobación únicamente en esa consulta:

dig @127.0.0.1 -p 5335 \
  dnssec-failed.org A +dnssec +cdflag

+cdflag es una herramienta de diagnóstico. No debe convertirse en la configuración habitual de los clientes

Paso 7: integrar systemd-resolved

Ubuntu 24.04 permite especificar un puerto en la opción DNS=. Crea /etc/systemd/resolved.conf.d/60-unbound.conf:

[Resolve]
DNS=127.0.0.1:5335
FallbackDNS=
Domains=~.
DNSSEC=no

DNSSEC=no evita una segunda capa de validación dentro de systemd-resolved. La política de aceptar o rechazar datos ya la aplicará Unbound.

Por este motivo, la bandera ad debe comprobarse directamente contra Unbound. La ruta completa se validará mediante sus resultados y la prueba negativa.

FallbackDNS= vacío elimina los fallbacks compilados, pero no necesariamente los DNS recibidos por DHCP, Netplan o una VPN. Estos servidores pueden continuar asociados a interfaces concretas.

Reinicia el stub y limpia su caché:

sudo systemctl restart systemd-resolved
sudo resolvectl flush-caches

resolvectl status

sudo journalctl \
  -u systemd-resolved \
  --since '-5 minutes' \
  --no-pager

El DNS global debe mostrar:

127.0.0.1:5335

El stub debe continuar disponible para las aplicaciones en 127.0.0.53:53.

Paso 8: probar la ruta completa

Ejecuta:

resolvectl query cloudflare.com
getent ahosts cloudflare.com

dig @127.0.0.53 cloudflare.com A +dnssec
dig @127.0.0.53 dnssec-failed.org A +dnssec

La consulta normal debe resolverse. El dominio deliberadamente inválido debe devolver SERVFAIL.

Si devuelve NOERROR, comprueba en resolvectl status que systemd-resolved no esté enviando la consulta a otro servidor DNS por interfaz o VPN.

Ejecuta dos veces una consulta directa:

dig @127.0.0.1 -p 5335 www.iana.org A +stats
dig @127.0.0.1 -p 5335 www.iana.org A +stats

Una segunda respuesta más rápida y con un TTL inferior es una señal de caché, pero no constituye una medición concluyente. Para evaluar rendimiento, utiliza varias consultas y una carga representativa.

Puerta de aceptación

  • Unbound escucha únicamente en loopback:5335.
  • UDP y TCP responden.
  • El dominio firmado valida correctamente.
  • La prueba DNSSEC bogus devuelve SERVFAIL.
  • resolvectl muestra Unbound como DNS global.
  • getent y las aplicaciones resuelven.
  • No hay errores persistentes en los journals.
  • El reloj permanece sincronizado.

Modo LAN opcional

Para atender clientes de una red privada, añade una dirección que exista realmente en el servidor y el CIDR mínimo necesario:

server:
    interface: 10.0.0.53@53
    access-control: 10.0.0.0/24 allow

Adapta las direcciones a tu red. Antes de reiniciar:

sudo unbound-checkconf
ip address show

Permite UDP y TCP 53 exclusivamente desde el CIDR autorizado en:

  • El firewall del host.
  • El firewall o security group del proveedor.
  • Las ACL intermedias.

Desde un cliente autorizado:

dig @10.0.0.53 cloudflare.com A +dnssec
dig @10.0.0.53 cloudflare.com A +dnssec +tcp
dig @10.0.0.53 dnssec-failed.org A +dnssec

Desde un origen no autorizado, la consulta debe rechazarse o no alcanzar el servicio.

Verifica con ss que Unbound no esté escuchando en una interfaz pública imprevista.

Rollback

Recupera y valida la ruta persistida del backup:

test -s "$HOME/.unbound-backup-last" || {
  printf 'No se encontró la referencia del backup.\n' >&2
  exit 1
}

BACKUP_DIR=$(cat "$HOME/.unbound-backup-last")

test -d "$BACKUP_DIR" || {
  printf 'No existe el backup: %s\n' "$BACKUP_DIR" >&2
  exit 1
}

Revierte primero la ruta del sistema mientras Unbound continúa disponible:

test -f \
  /etc/systemd/resolved.conf.d/60-unbound.conf

sudo mv \
  /etc/systemd/resolved.conf.d/60-unbound.conf \
  "$BACKUP_DIR/60-unbound.conf.disabled"

sudo systemctl restart systemd-resolved
sudo resolvectl flush-caches

resolvectl status
getent ahosts example.com

Confirma que systemd-resolved recuperó los servidores anteriores.

Después puedes retirar la configuración personalizada de Unbound:

test -f \
  /etc/unbound/unbound.conf.d/20-local-recursive.conf

sudo mv \
  /etc/unbound/unbound.conf.d/20-local-recursive.conf \
  "$BACKUP_DIR/20-local-recursive.conf.disabled"

sudo unbound-checkconf
sudo systemctl restart unbound

Si habilitaste el modo LAN, elimina también las reglas UDP/TCP 53 del firewall del host, del firewall perimetral y de las ACL intermedias.

Comprueba desde un origen no autorizado que el servidor ya no responde y revisa los listeners mediante ss.

No modifiques manualmente /etc/resolv.conf mientras continúe gestionado por systemd-resolved.

Problemas frecuentes

Unbound no inicia por el puerto

Ejecuta:

sudo ss -lntup | grep -E ':(53|5335)\b'

Revisa cada dirección, no solo el puerto. 127.0.0.53:53 y 127.0.0.1:5335 no entran en conflicto.

Busca configuraciones adicionales que declaren interface: 0.0.0.0, otra dirección ocupada o el puerto 53.

Aparece un error relacionado con root.key

Comprueba:

  • Que exista un único auto-trust-anchor-file.
  • Que el usuario unbound pueda leer y escribir el archivo.
  • Que pueda actualizar su directorio.
  • Que el reloj esté sincronizado.
  • Que unbound-anchor esté instalado.

No borres ni descargues claves sin comprender primero el mecanismo del paquete.

Las consultas normales funcionan, pero DNSSEC falla

Revisa:

  • Reloj del sistema.
  • Trust anchor.
  • Salida UDP y TCP 53.
  • Fragmentación de red.
  • Journal de Unbound.
  • Consulta directa contra 127.0.0.1:5335.

La consulta directa permite separar un problema de Unbound de uno relacionado con systemd-resolved.

dnssec-failed.org devuelve NOERROR por la ruta del sistema

Es probable que la consulta utilice otro DNS instalado por DHCP, Netplan o una VPN.

Inspecciona:

resolvectl status
resolvectl dns
resolvectl domain

Un dominio sin DNSSEC no presenta la bandera AD

Es un resultado válido. Una zona insegura legítima puede devolver NOERROR sin ad.

DNSSEC distingue entre estados seguro, inseguro y bogus; no exige que todos los dominios estén firmados.

Los clientes LAN no pueden consultar

Comprueba:

  • Dirección de escucha.
  • ACL de Unbound.
  • UDP y TCP 53.
  • Firewall del host.
  • Firewall perimetral.
  • Security groups.
  • Rutas entre cliente y servidor.

No amplíes la ACL a 0.0.0.0/0 para ocultar el problema.

Buenas prácticas

  • Mantén actualizados Unbound, unbound-anchor y dns-root-data.
  • Supervisa SERVFAIL, latencia, consumo, journals y sincronización horaria.
  • Revisa listeners y ACL después de actualizaciones.
  • Prueba UDP, TCP, un dominio firmado y un dominio bogus.
  • Mantén QNAME minimisation, pero no la confundas con cifrado.
  • Evita .local para zonas DNS privadas porque suele reservarse para mDNS.
  • Documenta DNS por interfaz, VPN y rutas ~. antes de modificar Netplan.
  • Conserva una consola alternativa y un rollback verificable.

Conclusión

La configuración estará completa cuando Unbound resuelva de forma recursiva, valide DNSSEC, responda mediante UDP y TCP y permanezca limitado al origen previsto.

La integración con systemd-resolved evita romper el comportamiento habitual de Ubuntu y permite revertir la ruta sin modificar manualmente /etc/resolv.conf.

DNSSEC aporta autenticidad e integridad. La confidencialidad requiere un diseño adicional con transporte cifrado.


Cloud Serversby Donweb

Todo el poder de la nube a tus proyectos y aplicaciones.
Alojamiento ultra rápido, escalable y con alta disponibilidad.

  • Performance que te sorprenderá
  • Rápida escalabilidad y sin limitaciones
  • Arquitectura de alta disponibilidad
  • Soporte experto y ejecutivos de cuenta
  • Pagos en tu moneda y facturación local

Descubre la mejor solución de Cloud Hosting