Presentamos PostScale -- API de correo para envíos transaccionales, recepción y direcciones enmascaradas. PostScale

    DNS Multi-Proveedor con Terraform y DNSControl

    Despliega zonas DNS en DNScale y Hetzner DNS para redundancia usando Terraform o DNSControl.

    Ejecutar tu DNS a través de un solo proveedor significa un solo punto de fallo. Si ese proveedor se cae — ya sea por una interrupción, un ataque DDoS o una mala configuración — tus dominios quedan inaccesibles. El DNS multi-proveedor elimina ese riesgo sirviendo la misma zona desde dos proveedores independientes simultáneamente.

    Esta guía recorre la configuración de DNScale y Hetzner DNS como proveedores duales usando Terraform o DNSControl. Ambas herramientas te permiten definir registros una vez y enviarlos a ambos proveedores, manteniendo todo sincronizado sin duplicación manual.

    Por qué DNS multi-proveedor

    DNS es la base de todo servicio de Internet que ejecutas. Una interrupción del proveedor no solo significa que tu sitio web es inaccesible — significa que el correo deja de fluir, las APIs se vuelven inaccesibles y los servicios que dependen de registros SRV o TXT se rompen.

    El DNS multi-proveedor funciona delegando tu dominio a servidores de nombres de ambos proveedores. Los resolvers en todo el mundo consultarán el conjunto de servidores de nombres que responda, así que si un proveedor está caído, el otro sigue sirviendo respuestas.

    ¿Cuándo tiene sentido el multi-proveedor?

    • Dominios de producción donde el tiempo de inactividad tiene un costo real
    • Entornos de cumplimiento que requieren redundancia
    • Servicios globales donde la cobertura del proveedor varía por región

    ¿Cuándo es excesivo? Para dominios de desarrollo, herramientas internas o dominios donde unos minutos de inactividad son aceptables, un solo proveedor con buen uptime generalmente es suficiente.

    Cómo funciona

    El concepto es directo:

    1. Define tus registros una vez en Terraform o DNSControl
    2. Envía registros idénticos a DNScale y Hetzner DNS
    3. Configura los registros NS en tu registrador apuntando a servidores de nombres de ambos proveedores
    4. Los resolvers consultan cualquier proveedor — el que responda primero gana
    ┌──────────────┐
    │   Registrador│
    │              │
    │ Registros NS:│
    │  ns1.dnscale │
    │  ns2.dnscale │
    │  hydrogen.ns │  ← Hetzner
    │  oxygen.ns   │  ← Hetzner
    └──────┬───────┘
    
    
    ┌──────────────┐     ┌──────────────┐
    │   DNScale    │     │  Hetzner DNS
    │              │     │              │
    │ example.com  │     │ example.com  │
    A, MX, TXT  │     │  A, MX, TXT
    │ (idénticos)  │     │ (idénticos)  │
    └──────────────┘     └──────────────┘
           ▲                    ▲
           │    ┌──────────┐    │
           └────│ Resolver │────┘
                └──────────┘
            Consulta cualquiera

    Ambos proveedores tienen los mismos registros. Tu herramienta de IaC es la única fuente de verdad, y ambos proveedores son simplemente espejos de esa verdad.

    Requisitos previos

    Necesitarás:

    1. Una cuenta de DNScale con una clave API — Obtener tu clave API
    2. Una cuenta de Hetzner DNS con un token API — Hetzner DNS Console
    3. Terraform (v1.0+) o DNSControl (v4.0+) instalados
    4. Un dominio que controles con acceso para configurar registros NS en el registrador

    Terraform: Configuración multi-proveedor

    Terraform hace que el DNS multi-proveedor sea limpio con su soporte nativo para múltiples proveedores y bucles for_each. Defines tus registros una vez en un bloque locals y los creas en ambos proveedores.

    Configuración de proveedores

    # providers.tf
    terraform {
      required_providers {
        dnscale = {
          source  = "dnscaleou/dnscale"
          version = "~> 1.0"
        }
        hetznerdns = {
          source  = "timohirt/hetznerdns"
          version = "~> 2.2"
        }
      }
    }
     
    provider "dnscale" {
      api_key = var.dnscale_api_key
    }
     
    provider "hetznerdns" {
      apitoken = var.hetzner_dns_token
    }
    # variables.tf
    variable "dnscale_api_key" {
      description = "DNScale API key"
      type        = string
      sensitive   = true
    }
     
    variable "hetzner_dns_token" {
      description = "Hetzner DNS API token"
      type        = string
      sensitive   = true
    }
     
    variable "domain" {
      description = "Domain to manage"
      type        = string
      default     = "example.com"
    }

    Definir registros una vez

    La clave del DNS multi-proveedor con Terraform es definir tus registros en un solo lugar. Usa locals para crear un conjunto de registros compartido:

    # records.tf
    locals {
      dns_records = {
        # Registros A
        "root-a" = {
          name  = "@"
          type  = "A"
          value = "203.0.113.10"
          ttl   = 3600
        }
        "www-a" = {
          name  = "www"
          type  = "CNAME"
          value = "example.com."
          ttl   = 3600
        }
        # Correo
        "mx-primary" = {
          name     = "@"
          type     = "MX"
          value    = "mail.example.com."
          ttl      = 3600
          priority = 10
        }
        "mail-a" = {
          name  = "mail"
          type  = "A"
          value = "203.0.113.20"
          ttl   = 3600
        }
        # SPF
        "spf" = {
          name  = "@"
          type  = "TXT"
          value = "v=spf1 mx -all"
          ttl   = 3600
        }
        # IPv6
        "root-aaaa" = {
          name  = "@"
          type  = "AAAA"
          value = "2001:db8::1"
          ttl   = 3600
        }
      }
    }

    Crear en ambos proveedores

    # dnscale.tf
    resource "dnscale_zone" "primary" {
      name = var.domain
    }
     
    resource "dnscale_record" "all" {
      for_each = local.dns_records
     
      zone_id  = dnscale_zone.primary.id
      name     = each.value.name
      type     = each.value.type
      content  = each.value.value
      ttl      = each.value.ttl
      priority = lookup(each.value, "priority", null)
    }
    # hetzner.tf
    resource "hetznerdns_zone" "secondary" {
      name = var.domain
      ttl  = 3600
    }
     
    resource "hetznerdns_record" "all" {
      for_each = local.dns_records
     
      zone_id = hetznerdns_zone.secondary.id
      name    = each.value.name
      type    = each.value.type
      value   = each.value.value
      ttl     = each.value.ttl
    }

    Para registros MX en Hetzner DNS, la prioridad generalmente se incluye en el campo value (por ejemplo, "10 mail.example.com."). Puede que necesites ajustar el formato dependiendo de la versión del proveedor. Consulta la documentación del proveedor Terraform de Hetzner DNS para detalles específicos.

    Aplicar

    export TF_VAR_dnscale_api_key="your-dnscale-key"
    export TF_VAR_hetzner_dns_token="your-hetzner-token"
     
    terraform init
    terraform plan    # Revisar cambios para ambos proveedores
    terraform apply   # Enviar a ambos simultáneamente

    Terraform crea recursos en ambos proveedores en paralelo, así que un solo apply actualiza todo. Para una inmersión más profunda sobre el proveedor de DNScale específicamente, consulta la guía del proveedor Terraform.

    DNSControl: Configuración multi-proveedor

    DNSControl tiene soporte nativo multi-proveedor integrado. Puedes adjuntar múltiples proveedores DNS a un solo dominio, y DNSControl envía registros idénticos a todos ellos en un solo comando.

    Credenciales

    // creds.json
    {
      "dnscale": {
        "TYPE": "DNSCALE",
        "api_key": "your-dnscale-key"
      },
      "hetzner": {
        "TYPE": "HETZNER",
        "api_token": "your-hetzner-token"
      }
    }

    Mantén creds.json fuera del control de versiones:

    echo "creds.json" >> .gitignore

    Configuración

    La función DnsProvider() de DNSControl acepta múltiples proveedores para un solo dominio. Los registros se envían automáticamente a todos los proveedores adjuntos:

    // dnsconfig.js
    var REG_NONE = NewRegistrar("none");
    var DSP_DNSCALE = NewDnsProvider("dnscale");
    var DSP_HETZNER = NewDnsProvider("hetzner");
     
    D("example.com", REG_NONE,
      DnsProvider(DSP_DNSCALE),
      DnsProvider(DSP_HETZNER),
     
      // Registros A
      A("@", "203.0.113.10", TTL(3600)),
      A("mail", "203.0.113.20", TTL(3600)),
     
      // IPv6
      AAAA("@", "2001:db8::1", TTL(3600)),
     
      // CNAME
      CNAME("www", "example.com.", TTL(3600)),
     
      // Correo
      MX("@", 10, "mail.example.com.", TTL(3600)),
     
      // SPF
      TXT("@", "v=spf1 mx -all", TTL(3600)),
     
    END);

    Eso es todo. Ambos proveedores están listados en el mismo dominio, y DNSControl se encarga del resto.

    Previsualizar y aplicar

    # Ver qué cambiaría en ambos proveedores
    dnscontrol preview
     
    # Aplicar cambios a ambos proveedores
    dnscontrol push

    La salida de preview muestra los cambios por proveedor, para que puedas verificar que tanto DNScale como Hetzner recibirán los registros correctos antes de aplicar.

    Para más detalles sobre DNSControl con DNScale, consulta la guía de DNSControl.

    Mantener los registros sincronizados

    El mayor riesgo con el DNS multi-proveedor es la divergencia — registros que se dessincronizan entre proveedores. Tu herramienta de IaC resuelve esto al ser la única fuente de verdad.

    IaC como fuente de verdad

    Nunca edites registros directamente en los paneles de DNScale o Hetzner. Todos los cambios pasan por tu configuración de Terraform o DNSControl. Esto asegura que ambos proveedores siempre tengan registros idénticos.

    Pipeline CI/CD

    Automatiza los despliegues para que los registros se envíen a ambos proveedores en cada merge a main:

    # .github/workflows/dns.yml
    name: DNS Deploy
    on:
      push:
        branches: [main]
        paths: ["dns/**"]
     
    jobs:
      deploy:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v4
     
          - name: Setup Terraform
            uses: hashicorp/setup-terraform@v3
     
          - name: Apply DNS changes
            working-directory: dns/
            env:
              TF_VAR_dnscale_api_key: ${{ secrets.DNSCALE_API_KEY }}
              TF_VAR_hetzner_dns_token: ${{ secrets.HETZNER_DNS_TOKEN }}
            run: |
              terraform init
              terraform apply -auto-approve

    Detección de divergencia

    Ejecuta verificaciones periódicas para detectar cambios manuales o inconsistencias de API:

    # Terraform: detectar divergencia
    terraform plan -detailed-exitcode
    # Código de salida 2 significa divergencia detectada
     
    # DNSControl: preview mostrará cualquier diferencia
    dnscontrol preview

    Programa esto en CI (por ejemplo, un cron job diario) y alerta ante diferencias inesperadas.

    Delegación NS en tu registrador

    Después de desplegar registros en ambos proveedores, actualiza los registros NS en tu registrador de dominio para incluir servidores de nombres de DNScale y Hetzner.

    Un conjunto NS típico se ve así:

    ns1.dnscale.eu
    ns2.dnscale.eu
    hydrogen.ns.hetzner.com
    oxygen.ns.hetzner.com
    helium.ns.hetzner.de

    Los nombres exactos de servidores de nombres de DNScale dependen de tu cuenta. Verifica los detalles de tu zona en el panel de DNScale para los servidores de nombres asignados.

    Configura todos estos como registros NS en tu registrador. La mayoría de los registradores permiten agregar tantos servidores de nombres como necesites.

    Verificar delegación

    Después de actualizar los registros NS (permite hasta 48 horas para la propagación), verifica con:

    dig NS example.com +short

    Deberías ver servidores de nombres de ambos proveedores en la respuesta. También puedes verificar que cada proveedor responde correctamente:

    # Consultar DNScale directamente
    dig @ns1.dnscale.eu example.com A +short
     
    # Consultar Hetzner directamente
    dig @hydrogen.ns.hetzner.com example.com A +short

    Ambos deberían devolver la misma dirección IP.

    Limitaciones y consideraciones

    DNSSEC

    DNSSEC multi-proveedor es complejo. Cada proveedor firma la zona con sus propias claves, así que necesitas:

    • Que ambos proveedores soporten DNSSEC multi-firmante (RFC 8901) — no es ampliamente soportado aún
    • Que un proveedor sea el firmante y transfiera zonas firmadas al otro
    • Omitir DNSSEC en zonas multi-proveedor hasta que mejore el soporte multi-firmante

    Para la mayoría de las configuraciones, omitir DNSSEC en zonas multi-proveedor es la opción pragmática. Si DNSSEC es un requisito obligatorio, considera usar un solo proveedor con garantías sólidas de uptime. Consulta la guía de DNSSEC para configuración DNSSEC de un solo proveedor.

    Alineación de TTL

    Mantén los TTLs idénticos en ambos proveedores. TTLs diferentes significan que los resolvers almacenan en caché los registros por duraciones distintas dependiendo de qué proveedor consultaron, lo que lleva a comportamiento inconsistente.

    Retrasos de propagación

    Cuando aplicas cambios, ambos proveedores los procesan independientemente. Hay una breve ventana (generalmente segundos, a veces minutos) donde un proveedor tiene los registros nuevos y el otro aún sirve los antiguos. Para la mayoría de los casos de uso esto es aceptable — solo evita hacer cambios que se romperían si se aplican parcialmente.

    Tipos de registros específicos del proveedor

    Limítate a tipos de registros estándar que ambos proveedores soporten: A, AAAA, CNAME, MX, TXT, SRV, CAA, NS. Las extensiones específicas del proveedor o tipos de registros propietarios no serán portables.

    Próximos pasos