# Automatización de la configuración DNS en Linux con Bash: Un enfoque dinámico y adaptable

- Link: https://binariocero.com/linux/automatizacion-de-la-configuracion-dns-en-linux-con-bash-un-enfoque-dinamico-y-adaptable
- Published: 2025-08-10T13:30:41+02:00
- Author: Juan José Fernández Durán

![Loading](https://binariocero.com/wp-content/plugins/page-views-count/ajax-loader-
2x.gif)

En entornos corporativos o de laboratorio, configurar correctamente los servidores
DNS es una tarea crítica que puede variar según el sistema operativo, el gestor 
de red en uso y la forma en que se administra el archivo `resolv.conf`. Para facilitar
esta labor, presentamos un **script Bash robusto y automatizado** que adapta la 
configuración DNS a diferentes entornos Linux, detectando dinámicamente el método
de resolución DNS en uso.

## Objetivo del script

El objetivo principal es **automatizar la configuración de servidores DNS** en sistemas
Linux, contemplando los siguientes escenarios:

 * Sistemas que utilizan **`systemd-resolved`**
 * Sistemas gestionados por **NetworkManager**
 * Configuraciones manuales tradicionales (modificación directa de `/etc/resolv.
   conf`)

## Características principales

 * Soporte para entornos **Debian, Ubuntu, CentOS, RHEL**, y derivados.
 * Autodetección del método de resolución DNS activo.
 * Registro detallado en un fichero de log (`/var/log/dns_config_auto.log`).
 * Configuración segura y persistente del archivo `/etc/resolv.conf`.
 * Capacidad de ser invocado con variables de entorno (`DNS_SERVERS`) para personalizar
   los servidores DNS.

    ```wp-block-code
    #!/bin/bash

    set -e

    # === Variables de entorno o argumentos ===
    DNS_SERVERS=(${DNS_SERVERS:-"1.1.1.1" "8.8.8.8"})
    LOGFILE="/var/log/dns_config_auto.log"

    # === Función de log ===
    log() {
        local MSG="$1"
        echo "$(date '+%Y-%m-%d %H:%M:%S') - $MSG" | tee -a "$LOGFILE"
    }

    # === Requiere root ===
    check_root() {
        if [[ $EUID -ne 0 ]]; then
            log "Acceso denegado. Este script debe ejecutarse como root."
            exit 1
        fi
    }

    # === Detectar sistema operativo ===
    detect_os() {
        if [[ -f /etc/os-release ]]; then
            . /etc/os-release
            OS_ID=$ID
            OS_VERSION=$VERSION_ID
            log "Sistema detectado: $OS_ID $OS_VERSION"
        else
            log "No se pudo detectar el sistema operativo."
            exit 1
        fi
    }

    # === Detectar gestor de DNS activo ===
    detect_dns_method() {
        if systemctl is-active --quiet systemd-resolved; then
            DNS_METHOD="systemd-resolved"
        elif systemctl is-active --quiet NetworkManager; then
            if grep -q "dns=" /etc/NetworkManager/NetworkManager.conf /etc/NetworkManager/conf.d/* 2>/dev/null | grep -q "dns=none"; then
                DNS_METHOD="manual"
            else
                DNS_METHOD="networkmanager"
            fi
        else
            DNS_METHOD="manual"
        fi
        log "Método de resolución DNS detectado: $DNS_METHOD"
    }

    # === Configurar systemd-resolved ===
    configure_systemd_resolved() {
        log "Configurando systemd-resolved..."

        # Crear archivo /etc/systemd/resolved.conf
        {
            echo "[Resolve]"
            for dns in "${DNS_SERVERS[@]}"; do
                echo "DNS=$dns"
            done
            echo "FallbackDNS=1.1.1.1 8.8.8.8"
        } > /etc/systemd/resolved.conf

        systemctl restart systemd-resolved
        log "systemd-resolved configurado y reiniciado."
    }

    # === Configurar NetworkManager ===
    configure_networkmanager() {
        log "Configurando DNS en NetworkManager..."

        mkdir -p /etc/NetworkManager/conf.d
        echo -e "[main]\ndns=none" > /etc/NetworkManager/conf.d/dns.conf

        configure_resolv_conf

        systemctl restart NetworkManager
        log "NetworkManager reiniciado."
    }

    # === Configurar /etc/resolv.conf manualmente ===
    configure_resolv_conf() {
        log "Configurando /etc/resolv.conf manualmente..."

        # Eliminar symlink si existe
        if [[ -L /etc/resolv.conf ]]; then
            log "Eliminando enlace simbólico en /etc/resolv.conf"
            rm -f /etc/resolv.conf
        fi

        : > /etc/resolv.conf
        for dns in "${DNS_SERVERS[@]}"; do
            echo "nameserver $dns" >> /etc/resolv.conf
        done
        chmod 644 /etc/resolv.conf

        log "Contenido final de /etc/resolv.conf:"
        cat /etc/resolv.conf | tee -a "$LOGFILE"
    }

    # === Programa principal ===
    main() {
        check_root
        detect_os
        detect_dns_method

        case "$DNS_METHOD" in
            systemd-resolved)
                configure_systemd_resolved
                ;;
            networkmanager)
                configure_networkmanager
                ;;
            manual)
                configure_resolv_conf
                ;;
            *)
                log "Método DNS no reconocido: $DNS_METHOD"
                exit 1
                ;;
        esac

        log "Configuración de DNS completada."
        log "SUCCESS"
    }

    main
    ```

## Análisis del flujo del script

### 1. Validación de permisos de ejecución

    ```wp-block-preformatted
    check_root() {    if [[ $EUID -ne 0 ]]; then        log "Acceso denegado. Este script debe ejecutarse como root."        exit 1    fi}
    ```

Este chequeo inicial garantiza que el script se ejecuta con privilegios de superusuario,
condición indispensable para modificar configuraciones de red y archivos del sistema.

### 2. Detección del sistema operativo

    ```wp-block-preformatted
    detect_os() {    if [[ -f /etc/os-release ]]; then        . /etc/os-release        OS_ID=$ID        OS_VERSION=$VERSION_ID    ...}
    ```

Aunque el script no utiliza directamente `OS_ID` y `OS_VERSION`, deja sentadas las
bases para adaptar comportamientos en función de la distribución, si se requiere
en futuras ampliaciones.

### 3. Detección del método de resolución DNS

    ```wp-block-preformatted
    detect_dns_method() {    ...}
    ```

Este bloque detecta si el sistema utiliza:

 * `systemd-resolved`
 * `NetworkManager`
 * Configuración **manual** (por descarte)

Incluso contempla si NetworkManager está configurado con `dns=none`, forzando el
método manual.

### 4. Configuración por método

#### a. **Systemd-resolved**

    ```wp-block-preformatted
    configure_systemd_resolved()
    ```

Se crea/modifica el archivo `/etc/systemd/resolved.conf` y se establece un conjunto
de DNS principales y de respaldo (`FallbackDNS`), reiniciando luego el servicio.

#### b. **NetworkManager**

    ```wp-block-preformatted
    configure_networkmanager()
    ```

Desactiva el control de DNS de NetworkManager (`dns=none`), lo cual implica que 
se gestionará de forma externa. Luego invoca `configure_resolv_conf` y reinicia 
el servicio.

#### c. **Manual**

    ```wp-block-preformatted
    configure_resolv_conf()
    ```

Este método elimina cualquier enlace simbólico en `/etc/resolv.conf` (muy común 
si se usa `systemd-resolved`) y escribe directamente las direcciones de los servidores
DNS proporcionados.

## Personalización vía variables de entorno

Puedes ejecutar el script con una lista personalizada de servidores DNS sin modificarlo:

    ```wp-block-preformatted
    DNS_SERVERS=("9.9.9.9" "149.112.112.112") ./dns_config.sh
    ```

## Registro de operaciones

El script genera un **log detallado** en:

    ```wp-block-preformatted
    /var/log/dns_config_auto.log
    ```

Este log permite auditar la operación completa, incluyendo la configuración final
de `/etc/resolv.conf`.

## Conclusión

Este script ofrece una solución **flexible, portable y mantenible** para la configuración
de servidores DNS en entornos heterogéneos. Su enfoque autodetectable lo hace ideal
para su integración en sistemas de aprovisionamiento automático, como scripts de
post-instalación, playbooks de Ansible o políticas de configuración en herramientas
como Puppet o NinjaOne.

## Recomendaciones adicionales

 * Incluir validación de formato IP para los servidores DNS proporcionados.
 * Incorporar soporte para entornos sin `systemd` o con gestores alternativos (ej.`
   netplan`).
 * Adaptar el script para contenedores o entornos WSL si se requiere.
