Files
ddns/README.md
T
2026-04-28 12:32:25 +00:00

168 lines
4.5 KiB
Markdown

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