--- title: "Cómo instalar y configurar CoreDNS en Ubuntu 24.04" description: "Instala CoreDNS en Ubuntu 24.04 como servicio systemd y configúralo como resolvedor con caché, reenvío por dominio y una zona DNS interna autoritativa." category: "Descubrimiento de Servicios" language: es source: https://cubepath.com/es/docs/descubrimiento-de-servicios/instalacion-y-configuracion-de-coredns updated: 2026-09-25 --- # Cómo instalar y configurar CoreDNS en Ubuntu 24.04 CoreDNS es un servidor DNS escrito en Go cuya funcionalidad se compone mediante plugins declarados en un único fichero, el `Corefile`. Es el DNS predeterminado de Kubernetes, pero también sirve como resolvedor con caché o servidor autoritativo para una red interna. En esta guía instalarás CoreDNS en Ubuntu 24.04 como servicio systemd y lo configurarás como resolvedor con caché para tu red privada, con reenvío por dominio y una zona interna propia. ## Requisitos previos - Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath, con al menos 512 MB de RAM. - Un usuario no root con privilegios `sudo`. - La subred privada desde la que los clientes consultarán el DNS. En los ejemplos se usa `10.0.0.0/8`; sustitúyela por la tuya. - `dig` para las pruebas, incluido en el paquete `dnsutils`: ```bash sudo apt update sudo apt install dnsutils ``` ## Paso 1: Descargar e instalar el binario CoreDNS no está empaquetado en los repositorios de Ubuntu con una versión actual, así que se usa el binario oficial de GitHub. Consulta la última versión en la [página de releases](https://github.com/coredns/coredns/releases) y ajusta la variable si es más nueva que la indicada. Si tu servidor es ARM, cambia `amd64` por `arm64`. ```bash COREDNS_VERSION="1.14.7" cd /tmp curl -LO "https://github.com/coredns/coredns/releases/download/v${COREDNS_VERSION}/coredns_${COREDNS_VERSION}_linux_amd64.tgz" curl -LO "https://github.com/coredns/coredns/releases/download/v${COREDNS_VERSION}/coredns_${COREDNS_VERSION}_linux_amd64.tgz.sha256" ``` Verifica la suma de comprobación antes de instalar nada: ```bash sha256sum -c "coredns_${COREDNS_VERSION}_linux_amd64.tgz.sha256" ``` ```output coredns_1.14.7_linux_amd64.tgz: OK ``` Extrae el binario e instálalo en `/usr/local/bin`: ```bash tar xzf "coredns_${COREDNS_VERSION}_linux_amd64.tgz" sudo install -m 755 coredns /usr/local/bin/coredns coredns -version ``` ```output CoreDNS-1.14.7 ``` La segunda línea de la salida indica la plataforma y la versión de Go con la que se compiló. Puedes listar los plugins compilados en el binario con `coredns -plugins`. ## Paso 2: Crear el usuario y los directorios CoreDNS no necesita ejecutarse como root. Crea un usuario de sistema sin shell y los directorios de configuración y zonas: ```bash sudo useradd --system --no-create-home --shell /usr/sbin/nologin coredns sudo mkdir -p /etc/coredns/zones ``` Los ficheros de `/etc/coredns` pertenecen a root y CoreDNS solo necesita leerlos, así que no hace falta cambiar su propietario. ## Paso 3: Liberar el puerto 53 En Ubuntu 24.04, `systemd-resolved` ejecuta un stub DNS en `127.0.0.53:53` que impide a CoreDNS escuchar en todas las interfaces del puerto 53. Compruébalo: ```bash sudo ss -lunp 'sport = :53' ``` ```output State Recv-Q Send-Q Local Address:Port Peer Address:Port Process UNCONN 0 0 127.0.0.54:53 0.0.0.0:* users:(("systemd-resolve",pid=612,fd=16)) UNCONN 0 0 127.0.0.53%lo:53 0.0.0.0:* users:(("systemd-resolve",pid=612,fd=14)) ``` En lugar de desinstalar `systemd-resolved` (del que dependen otros componentes del sistema), desactiva solo el stub con un fichero drop-in: ```bash sudo mkdir -p /etc/systemd/resolved.conf.d sudo nano /etc/systemd/resolved.conf.d/no-stub.conf ``` ```ini [Resolve] DNSStubListener=no ``` Sin el stub, `/etc/resolv.conf` debe apuntar a la lista real de servidores que gestiona `systemd-resolved`, no a `127.0.0.53`. Cambia el enlace simbólico y reinicia el servicio: ```bash sudo ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf sudo systemctl restart systemd-resolved ``` Comprueba que el puerto 53 está libre (el comando no debe devolver ninguna línea con `:53`) y que el servidor sigue resolviendo nombres: ```bash sudo ss -lunp 'sport = :53' getent hosts ubuntu.com ``` ## Paso 4: Escribir el Corefile El `Corefile` se organiza en bloques de servidor: cada bloque empieza por la zona que atiende (`.` significa "todo lo demás") y contiene los plugins que se aplican. El orden de los plugins dentro del bloque no importa, porque CoreDNS los ejecuta en un orden fijo definido al compilar. Crea el fichero: ```bash sudo nano /etc/coredns/Corefile ``` ```text . { acl { allow net 10.0.0.0/8 127.0.0.0/8 block } forward . 1.1.1.1 9.9.9.9 { health_check 5s } cache 300 errors log . { class denial error } health 127.0.0.1:8080 ready 127.0.0.1:8181 prometheus 127.0.0.1:9153 reload loop } ``` Esto es lo que hace cada plugin: - `acl`: solo responde a la red privada y a localhost; el resto de clientes recibe `REFUSED`. Un resolvedor abierto a Internet se usa para ataques de amplificación DDoS, así que esta línea no es opcional. - `forward`: reenvía las consultas que no puede responder a Cloudflare (`1.1.1.1`) y Quad9 (`9.9.9.9`), comprobando cada 5 segundos si siguen respondiendo. - `cache 300`: guarda las respuestas hasta 300 segundos (o el TTL del registro, si es menor). - `errors` y `log`: registran errores y, para no llenar el journal, solo las consultas que terminan en NXDOMAIN o error. - `health`, `ready` y `prometheus`: endpoints de estado y métricas, limitados a localhost. - `reload`: vuelve a leer el `Corefile` automáticamente cuando cambia (lo comprueba cada 30 segundos). - `loop`: detecta bucles de reenvío y detiene CoreDNS en lugar de saturar la CPU. ## Paso 5: Crear el servicio systemd Crea la unidad de systemd: ```bash sudo nano /etc/systemd/system/coredns.service ``` ```ini [Unit] Description=CoreDNS DNS server Documentation=https://coredns.io After=network-online.target Wants=network-online.target [Service] User=coredns Group=coredns ExecStart=/usr/local/bin/coredns -conf /etc/coredns/Corefile ExecReload=/bin/kill -SIGUSR1 $MAINPID Restart=on-failure AmbientCapabilities=CAP_NET_BIND_SERVICE CapabilityBoundingSet=CAP_NET_BIND_SERVICE NoNewPrivileges=true ProtectSystem=strict ProtectHome=true PrivateTmp=true LimitNOFILE=1048576 [Install] WantedBy=multi-user.target ``` `AmbientCapabilities=CAP_NET_BIND_SERVICE` permite al usuario `coredns` abrir el puerto 53 sin ser root, sin tener que marcar el binario con `setcap` (que habría que repetir en cada actualización). Las opciones `Protect*` impiden que el proceso escriba en el sistema de ficheros. `SIGUSR1` hace que CoreDNS recargue el `Corefile`. Arranca y habilita el servicio: ```bash sudo systemctl daemon-reload sudo systemctl enable --now coredns systemctl status coredns --no-pager ``` ```output ● coredns.service - CoreDNS DNS server Loaded: loaded (/etc/systemd/system/coredns.service; enabled; preset: enabled) Active: active (running) since Thu 2026-09-24 11:02:41 UTC; 3s ago ``` Si el servicio no arranca, `journalctl -u coredns -n 50` muestra el motivo (normalmente un error de sintaxis en el `Corefile` o el puerto 53 ocupado). ## Paso 6: Probar la resolución y la caché Consulta un dominio público a través de CoreDNS: ```bash dig @127.0.0.1 ubuntu.com +noall +answer +stats | grep -E 'IN|Query time' ``` ```output ubuntu.com. 300 IN A 185.125.190.20 ;; Query time: 18 msec ``` Repite la consulta. La segunda respuesta sale de la caché: el tiempo baja a 0 ms y el TTL va disminuyendo: ```output ubuntu.com. 291 IN A 185.125.190.20 ;; Query time: 0 msec ``` Comprueba también los endpoints de estado: ```bash curl -s http://127.0.0.1:8080/health; echo curl -s http://127.0.0.1:8181/ready; echo ``` ```output OK OK ``` ## Paso 7: Añadir una zona interna autoritativa Con el plugin `file`, CoreDNS responde con autoridad para una zona a partir de un fichero en formato estándar (RFC 1035), el mismo que usa BIND. En este ejemplo se usa `corp.internal`: el dominio de nivel superior `.internal` está reservado para uso privado, por lo que nunca chocará con un dominio real. Crea el fichero de zona: ```bash sudo nano /etc/coredns/zones/db.corp.internal ``` ```text $ORIGIN corp.internal. $TTL 300 @ IN SOA ns1.corp.internal. hostmaster.corp.internal. ( 2026092401 ; serial (AAAAMMDDNN) 3600 ; refresh 900 ; retry 604800 ; expire 300 ) ; TTL negativo @ IN NS ns1.corp.internal. ns1 IN A 10.0.0.53 web IN A 10.0.1.10 api IN A 10.0.1.20 db IN A 10.0.1.30 www IN CNAME web.corp.internal. ``` Sustituye `10.0.0.53` por la IP privada de tu servidor CoreDNS y los demás registros por los tuyos. Después, añade un bloque para la zona al final del `Corefile`: ```bash sudo nano /etc/coredns/Corefile ``` ```text corp.internal { acl { allow net 10.0.0.0/8 127.0.0.0/8 block } file /etc/coredns/zones/db.corp.internal { reload 30s } errors } ``` CoreDNS elige siempre el bloque con la zona más específica, así que las consultas a `corp.internal` las atiende este bloque y el resto sigue yendo al bloque `.`. La opción `reload 30s` vuelve a leer el fichero de zona cuando cambia su número de serie, por lo que para publicar cambios basta con editar los registros e incrementar el serial. El plugin `reload` del bloque `.` aplicará el nuevo `Corefile` en unos 30 segundos. Para aplicarlo ya: ```bash sudo systemctl reload coredns ``` Comprueba los registros: ```bash dig @127.0.0.1 web.corp.internal +short dig @127.0.0.1 www.corp.internal +short ``` ```output 10.0.1.10 web.corp.internal. 10.0.1.10 ``` La respuesta debe llevar el indicador `aa` (authoritative answer). Compruébalo con `dig @127.0.0.1 api.corp.internal | grep flags`. ## Paso 8: Reenviar un dominio a otro servidor DNS Es habitual que un dominio concreto lo resuelva otro servidor: un Active Directory, una VPN o el DNS de un clúster. Para eso basta un bloque con su propio `forward`. Por ejemplo, para enviar `ad.example.com` a los controladores de dominio `10.0.5.10` y `10.0.5.11`, añade al `Corefile`: ```text ad.example.com { acl { allow net 10.0.0.0/8 127.0.0.0/8 block } forward . 10.0.5.10 10.0.5.11 cache 60 errors } ``` Recarga con `sudo systemctl reload coredns` y prueba con `dig @127.0.0.1 dc01.ad.example.com`. ### Añadir entradas estáticas con hosts Para unos pocos nombres sueltos no hace falta una zona: el plugin `hosts` acepta entradas en línea con el formato de `/etc/hosts`. Añádelo dentro del bloque `.`: ```text hosts { 10.0.2.50 legacy-app.lan 10.0.2.51 old-db.lan fallthrough } ``` `fallthrough` es importante: sin él, cualquier nombre que no esté en la lista devolvería NXDOMAIN en lugar de pasar a `forward`. ## Paso 9: Abrir el firewall y usar CoreDNS desde los clientes Permite el DNS solo desde la red privada. Sustituye la subred por la tuya: ```bash sudo ufw allow from 10.0.0.0/8 to any port 53 proto udp sudo ufw allow from 10.0.0.0/8 to any port 53 proto tcp ``` No abras los puertos 8080, 8181 y 9153: en esta configuración solo escuchan en localhost. Desde otro servidor de la red privada, sustituye **`coredns_private_ip`** por la IP privada de CoreDNS y comprueba que responde: ```bash dig @coredns_private_ip web.corp.internal +short ``` ```output 10.0.1.10 ``` Para que un cliente Ubuntu use CoreDNS de forma permanente, configura el servidor DNS de su interfaz en Netplan (clave `nameservers.addresses`) y aplica los cambios con `sudo netplan apply`. ## CoreDNS en Kubernetes En Kubernetes, CoreDNS se ejecuta como Deployment en el namespace `kube-system` y su `Corefile` vive en un ConfigMap. Puedes ver la configuración actual con: ```bash kubectl -n kube-system get configmap coredns -o yaml ``` Para reenviar un dominio interno (por ejemplo `corp.internal` hacia el servidor que acabas de montar), edita el ConfigMap y añade un bloque nuevo junto al `.:53` existente, sin tocar este: ```bash kubectl -n kube-system edit configmap coredns ``` ```text corp.internal:53 { errors cache 30 forward . 10.0.0.53 } ``` El `Corefile` predeterminado de Kubernetes incluye el plugin `reload`, así que los pods de CoreDNS aplican el cambio en uno o dos minutos sin reiniciarlos. En clústeres gestionados (por ejemplo, con un addon que reescribe el ConfigMap) consulta la documentación de la distribución, porque tus cambios podrían sobrescribirse. ## Solución de problemas ### Listen: listen tcp :53: bind: address already in use Otro proceso ocupa el puerto 53. Identifícalo con `sudo ss -lntup 'sport = :53'`. Si es `systemd-resolve`, revisa el Paso 3; si es `dnsmasq` o `named`, detenlo y deshabilítalo. ### Loop detected en el journal El plugin `loop` ha detectado que CoreDNS se reenvía consultas a sí mismo. Suele pasar si usas `forward . /etc/resolv.conf` y ese fichero apunta a `127.0.0.1`. Usa servidores upstream explícitos, como en el Paso 4. ### Los clientes reciben REFUSED La IP del cliente no está permitida en el plugin `acl`. Revisa la subred en cada bloque y recarga el servicio. ### Un cambio en el fichero de zona no se aplica El plugin `file` solo recarga la zona si el número de serie del registro SOA aumenta. Increméntalo en cada cambio y consulta `journalctl -u coredns -n 20` para ver si hay errores de sintaxis en la zona. ## Conclusión Tienes CoreDNS funcionando en Ubuntu 24.04 como servicio systemd sin privilegios de root, actuando como resolvedor con caché restringido a tu red privada, con una zona interna autoritativa y reenvío por dominio. Como siguientes pasos, puedes añadir un segundo servidor CoreDNS con la misma configuración para tener redundancia, recoger las métricas del puerto 9153 con Prometheus o cifrar el reenvío hacia los upstream con DNS over TLS (`forward . tls://1.1.1.1` con `tls_servername cloudflare-dns.com`).