Usar Cloudflare como DDNS

Publicado

Detallo los pasos que seguí para poder tener un dominio de Cloudflare apuntando a la direccion de mi Raspberry Pi.

El plan consiste en ejecutar un script de manera programada, cada cierto tiempo, que se encargue de averiguar la IP actual de la conexion a internet, la compare con la IP asignada al DNS, y en caso de ser distintas ese mismo script se encargude de actualizar la IP a través de un request a la API de Cloudflare.

Conseguir la IP pública actual

Para esto encontré básicamente 2 métodos, el primero es usando curl o wget, y el segundo es usando dig.

Ejemplos con el comando curl:

curl --silent http://whatismyip.akamai.com/
curl --silent https://api.ipify.org

Ejemplo con el comando dig

dig @resolver1.opendns.com ANY myip.opendns.com +short

Usando como referencia la información que encontré en Stack Overflow al respecto, la diferencia entre curl/wget y dig es que los primeros funcionan a nivel HTTP, mientras que el último funciona a nivel de DNS, lo que lo hace más rápido y también más confiable.

Actualizar IP de Cloudflare a través de la API

Cloudflare provee una API desde la que se pueden hacer de forma automática muchas de las tareas de administración, sin pasar por su dashboard. También proveen una documentación bastante detallada de su uso.

Conseguir API_KEY

Para poder usar la API de Cloudflare necesitamos autenticarnos, y para eso necesitamos una API KEY de nuestra cuenta. La conseguimos desde dash.cloudflare.com/profile, abajo de todo.

Conseguir ZONE_ID

Otro dato que necesitamos es el Zone ID. En Cloudflare las “zones” son cada uno de los dominios que tenemos cargados en la cuenta. Para obtener el Zone ID entramos al dashboard del dominio, y abajo de todo a la derecha, en la sección API encontramos el dato que necesitamos.

Conseguir DNS_RECORD_ID

El último dato que necesitamos es el ID del DNS Record. Cada uno de los parametros que definimos para un dominio es un DNS Record. Para poder conseguir el dato que necesitamos vamos a tener que hacerlo a través de la API.

curl -s GET "https://api.cloudflare.com/client/v4/zones/<ZONE_ID>/dns_records" \
  -H "Content-Type:application/json" \
  -H "X-Auth-Key:<API_KEY>" \
  -H "X-Auth-Email:<AUTH_EMAIL>"

https://api.cloudflare.com/#dns-records-for-a-zone-list-dns-records

Actualizar DNS Record

Desde endpoint de cloudflare correspondiente

https://api.cloudflare.com/#dns-records-for-a-zone-update-dns-record

PUT zones/:zone_identifier/dns_records/:identifier

Juntar todo en un script

El script de forma básica lo que hace es obtener la IP actual, y compararla con una IP anterior (si es que existe) y en el caso de que sean iguales se detiene ahi, sin hacer ningun trabajo extra.

Ahora si las IPs son distintas, actualiza el valor de Cloudflare con el valor de la nueva IP, y guarda esa nueva IP de forma local.

#/usr/bin/env sh

AUTH_EMAIL=
API_KEY=
DNS_ZONE_ID=
DNS_RECORD_ID=
DOMAIN_NAME=
IP_FILE="/tmp/public-ip.txt"
LOG_FILE="/tmp/cloudflare-response.json"

# Get previous IP address
_PREV_IP=$(cat $IP_FILE &> /dev/null)
_CURRENT_IP=$(curl --silent https://api.ipify.org)

# If new/previous IPs match, no need for an update.
if [ "$_CURRENT_IP" = "$_PREV_IP" ]; then
    exit 0
fi

_UPDATE_JSON=$(cat <<EOF
{ "type": "A",
  "name": "$DOMAIN_NAME",
  "content": "$_CURRENT_IP",
  "ttl": 1,
  "proxied": false }
EOF
)

curl "https://api.cloudflare.com/client/v4/zones/$DNS_ZONE_ID/dns_records/$DNS_RECORD_ID" \
  --silent \
  -X PUT \
  -H "Content-Type: application/json" \
  -H "X-Auth-Email: $AUTH_EMAIL" \
  -H "X-Auth-Key: $API_KEY" \
  -d "$_UPDATE_JSON" \
  > $LOG_FILE

echo $_CURRENT_IP > $IP_FILE

Ejecutar automáticamente desde CRON

Basta con agregar al crontab

*/2 * * * * /usr/local/bin/cloudflare-ddns-update.sh > /dev/null 2>&1

Conclusión

Este proyecto contaba con el objetivo específico de actualizar Cloudflare, pero cada una de las partes que componen esta solución pueden adaptarse para distintos proyectos, o distintos proveedores.

Fuentes: