Porkbun DDNS — Dynamic DNS para carloselugo.com

Fecha: Abril 2026
Servidor: labmini-01 (Dell Optiplex)
Dominio: carloselugo.com
Ubicación del script: /opt/ddns/ddns_porkbun.sh


Objetivo

Detectar cambios en la IP pública del homelab y actualizar automáticamente los registros DNS en Porkbun — sin depender de un servicio DDNS de terceros.


Arquitectura

cron (cada 30 min)
  → ddns_porkbun.sh
      → obtiene IP pública (api.ipify.org)
      → compara con state file (~/.porkbun-ddns.last-ip)
      → si cambió → Porkbun API (editByNameType)
                  → actualiza registros A

Registros DNS actualizados

Subdominio FQDN Tipo
@ carloselugo.com A
gamesever1 gamesever1.carloselugo.com A
git git.carloselugo.com A

Nota: *.carloselugo.com tiene un CNAME apuntando a carloselugo.com, por lo que cualquier subdominio nuevo hereda la IP del root automáticamente sin necesitar su propio registro A.


Archivos

Archivo Ruta
Script /opt/ddns/ddns_porkbun.sh
State file /home/netintel/.porkbun-ddns.last-ip
Log /home/netintel/.porkbun-ddns.log

Configuración del script

API_KEY="pk1_..."           # Porkbun API key
SECRET_KEY="sk1_..."        # Porkbun secret key
DOMAIN="carloselugo.com"
SUBDOMAINS=("@" "gamesever1" "git")
STATE_FILE="/home/netintel/.porkbun-ddns.last-ip"
LOG_FILE="/home/netintel/.porkbun-ddns.log"

Endpoint API usado

POST /dns/editByNameType/{domain}/A/{subdomain}

Se usa editByNameType en lugar de edit por ID porque es más robusto — no requiere hacer un retrieve previo para obtener el record ID, y evita el riesgo de crear registros duplicados accidentalmente.

Para el root (@) el endpoint es:

POST /dns/editByNameType/carloselugo.com/A

Para subdomains:

POST /dns/editByNameType/carloselugo.com/A/git

Prerequisitos en Porkbun

  1. Generar API key y secret en Account Settings → API Access
  2. Habilitar API access para el dominio en Domain Management → carloselugo.com → API Access (toggle)

Sin el toggle por dominio, el API devuelve DOMAIN_IS_NOT_OPTED_IN_TO_API_ACCESS aunque las keys sean correctas.


Lógica del script

  1. Obtiene la IP pública via api.ipify.org (fallback: ifconfig.me, icanhazip.com)
  2. Lee la última IP conocida del state file
  3. Si son iguales → exit silencioso (no llama al API)
  4. Si son diferentes → por cada subdominio:
    • Obtiene la IP actual en DNS via retrieveByNameType
    • Si ya coincide → skip
    • Si no → llama a editByNameType con la nueva IP
  5. Guarda la nueva IP en el state file

Cron

# crontab -e (usuario netintel)
*/30 * * * * /opt/ddns/ddns_porkbun.sh

Corre cada 30 minutos. Solo genera output en el log cuando la IP cambia.


Verificar funcionamiento

# Correr manualmente
/opt/ddns/ddns_porkbun.sh

# Ver log
tail -f ~/.porkbun-ddns.log

# Ver última IP registrada
cat ~/.porkbun-ddns.last-ip

# Forzar una IP específica (solo script de prueba)
/opt/ddns/ddns_porkbun_test.sh -f 1.2.3.4

Ejemplo de log

# Primera ejecución
[2026-04-28 11:44:54] IP cambió: (primera ejecución) → 24.139.235.46
[2026-04-28 11:44:55]   [@] Ya actualizado (24.139.235.46)
[2026-04-28 11:44:56]   [gamesever1] Ya actualizado (24.139.235.46)
[2026-04-28 11:44:57]   [git] Ya actualizado (24.139.235.46)

# Cuando la IP cambia
[2026-04-28 12:00:00] IP cambió: 24.139.235.46 → 24.139.236.10
[2026-04-28 12:00:01]   [@] ✓ 24.139.235.46 → 24.139.236.10
[2026-04-28 12:00:02]   [gamesever1] ✓ 24.139.235.46 → 24.139.236.10
[2026-04-28 12:00:03]   [git] ✓ 24.139.235.46 → 24.139.236.10
[2026-04-28 12:00:03] Listo. 3 registro(s) actualizado(s).

# Cuando no hay cambio (silencioso, no aparece en log)

Troubleshooting

El script no puede escribir el log
Verificar que las rutas de STATE_FILE y LOG_FILE sean escribibles por el usuario que corre el cron. Usar rutas en $HOME si no se corre como root.

Error: DOMAIN_IS_NOT_OPTED_IN_TO_API_ACCESS
El toggle de API access del dominio en Porkbun está desactivado. Activarlo en Domain Management.

El API conecta por IPv6 y falla
El servidor tiene conectividad IPv6. Todos los curl usan -4 para forzar IPv4 y evitar timeouts silenciosos.

El record desaparece después de editar
No usar dns/edit por ID cuando hay Cloudflare proxy habilitado en Porkbun — puede borrar el record. Usar siempre editByNameType.

S
Description
No description provided
Readme
30 KiB
Languages
Shell 100%