Usar Cloudflare como servicio de dns dinámico gratuito

  • 28 Ene 2020
  • DNS, Cloudflare, Linux

La gente de Cloudflare Inc. ofrece un servicio de DNS increiblemente fantástico. En su plan gratuito brinda los siguiente 3 servicios: 

  • DDoS attack mitigation
  • Global Content Delivery Network
  • Support via email

En este artículo no les voy a hablar de ninguno de estos. Si no, de lo bien que esta gente pensó en como ofrecer sus servicios. Cada una de las cosas que puedan configurarse a través de la interfaz web, pueden hacerse también a través de una API. Esto quiere decir que cuando por ejemplo configuramos la dirección IP dentro un DNS de tipo A, la misma configuración podrá realizarse a través de la API. A su vez, esto quiere decir que con un script en PHP podemos pedirle favores a la API que muy contenta trabajará para satisfacer nuestros caprichos. Que pueden ser tantos, pero en este capítulo voy a tratar el de actualizar una o varias configurciones de un dominio con una dirección IP dinámica.

Ingredientes

  • Un dominio
  • Una cuenta en Cloudflare
  • Un servidor (Fedora en este caso) conectado a un ISP con IP dinámico

Configurar Cloudflare

Una vez que tenemos la cuenta de Cloudflare, agregamos nuestro dominio. A modo de ejemplo, vamos a suponer que se trata de midominio.com. Bien, nuestro objetivo será crear el subdominio casa y lograr que casa.midominio.com apunte siempre a un determinado lugar donde su conexión a Internet sea con un servcio de dirección IP dinámica.

Una vez que agregamos el dominio, vamos a notar que Cloudflare copia la configuración DNS existente y un segundo después nos invita a modificar los DNS de midominio.com de tal modo que sea ahora Cloudflare quien los administra. Los DNS de Cloudflare, es decir, los DNS de tipo NS que debemos configurar para midominio.com son:

  • DNS1: adi.ns.cloudflare.com
  • DNS2: quinton.ns.cloudflare.com

Bien, ahora volvemos a Cloudflare y agregamos un nuevo registro DNS de tipo A con nombre casa y colocamos la dirección IP de nuestro ISP.

Modificar configuración DNS con un script en PHP

Para que nuestro script funcione vamos a tener que crear un Token. Esto se hace entrando en el dominio, categoría Overview, sección API. Vamos a encontrar un link con el texto Get your API token. Creamos un token con dos permisos:

  • Account Settings:Read
  • Zone:Read, DNS:Edit

Apenas son creados los permisos, Cloudflare nos mostrará un token para ser utilizado en un esquema de autenticación Bearer. Debería verse más o menos así:

curl -X GET "https://api.cloudflare.com/client/v4/zones/cd7d0123e3012345da9420df9514dad0" \
-H "Content-Type:application/json" \
-H "Authorization: Bearer 1234567893feefc5f0q5000bfo0c38d90bbeb"

Ahora sí, vamos a nuestro servidor, el mismo que navega con un dirección IP pública dinámica, y creamos un achivo. Por ejemplo: /opt/midominio.com-updater.php. La misión de este script será muy simple: Comparar la configuración del dominio con la dirección IP pública y si no son iguales, modificar la configuración del dominio con la nueva dirección IP. Este es el código:

<?php
$headers = [
    'Authorization: Bearer ****************************************',
    'Content-Type: application/json'
];

$domain = "midominio.com";
$record = array("casa.midominio.com");
$ip = file_get_contents('https://api.ipify.org');

$ch = curl_init();

// get zone id
curl_setopt($ch, CURLOPT_URL, "https://api.cloudflare.com/client/v4/zones?name=$domain");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$result = curl_exec($ch);
if (curl_errno($ch)) {
    exit('Error: ' . curl_error($ch));
}
curl_close ($ch);

$json = json_decode($result, true);

$ZoneID = $json['result']['0']['id'];


for ($n = 0;$n < count($record); $n++) {

  $data = [
      'type' => 'A',
      'name' => $record[$n],
      'content' => $ip,
      'ttl' => 1,
      'proxied' => true
  ];

	$ch = curl_init();

	curl_setopt($ch, CURLOPT_URL, "https://api.cloudflare.com/client/v4/zones/$ZoneID/dns_records?name=$record[$n]");
	curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
	curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

	$result = curl_exec($ch);
	if (curl_errno($ch)) {
	    exit('Error: ' . curl_error($ch));
	}
	curl_close ($ch);

	$json = json_decode($result, true);

	$DNSID = $json['result']['0']['id'];

	$old_ip = $json['result']['0']['content'];

  echo "Working with: $record[$n]" . PHP_EOL;

	if ($old_ip === $ip) {
	    echo "Cloudflare IP: $old_ip" . PHP_EOL;
	    echo "Current IP: $ip" . PHP_EOL;
	    echo "The IP doesn't have to be changed!" . PHP_EOL;
	}
	else {
	    echo "Cloudflare IP: $old_ip" . PHP_EOL;
	    echo "Current IP: $ip" . PHP_EOL;
	    echo "The IP has to be changed!" . PHP_EOL;
	    $ch = curl_init();

	    curl_setopt($ch, CURLOPT_URL, "https://api.cloudflare.com/client/v4/zones/$ZoneID/dns_records/$DNSID");
	    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
	    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
	    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
	    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

	    $result = curl_exec($ch);
	    if (curl_errno($ch)) {
		exit('Error: ' . curl_error($ch));
	    }
	    echo "The IP has changed from $old_ip to $ip!" . PHP_EOL;
	}
}

Las variables a configurar son el token para la autenticación en $header, el dominio en $domain y el record DNS en $record. Esta última es un array para que sea simple modificar más de un record que apunten al mismo servidor.

Correr un script cada x minutos en segundo plano en Fedora

Ahora que tenemos el script, necesitariamos correrlo cada x minutos, digamos 5. Para ello, vamos a crear un archivo en /etc/systemd/system/midominio.com-updater.service con el siguiente código:

[Unit]
Description=Update midominio.com to current IP if needed

[Service]
Type=oneshot
ExecStart=/usr/bin/php /opt/midominio.com-updater.php

Ahora, necesitamos otro archivo en /etc/systemd/system/midominio.com-updater.timer

[Unit]
Description=Update midominio.com entry in Cloudflare every 5 minutes

[Timer]
# Time to wait after booting before we run first time
OnBootSec=5min
# Time between running each consecutive time
OnUnitActiveSec=5m
Unit=midominio.com-updater.service

[Install]
WantedBy=timers.target

Por último arrancamos el timer y habilitamos el servicio para que se ejecute al arranque del sistema.

systemctl start midominio.com-updater.timer
systemctl enable midominio.com-updater.timer

Enlaces externos