# 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 ```bash 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 ```bash # 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 ```bash # 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`.