← Blog

Alexis · 2026-10-12

DNS de Cloudflare: la capa omnipresente de la infraestructura global de internet

Si el internet tradicional es un vasto sistema de cables físicos y centros de datos, Cloudflare es el sistema operativo inteligente construido sobre él. Gestiona la seguridad, el enrutamiento del tráfico, el rendimiento y el cómputo en el borde global. Hoy en día es prácticamente imposible evitarlo — la mayoría de los servidores web que gestiono están expuestos primero a través del DNS de Cloudflare, y se benefician de inmediato de sus capacidades de seguridad y rendimiento.

La gestión del DNS en Cloudflare puede hacerse manualmente, y así era exactamente como gestionaba todos mis dominios hasta este artículo.

Preparar un entorno shell IaC

Primero, en NixOS, habilitar cf-terraforming y terraform. Esto puede ser lento ya que parece requerir compilación, al menos en mi máquina NixOS.

{ pkgs ? import <nixpkgs> { config.allowUnfree = true; } }:

pkgs.mkShell {
  buildInputs = with pkgs; [
    pkgs.terraform
    pkgs.cf-terraforming
  ];
  shellHook = ''
    echo "Cloudflare IaC environment loaded!"
  '';
}

Una opción más rápida es obtener el script directamente

Exportar la configuración DNS de Cloudflare e inicializar Terraform

Clonar el repositorio e inicializar el espacio de trabajo de Terraform:

    terraform init

Luego exportar la configuración DNS de Cloudflare:

    sh ./exportZones.sh

Dos cosas ocurrirán:

A continuación se muestra el contenido del script exportZones.sh:

#!/bin/sh

if [ -f ".env.local" ]; then
    CLOUDFLARE_API_TOKEN=$(grep -E '^CLOUDFLARE_API_TOKEN=' .env.local | cut -d '=' -f 2- | tr -d '"' | tr -d "'")
    CLOUDFLARE_ACCOUNT_ID=$(grep -E '^CLOUDFLARE_ACCOUNT_ID=' .env.local | cut -d '=' -f 2- | tr -d '"' | tr -d "'")
    echo "Loaded API token from .env.local"
fi

if [ -z "$CLOUDFLARE_API_TOKEN" ]; then
    echo "ERROR: CLOUDFLARE_API_TOKEN is missing from .env.local and environment." >&2
    exit 1
fi

if [ -z "$CLOUDFLARE_ACCOUNT_ID" ]; then
    echo "ERROR: CLOUDFLARE_ACCOUNT_ID is missing from .env.local and environment." >&2
    exit 1
fi

export CLOUDFLARE_API_TOKEN
export CLOUDFLARE_ACCOUNT_ID

echo "1. Generating zones file..."
cf-terraforming generate --resource-type cloudflare_zone > zones.tf

echo "1.1. Generating root-level zone imports..."
awk '
    /resource "cloudflare_zone"/ {
        if (match($0, /terraform_managed_resource_[a-f0-9]{32}_[0-9]+/)) {
            resource_name = substr($0, RSTART, RLENGTH)
            token = substr($0, RSTART + 27, RLENGTH - 27)
            split(token, parts, "_")
            zone_id = parts[1]

            print "import {"
            print "  to = cloudflare_zone." resource_name
            print "  id = \"" zone_id "\""
            print "}"
            print ""
        }
    }
' "zones.tf" > "import_zones.tf"

echo "2. Processing zones and exporting DNS records to root..."

awk '
  /resource "cloudflare_zone"/ {
    if (match($0, /terraform_managed_resource_[a-f0-9]+/)) {
      id = substr($0, RSTART + 27, RLENGTH - 27)
    }
  }
  /^[ \t]*zone[ \t]*=/ {
    if (match($0, /"[^"]+"/)) {
      domain = substr($0, RSTART + 1, RLENGTH - 2)
    }
    if (id != "" && domain != "") {
      print id "|" domain
      id = ""
      domain = ""
    }
  }
' "zones.tf" | while IFS='|' read -r zone_id domain_name; do
    if [ -n "$zone_id" ] && [ -n "$domain_name" ]; then
        DNS_FILE="dns_${domain_name}.tf"
        IMPORTS_FILE="import_dns_${domain_name}.tf"
        
        echo "Exporting DNS for: $domain_name -> $DNS_FILE"
        CLOUDFLARE_ACCOUNT_ID="" cf-terraforming generate --resource-type cloudflare_record --zone "$zone_id" > "$DNS_FILE"

        echo "Calculating imports for $domain_name (Zone ID: $zone_id)"
        awk -v zid="$zone_id" '
            /resource "cloudflare_record"/ {
                if (match($0, /terraform_managed_resource_[a-f0-9]{32}_[0-9]+/)) {
                  resource_name = substr($0, RSTART, RLENGTH)
                  token = substr($0, RSTART + 27, RLENGTH - 27)
                  split(token, parts, "_")
                  rec_id = parts[1]

                  print "import {"
                  print "  to = cloudflare_record." resource_name
                  print "  id = \"" zid "/" rec_id "\""
                  print "}"
                  print ""
                }
            }
        ' "$DNS_FILE" > "$IMPORTS_FILE"
    fi
done

echo "Done! Zones, import_zones.tf, and individual dns/import files are saved at the root."

Revisa los archivos de zonas y el export de DNS.

El repositorio debería verse así — los archivos de importación y el estado no se versionan:

.
├── backend.tf --> Optional: your backend configuration
├── domains --> The domains you configure in your Cloudflare account
│   ├── dns_alcanzatuproposito.com.tf
│   ├── dns_comunidadsana.com.tf
│   ├── dns_emely.es.tf 
│   ├── dns_jugandoalacomidita.com.tf
│   ├── dns_miespazio.pe.tf
│   └── versions.tf
├── exportZones.sh
├── LICENSE
├── modules.tf
├── README.md
├── shell.nix
├── versions.tf
└── zones.tf --> Zone files

Verificar que Terraform funciona correctamente tras el export

  terraform plan -out "plan.tfplan" 

Hemos exportado los imports, las zonas y los archivos DNS desde Cloudflare. Como los formatos de lectura y escritura difieren ligeramente, Terraform planificará con imports y cambios, pero sin adiciones ni eliminaciones.

...
Plan: 41 to import, 0 to add, 36 to change, 0 to destroy.

Saved the plan to: plan.tfplan
...

Ahora ejecuta apply para persistir el estado en tu backend:

  terraform apply "plan.tfplan"

Tras esto, ejecutar terraform plan debería mostrar:

No changes. Your infrastructure matches the configuration.

Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.

Esto te permite gestionar tu configuración DNS, planificar y aplicar cambios mediante Terraform, o conectar una GitHub Action para desplegar tu configuración DNS de forma automática. En el próximo artículo, veré cómo gestionar el estado de Terraform usando Forgejo Packages y configurar un backend de Terraform para enlazarlo.

Stack

Cloudflare · Terraform · Git