Recientemente tuve la necesidad de apuntar un dominio a la red de mi casa, pues muchas veces me conecto remotamente a mi servidor bastión y salto entre servidores dentro de mi red para tareas de mantenimiento y otras cosas.
Como mi proveedor de internet, Cableonda, ofrece internet (miserable por el precio) a través de IP dinámica, pensé en pedir una IP estática, pues de este modo apuntaba el dominio a la IP y no tenía que hacer más nada. Comentando esto a soporte de ellos, me indican que tiene un costo de 10$ mensuales adicionales a la facturación. Así que después de considerar un aumento de 120$ anuales + ITBMS, pensé que sería mejor utilizar un servicio de DNS dinámico, pues al fin y al cabo, existen varios gratuitos.
Investigando me topé un montón de guías, al final termine eligiendo un proceso mucho más simple. Un script bash.
Primero creamos el nombre de dominio que necesitamos en el tablero de DigitalOcean en Manage > Networking > el dominio que deseamos. Y añadimos el registro.
Si hacemos ping
al dominio luego de crearlo con esos datos, tendremos una respuesta así:
1 2 3 4 5 | usuario@host:~$ ping home.dominio.com PING home.dominio.com (192.168.1.1) 56(84) bytes of data. 64 bytes from USG (192.168.1.1): icmp_seq=1 ttl=64 time=0.210 ms 64 bytes from USG (192.168.1.1): icmp_seq=2 ttl=64 time=0.280 ms 64 bytes from USG (192.168.1.1): icmp_seq=3 ttl=64 time=0.257 ms |
Ahora necesitamos nuestro token personal de la APIv2 de DigitalOcean. Vamos a nuestro Dashboard y luego a Manage > API.
Una vez hemos hecho el proceso y copiado el token personal, estamos listos para el script. Podemos verlo aquí. Solo clonamos el repositorio.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | #!/usr/bin/env bash [ ! -f ./secrets ] && \ echo 'secrets file is missing!' && \ exit 1 source ./secrets # Exit if the RECORD_IDS array has no elements [ ${#RECORD_IDS[@]} -eq 0 ] && \ echo 'RECORD_IDS are missing!' && \ exit 1 public_ip=$(curl -s http://checkip.amazonaws.com/) for ID in "${RECORD_IDS[@]}"; do local_ip=$( curl \ --fail \ --silent \ -X GET \ -H "Content-Type: application/json" \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ "https://api.digitalocean.com/v2/domains/${DOMAIN}/records/${ID}" | \ grep -Eo '"data":".*?"' | \ grep -Eo '\d+\.\d+\.\d+\.\d+' ) # if the IPs are the same just exit [ "$local_ip" == "$public_ip" ] && exit 0 # --fail silently on server errors curl \ --fail \ --silent \ --output /dev/null \ -X PUT \ -H "Content-Type: application/json" \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ -d "{"data": "${public_ip}"}" \ "https://api.digitalocean.com/v2/domains/${DOMAIN}/records/${ID}" done |
Añadimos nuestro token personal en el archivo secrets
en la línea ACCESS_TOKEN
y el dominio del cual vamos a editar el registro en DOMAIN
. Le damos permiso de ejecución a los scripts.
1 2 | $ chmod +x update-dns.sh $ chmod +x get-dns.sh |
Solo nos falta el RECORD_ID, el cual lo podemos obtener con el script get-dns.sh
:
1 | $ ./get-dns.sh |
Obtendremos una respuesta parecida a esta:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | { "domain_records": [ { "id": 28448429, "type": "NS", "name": "@", "data": "ns1.digitalocean.com", "priority": null, "port": null, "ttl": 1800, "weight": null, "flags": null, "tag": null }, { "id": 28448430, "type": "NS", "name": "@", "data": "ns2.digitalocean.com", "priority": null, "port": null, "ttl": 1800, "weight": null, "flags": null, "tag": null }, { "id": 28448431, "type": "NS", "name": "@", "data": "ns3.digitalocean.com", "priority": null, "port": null, "ttl": 1800, "weight": null, "flags": null, "tag": null }, { "id": 28448432, "type": "A", "name": "home", "data": "192.168.1.1", "priority": null, "port": null, "ttl": 1800, "weight": null, "flags": null, "tag": null } ], "links": { }, "meta": { "total": 4 } } |
Ahora el registro que vamos a editar tiene como ID, 28448432 como se ve en la línea 40. Este es el dato que añadiremos al archivo secrets
. Ahora podremos ejecutar el script:
1 | $ ./update-dns.sh |
Inmediatamente en el tablero de DigitalOcean, en el dominio veremos la actualización.
Y si hacemos ping al dominio, veremos la respuesta siempre y cuando ya se haya propagado, cosa que podría tardar de algunos minutos a horas.
1 2 3 4 5 | usuario@host:~$ ping home.dominio.com PING home.dominio.com (190.219.162.100) 56(84) bytes of data. 64 bytes from 190.219.162.109 (190.219.162.100): icmp_seq=1 ttl=64 time=0.595 ms 64 bytes from 190.219.162.109 (190.219.162.100): icmp_seq=2 ttl=64 time=0.582 ms 64 bytes from 190.219.162.109 (190.219.162.100): icmp_seq=3 ttl=64 time=0.597 ms |
Por último, tengo dos opciones. Añadirlo al USG y ejecutarlo con cron o utilizarlo en el bastión del mismo modo ejecutado por cron. Editamos nuestro crontab con crontab -e
y añadimos esta línea.
1 | 0 * * * * /home/usuario/scripts/update-dns.sh > /dev/null 2>&1 |
De manera tal que el actualizador de DNS se ejecuta cada hora a la hora en punto.
Si deseamos saber si ha ejecutado la tarea, después de unas horas, verificamos el archivo /var/log/syslog
1 | $ sudo cat /var/log/syslog | grep CRON |
Y tendremos una salida como esta, dependiendo de cuantas veces se haya ejecutado la tarea:
1 2 3 4 | Feb 20 13:00:01 host CRON[23912]: (user) CMD (/home/user/scripts/update-dns.sh > /dev/null 2>&1) Feb 20 14:00:01 host CRON[30157]: (user) CMD (/home/user/scripts/update-dns.sh > /dev/null 2>&1) Feb 20 15:00:01 host CRON[7474]: (user) CMD (/home/user/scripts/update-dns.sh > /dev/null 2>&1) Feb 20 16:00:01 host CRON[6428]: (user) CMD (/home/user/scripts/update-dns.sh > /dev/null 2>&1) |
En conclusión, tengo un subdominio que apunta a mi red en casa con su ip actualizada cuando hay un cambio y realiza comprobaciones cada hora. Muy útil para evitar pagar de más por una ip fija.
@linkmoises
[…] había estado usando un script para actualizar mediante una tarea cron la IP de un registro A de un nombre de dominio de manera […]