DD-WRTProbablemente la mayoría de los que lleguen hasta acá sepan que es DynDNS y para que se usa. Básicamente, estamos hablando de un servicio de DDNS que nos permite asignarle un dominio a una dirección IP dinámica, de forma de tener acceso remoto. Hoy en día la mayoría de los modems pueden informar a estos servicios cuando cambia su IP pública, de modo que el dominio siempre apunte a la IP actualizada.

Lo que quizá muchos no se han enterado es que a partir de ahora los usuarios del servicio gratuito tendrán que loguearse por lo menos una vez al mes en la página de DynDNS para que los dominios no se den de baja.  Si, ya se, tampoco es que sea la muerte de nadie, pero ahí esta el cambio.

¿Que hacer entonces? Bueno, hay por lo menos 3 opciones:

  • Loguearse cada mes para que se enteren que seguimos vivos
  • Pagar los 10 dolares por la suscripción Pro. No sean ratones.
  • Utilizar el servicio de otra empresa, como No-IP

Sin embargo, este cambio a mi me inspiro a hacer la nerdada que explico en este post: Crear mi propio servicio de DDNS :mrgreen:

Requisitos

Antes que nada les aclaro que lo que verán aquí es código bien mierdoso, altamente perfeccionable, pero que funciona, seguro alguien con un poco de mayor conocimiento lo pueda mejorar :mrgreen:

Hecha la aclaración, las cosas que se necesitan son:

  • Servidor Linux con IP fija.
  • Servidor web con PHP: Atenderá las peticiones. Puede ser Apache. También se usará el modulo de autentificación básica.
  • Servidor BIND: Es el servidor de DNS. Debiera estar instalado y configurado con algún dominio.
  • Servidor de base de datos: No es realmente necesario, pero si en caso que se quiera hacer todo tal cual lo explico
  • Modem o router adecuado: Tiene que poder notificarle los cambios a servicios personalizados (Yo uso DD-WRT).

Manos a la obra

Para que tengan una idea de como funcionaria esto, seria algo asi:

  1. El modem detecta que cambio su IP y manda una petición al servidor
  2. Apache responde a la petición, y el código PHP ejecutado genera el archivo actualizado para la zona maestra que deberá usar BIND
  3. Un script ejecutado cada 5 minutos detecta la existencia de ese archivo
  4. Si existe, reemplaza el archivo de la zona original, por el nuevo y refresca BIND

Todo lo hice en Debian Wheezy, ojo que la ubicación de los archivos pueden variar en otras distribuciones ;)

Paso 1: Definir la zona maestra que va a contener los registros

En mi caso, a modo de ejemplo, puedo hacer que dyn.imcosta.net sea el dominio que va a contener los registros con direcciones dinamicas. En ese caso podria tener servidor1.dyn.imcosta.net o servidor2.dyn.imcosta.net, cada uno apuntado a la dirección IP que oportunamente informe el modem.

Recomiendo que no mezclen lo que son “registros dinamicos” con otras aplicaciones estaticas como alguna web, porque para darle la utilidad que necesitamos hay que bajarle el TTL a la zona, de modo que los cambios se propaguen rapidamente por Internet. En mi caso poniendo todo lo dinamico dentro de dyn.imcosta.net solo “lo que esta ahi dentro” es cacheado por poco tiempo mientras que los registros dentro de “imcosta.net” no necesariamente, es decir, pueden estar un largo tiempo sin refrescarse en cualquier servidor DNS que ande por ahi suelto porque estos registros no cambian frecuentemente.

Entonces, primero, vamos a configurar BIND para la zona maestra.

Editamos /etc/bind/named.conf.local y le agregamos la nueva zona:

zone "dyn.imcosta.net" {
type master;
file "/var/lib/bind/dyn.imcosta.net.hosts";
};

Como ven esa zona apunta a un archivo. Ya que estamos lo vamos a generar, pero tengan en cuenta que ese archivo será reemplazado cada vez que ocurra un cambio de IP. El archivo debiera contener algo así:

$ttl 300
dyn.imcosta.net.        IN      SOA     servidor.imcosta.net. info.mail.com.ar. (
1368652135
300
3600
604800
300 )
dyn.imcosta.net.        IN      NS      ns1.imcosta.net.
dyn.imcosta.net.        IN      NS      ns2.imcosta.net.

Si se fijan, lo que definimos acá es:

  • TTL: Hablando mal y pronto, todo lo que dice 300. En este caso estos registros son validos por 300 segundos, es decir, 5 minutos.
  • Autoridad de zona: Ahi es “servidor.imcosta.net”. Podria ser algo como www.midominio.com
  • E-Mail del responsable: Donde dice “info.mail.com.ar”. Seria info@mail.com.ar
  • Servidores DNS: Los que se utilicen para la zona. Pongan los suyos, como es lógico deben apuntar a su servidor =P

Paso 2: Generar directorios para Apache

El modem o router informará los cambios de IP por medio de una petición HTTP a nuestro servidor. Para poder atenderla, debemos generar un pequeño archivito PHP que haga la magia ;)

Como es lógico que no queremos que cualquiera cambie las IPs sin autorización, va a ser necesario proteger el archivo, pero mejor aún, lo que hacemos es proteger todo el directorio con .htaccess de modo que se requiera ingresar usuario y contraseña para acceder a lo que contenga.

¿Donde ubicar los archivos? ¿Que dominio usar? Eso depende de cada uno, pueden ponerlo en cualquier lado que sea accesible desde Internet pero asegurense de proteger el directorio. En este caso voy a suponer que tenemos el siguiente directorio /var/www/dyndns/public y que el mismo, lógicamente, se puede acceder desde afuera por HTTP.

Para proteger ese directorio, entramos al mismo y creamos un archivo .htaccess con el siguiente contenido.

AuthUserFile /var/www/dyndns/.htpasswd
AuthName "Usuario"
AuthType Basic
Require valid-user

Ahora creamos el archivo .htpasswd, entonces ejecutamos el siguiente comando:

htpasswd -c /var/www/dyndns/.htpasswd usuario

Siendo usuario el nombre de usuario, y la contraseña la que ingresemos cuando ejecutemos el comando.

Por otra parte vamos a necesitar un directorio donde PHP pueda escribir. Yo creé dentro de /var/www/dyndns/public un nuevo directorio llamado “bind” y le dí un bruto 777 :P

mkdir /var/www/dyndns/public/bind
chmod 777 /var/www/dyndns/public/bind

Paso 3: Crear la base de datos

En mi caso decidí usar una base de datos para guardar una tablita llamada “hosts” que contenga la última IP notificada.

La estructura de la misma es esta:

Estructura - Tabla

Paso 4: Desarrollar la web

El archivo PHP lo que tiene que hacer es:

  1. Fijarse si el host enviado por GET existe en la BD y si no existe lo crea con la dirección IP y vuelve a generar el archivo para BIND.
  2. Si existe verificar si cambio la dirección IP. Si no cambio, no hace nada. Si cambio, actualiza la tabla ingresando la nueva IP y vuelve a generar el archivo de BIND.
  3. Generar el archivo de BIND, para esto toma una plantilla, recorre todos los registros de la BD y va agregandole al final los registros A correspondientes.

Un detalle importante tiene que ver con el SERIAL: Este es un numerito que lleva el archivo de la zona, osea, el que generará el PHP para BIND que indica algo así como “que versión” de registros contiene.De esta manera los demás servidores DNS pueden saber si se cambió algo. Cada vez que se actualiza el archivo, tiene que subir en 1. Para esto podemos usar un registro en la BD o como hice yo, un archivo, donde vayamos registrando el último serial e ir sumándole 1 a medida que generamos una nueva versión. Pueden verlo en el ejemplo.

Entonces, primero que nada, copiamos el archivo de /var/lib/bind/dyn.imcosta.net.hosts al directorio de trabajo. Esta sera la plantilla con lo que arrancarán los archivos de zona generados por el código PHP:

cp /var/lib/bind/dyn.imcosta.net.hosts /var/www/dyndns/template.txt

Luego tomamos el serial del mismo (Es el primer número largo, en este caso 1368652135) y lo guardamos en otro archivo dentro del directorio editable para PHP, en mi caso /var/www/dyndns/public/bind/serial.txt

Hecho esto editamos /var/www/dyndns/template.txt y donde esta el serial le ponemos alguna marca que después reemplazaremos por medio de código por el nuevo serial. Por ejemplo podemos escribirle: “[SERIAL]”

Y por último algo así seria el código PHP que podemos colocar en /var/www/dyndns/public/index.php

$ip = $_SERVER['REMOTE_ADDR'];
$host = $_GET['host'];
 
if($_GET['host'] == "")
die("No se ha indicado el host");
 
$host = str_replace("/", "", $host);
 
//****************************************************************************
 
echo "IP Nueva: " . $ip;
 
$conexion = mysql_connect("localhost", "usuario", "contraseña");
if(!$conexion) die("Error: No se pudo conectar a la BD");
 
mysql_select_db("basedatos", $conexion);
 
$sql = "SELECT * FROM `hosts` WHERE `hostname` = '" .$host .  "'";
 
$result = mysql_query($sql);
 
if(mysql_num_rows($result) == 0)
{
echo "\nRegistrando host nuevo...";
 
//Cargo nuevo host
$sql = "INSERT INTO `basedatos`.`hosts` (`id`, `hostname`, `ip`) VALUES (NULL, '" . $host. "', '" . $ip . "');";
mysql_query($sql);
generarArchivo();
}
else
{
$row = mysql_fetch_array($result);
echo "\nIP Anterior: " . $row['ip'];
 
//Actualizo IP de registro existente
if($row['ip'] != $ip)
{
echo "\nActualizando IP para el host";
$sql = "UPDATE `basedatos`.`hosts` SET `ip` = '" . $ip  . "' WHERE `hosts`.`id` = " . $row['id'] . ";";
mysql_query($sql);
generarArchivo();
}
else
{
echo "\nNo hubo cambios";
}
}
 
echo "\nTrabajo finalizado";
 
function generarArchivo()
{
echo "\nGenerando nuevo archivo";
 
//Leemos los viejos archivos
$plantilla = file_get_contents("../template.txt");
$nextSerial =  file_get_contents("bind/serial.txt") + 1;
 
$plantilla = str_replace("[SERIAL]", $nextSerial, $plantilla);
 
$sql = "SELECT * FROM `hosts`";
$result = mysql_query($sql);
 
while($row = mysql_fetch_array($result))
$plantilla .= "\n". $row['hostname'] . ".dyn.imcosta.net.   IN      A       " . $row['ip'];
 
//Escribimos los nuevos archivos
file_put_contents("bind/bind.conf", $plantilla);
file_put_contents("bind/serial.txt", $nextSerial);
 
echo "\nRealizado... Los cambios deberian reflejarse en un maximo de 5 minutos.";
}

Eso es todo, si hubo cambios se tendria que haber actualizado la BD y tendriamos el archivito bind.conf en el directorio bind, con el serial que indica el archivo serial.txt, y todos los registros que fueron leidos de la base de datos :mrgreen:

Paso 5: Crear el script que verificará los cambios

Ahora lo que tenemos que hacer es generar un script que compruebe si existe el archivo /var/www/dyndns/public/bind/bind.conf, y en tal caso lo mueva a /var/lib/bind/dyn.imcosta.net.hosts (Si ya existe, que lo reemplace sin asco) y le diga a BIND que refresque sus registros.

El script en cuestión lo podemos guardar en /var/www/dyndns/ Yo lo llame dnscron.sh ;)

#!/bin/bash
FILE=/var/www/dyndns/public/bind/bind.conf
 
if [ -f $FILE ];
then
mv $FILE /var/lib/bind/dyn.imcosta.net.hosts
/usr/sbin/rndc reload dyn.imcosta.net
fi

Paso 6: Programar la ejecución del script con cron

Por ultimo hay que configurar CRON para que ejecute el script cada tantos minutos. Yo le puse 5. Para esto tiramos un crontab -e y agregamos:

0,5,10,15,20,25,30,35,40,45,50,55 * * * * /var/www/dyndns/dnscron.sh

 Paso 7: Configurar el modem o router

Acá dependerá del modem que tengamos, pero si usamos DD-WRT la configuración quedaría algo así:

DD-WRT

Listo… cuando cambie la IP el modem llamara al archivo PHP que se encuentre en dyn.imcosta.net logueandose con el usuario y contraseña adecuados, el servidor generará el archivo para BIND con el nuevo serial apuntando servidor1.dyn.imcosta.net a la nueva dirección, y en un maximo de 5 minutos actuará el script de cron, reemplazará el viejo archivo de registros por el nuevo, y refrescará el DNS. De paso ya que estamos, podemos registrar algún CNAME en otra zona que apunte al dominio largo (Por ejemplo, servidor1.imcosta.net apuntando a servidor1.dyn.imcosta.net).

Gualá, Habemus servicio de DDNS. No será tan professhional pero es mio y funciona :mrgreen:

Etiquetas: , , , , , , , , , ,

15 Comentarios


  1. Mexedi on 08 jun 2013

    Hola, Gracias por la Manual, voy a probarla.

  2. […] voy a hacer unos de esos post que como el anterior no interesa a nadie, pero que al menos me sirven como recordatorio para cuando quiera hacer lo […]

  3. carlos aguilar on 27 sep 2013

    Muy bien, justo lo que estaba buscando, ya me tiene hasta el tope el dyndns.
    muchas gracias.

  4. Maldito Nerd on 02 oct 2013

    Me encantó. Se parece mucho el tipo de trabajo que me tomaría si no fuera po ruq es mucho trabajo. Voy a seguir chusmeando tu blog a ver que más hay de interesante y te dejo un tip para el cron cada 5″: */5 * * * *

    Saludos!

  5. Ricardo on 20 nov 2013

    Hola como estas …esta bueno el post te queria consultar esto me serviria para poder crear un servidor y que mis clientes de camaras ip se conecten a este servidor? x lo que entendi es para eso pero quiero que me lo confirmes vos …gracias

    • Miguel on 20 nov 2013

      Claro. Básicamente lo que haces es que desde la dirección de tu dominio siempre se acceda a tu servidor con IP dinamica: Cuando la IP cambia, se avisa que el dominio apunte a la nueva ;)

      • Domingo on 13 oct 2014

        Hola Miguel, eso es lo que necesito per no soy capaz de Instalarlo, serias tan amable de sie quieres instalarmelo

        por que me quedo en la base de datos , como creo eso

        si quieres te paso el usario y contra del servidor aqui.

        los Requisitos estan .

        bueno muchas gracias
        y un saludo desde Alemania

      • Domingo on 13 oct 2014

        Hola Miguel, eso es lo que necesito per no soy capaz de Instalarlo, serias tan amable de sie quieres instalarmelo

        por que me quedo en la base de datos , como creo eso

        si quieres te paso el usario y contra del servidor aqui.

        los Requisitos estan .

        bueno muchas gracias
        y un saludo desde Alemania

  6. Osvaldo on 31 ene 2014

    Muy buena tú solución. 1) Que hacemos si al habilitar el DDNS en nuestro router no permite la opción personalizada ? Es decir solo permite servicios que hoy son pagos ? Ej el Cisco Linksys WRT54G2. 2) En el caso de una PC que debo configuar o instalar ?

    Muchas Gracias

  7. Manuel Manzano on 21 feb 2014

    gracias por el manual, si lo puedo mejorar en lago te aviso, pero muchas gracias, estaba buscando justo esto para implementarlo, ya me canse del dyndns

  8. Pabloss on 19 jul 2014

    muy bueno, no hay una manero de hacer la actualizacion desde una PC … automaticamente sin pasar por un router?

  9. Julio on 14 ene 2015

    Una obra maestra, voy a crear mi servidor, casi seguro qe pida ayuda. Te re agradezco este trabajo. :D
    Pienso usar ubuntu 14, que opinas??

  10. Julio on 14 ene 2015

    Hola, no se si llego mi otro comentario, pero esta genial esto que hiciste, quiero hacerlo sobre ubuntu 14, que opinas??

    Pensé en un soft que actualize la ip e informe al server,(como alternativa a la configuración del router) como hace dyndns con el “dyndns updater” que decis??

  11. Luis Alberto on 19 mar 2015

    Gracias por el aporte. Estaba usando CDMON que presta este servicio, pero ahora es pago. Con esto voy a implementar mi propio DDNS ya que cuento con un DNS.

    Mil Gracias por el aporte.

    Saludos desde Venezuela


Deja tu comentario