Si tienes un servidor en casa o detrás de una conexión con IP dinámica, sabes que tarde o temprano tu dirección IP pública cambia y tu dominio deja de apuntar a tu equipo. En esta entrada explico cómo resolverlo con OVH usando su API compatible con DynDNS y un pequeño script en Bash que se ejecuta desde cron: comprueba tu IP pública, la compara con la que tiene el DNS y solo envía la actualización cuando es necesario.
1. Qué necesitas en OVH antes de empezar
- Un dominio gestionado en OVH (por ejemplo,
tudominio.com). - Activar el servicio DynHost en el panel de OVH: Web Cloud → Dominios → tu dominio → Zona DNS → DynHost.
- Crear unas credenciales DynHost (un identificador y una contraseña). El identificador suele tener el formato
tudominio.com-dyndns. Anótalas: las necesitarás en el script. - Crear el registro DynHost (un registro A de tipo dinámico) para el subdominio que quieras actualizar, por ejemplo
mihost.tudominio.com.
Con esto, OVH expone un endpoint compatible con el protocolo DynDNS2 que permite actualizar la IP del registro mediante una simple petición HTTPS.
2. La API de actualización de OVH
El endpoint es:
https://dns.eu.ovhapis.com/nic/update?system=dyndns&hostname=HOST&myip=IPParámetros:
| Parámetro | Descripción |
|---|---|
system=dyndns | Protocolo DynDNS2 (fijo). |
hostname | Nombre completo del registro a actualizar, p. ej. mihost.tudominio.com. |
myip | Nueva dirección IP pública que se quiere asignar. |
La autenticación se envía en la propia URL (método usuario:contraseña delante del dominio). Las respuestas habituales son:
good <IP>→ actualización realizada correctamente.nochg <IP>→ la IP enviada ya coincide con la registrada; no hubo cambio.badauth→ credenciales incorrectas.abuse→ bloqueo temporal por abuso (demasiadas peticiones).
3. Requisitos en el servidor
bash,curly herramientas básicas (awk,tail,date).dig(paquetednsutils); si no está disponible, el script usagetentautomáticamente.cronpara la ejecución periódica.
4. El script completo
Guarda el siguiente contenido como update_ipv4.sh. Solo tienes que adaptar las variables HOSTNAME y UPDATE_URL con tu host y tus credenciales de OVH:
#!/bin/bash
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
HOSTNAME="mihost.tudominio.com"
UPDATE_URL="https://tudominio.com-dyndns:TU_TOKEN_SECRETO@dns.eu.ovhapis.com/nic/update"
LOG_FILE="$SCRIPT_DIR/update_ipv4.log"
IP_HISTORY_FILE="$SCRIPT_DIR/ip_history.log"
LAST_UPDATE_FILE="$SCRIPT_DIR/last_update"
FORCE_INTERVAL=21600 # 6 horas
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S') $*" >> "$LOG_FILE"
}
MISSING_DEPS=0
for cmd in curl awk cat tail date readlink; do
if ! command -v "$cmd" >/dev/null 2>&1; then
echo "$(date '+%Y-%m-%d %H:%M:%S') ERROR: dependencia no encontrada: $cmd" >> "$LOG_FILE" 2>/dev/null
MISSING_DEPS=1
fi
done
HAS_DIG=0
HAS_GETENT=0
command -v dig >/dev/null 2>&1 && HAS_DIG=1
command -v getent >/dev/null 2>&1 && HAS_GETENT=1
if [ $HAS_DIG -eq 0 ]; then
if [ $HAS_GETENT -eq 1 ]; then
log "AVISO: dig no disponible, se usara getent para resolver el host"
else
log "ERROR: no hay herramienta para resolver DNS (se necesita dig o getent)"
MISSING_DEPS=1
fi
fi
if [ $MISSING_DEPS -eq 1 ]; then
exit 1
fi
IP=$(curl -s --max-time 10 https://api.ipify.org || curl -s --max-time 10 https://ifconfig.me || curl -s --max-time 10 https://icanhazip.com)
if ! [[ "$IP" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
log "ERROR: no se pudo obtener la IP publica"
exit 1
fi
HOST_IP=""
if [ $HAS_DIG -eq 1 ]; then
HOST_IP=$(dig +short A "$HOSTNAME" 2>/dev/null | grep -m1 -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$')
fi
if [ -z "$HOST_IP" ] && [ $HAS_GETENT -eq 1 ]; then
HOST_IP=$(getent hosts "$HOSTNAME" 2>/dev/null | grep -m1 -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+')
fi
LAST_ASSIGNED_IP=$(tail -n1 "$IP_HISTORY_FILE" 2>/dev/null | awk '{print $NF}')
LAST_UPDATE=$(cat "$LAST_UPDATE_FILE" 2>/dev/null)
[[ "$LAST_UPDATE" =~ ^[0-9]+$ ]] || LAST_UPDATE=0
NOW=$(date +%s)
FORCED=0
if [ $((NOW - LAST_UPDATE)) -ge $FORCE_INTERVAL ]; then
FORCED=1
fi
if [ "$IP" = "$LAST_ASSIGNED_IP" ] && [ "$IP" = "$HOST_IP" ] && [ $FORCED -eq 0 ]; then
log "OMITIDO: IP=$IP sin cambios (host=$HOST_IP, ultima_asignada=$LAST_ASSIGNED_IP)"
exit 0
fi
if [ $FORCED -eq 1 ]; then
MOTIVO="actualizacion forzada cada 6h"
else
MOTIVO="cambio detectado (host=$HOST_IP, ultima_asignada=$LAST_ASSIGNED_IP)"
fi
RESPONSE=$(curl -s --max-time 15 "${UPDATE_URL}?system=dyndns&hostname=${HOSTNAME}&myip=${IP}")
CURL_EXIT=$?
if [ $CURL_EXIT -ne 0 ]; then
log "ERROR: curl fallo con codigo $CURL_EXIT ($MOTIVO)"
exit 1
fi
case "$RESPONSE" in
good*|nochg*)
echo "$(date '+%Y-%m-%d %H:%M:%S') $IP" >> "$IP_HISTORY_FILE"
echo "$NOW" > "$LAST_UPDATE_FILE"
log "ACTUALIZADO: IP=$IP RESPUESTA=$RESPONSE ($MOTIVO)"
;;
*)
log "ERROR: respuesta inesperada='$RESPONSE' IP=$IP ($MOTIVO)"
exit 1
;;
esacDale permisos de ejecución y restringe el acceso, ya que el fichero contiene tus credenciales:
chmod 700 update_ipv4.sh5. Cómo funciona
- Verifica dependencias: comprueba que
curly las herramientas necesarias existen; si faltadig, usagetentcomo alternativa. Si falta algo crítico, anota el error en el log y sale. - Obtiene tu IP pública consultando varios servicios externos en cascada (
api.ipify.org,ifconfig.me,icanhazip.com) para no depender de uno solo. - Resuelve tu hostname con
digpara saber qué IP tiene el DNS actualmente. - Lee el estado local: la última IP asignada (fichero
ip_history.log) y el momento de la última actualización enviada (ficherolast_updatecon un timestamp Unix). - Decide:
- Si la IP pública coincide con la última asignada y con la del DNS, y no han pasado 6 horas, no envía nada (registro
OMITIDO). - Si hay discrepancia, envía la actualización (registro
ACTUALIZADO). - Independientemente de lo anterior, cada 6 horas fuerza una actualización como medida de seguridad.
- Si la IP pública coincide con la última asignada y con la del DNS, y no han pasado 6 horas, no envía nada (registro
- Envía la petición con
curly solo actualiza el estado local si OVH respondegoodonochg; en caso contrario registra el error para reintentar en la siguiente ejecución.
6. Ficheros generados
| Fichero | Contenido |
|---|---|
update_ipv4.log | Log de ejecuciones: ACTUALIZADO, OMITIDO, AVISO y ERROR. |
ip_history.log | Histórico de IPs asignadas con fecha. |
last_update | Timestamp de la última petición enviada (para la regla de las 6 horas). |
Ejemplo de log:
2026-01-15 10:59:37 ACTUALIZADO: IP=203.0.113.42 RESPUESTA=good 203.0.113.42 (cambio detectado (host=198.51.100.7, ultima_asignada=198.51.100.7))
2026-01-15 11:10:01 OMITIDO: IP=203.0.113.42 sin cambios (host=203.0.113.42, ultima_asignada=203.0.113.42)7. Programación con cron
Edita el crontab del usuario y añade una ejecución periódica; por ejemplo, cada 10 minutos:
crontab -e*/10 * * * * /ruta/a/update_ipv4.shNo te preocupes por la frecuencia: el propio script evita enviar peticiones innecesarias, así que ejecutarlo a menudo no satura la API de OVH.
8. Resolución de problemas
| Síntoma | Causa probable | Solución |
|---|---|---|
badauth | Credenciales DynHost incorrectas. | Revisar identificador y contraseña en el panel de OVH. |
abuse | Bloqueo por exceso de peticiones. | Esperar y reducir la frecuencia de actualización. |
ERROR: no se pudo obtener la IP publica | Sin salida a internet o servicios caídos. | Comprobar conectividad con curl -s https://api.ipify.org. |
| El host no resuelve la IP nueva | Propagación DNS o caché. | Esperar unos minutos y verificar con dig +short mihost.tudominio.com. |
| El cron no ejecuta el script | Rutas relativas o falta de permisos. | Usar rutas absolutas en el crontab y chmod 700. |
9. Nota de seguridad
El script contiene las credenciales DynHost en la variable UPDATE_URL. Mantén el fichero con permisos restrictivos (chmod 700), no lo subas a repositorios públicos y, si compartes el código (como en esta entrada), sustituye siempre tu dominio y tus credenciales por marcadores genéricos.
Con esto tendrás tu subdominio de OVH apuntando siempre a tu IP pública actual, sin dependencias externas ni clientes de DynDNS de terceros: solo bash, curl y cron.
No hay comentarios:
Publicar un comentario