Saltar a contenido
desec

DDNS (DNS dinámico) · DNS soberano · API REST (estilo de arquitectura para APIs web) · Dominios · Let's Encrypt

📌 Sin versionar

deSEC — DNS dinámico soberano

Servicio gratuito de DNS (servidor de nombres de dominio) operado por una organización alemana sin ánimo de lucro y financiado por el gobierno alemán. Es el eslabón que convierte una IP pública dinámica (que cambia cada vez que el router se reinicia) en un nombre de dominio estable.

SmallCountry usa deSEC para dos cosas:

  1. Zona 0 — Infraestructura VPN: dominio gratuito smallcountry.dedyn.io con subdominios vpn para NetBird y wg para el bypass de emergencia de WireGuard. La IP pública se actualiza automáticamente cada 5 minutos mediante un systemd timer.
  2. Dominios propios (futuro): cuando se adquieran dominios como elsalto.es o se vinculen dominios ya contratados como corraldelviento.es (Arsys), deSEC actuará como servidor DNS autoritativo delegando los nameservers desde el registrador.

Como usuario

No se interactúa directamente con deSEC. El systemd timer actualiza la IP automáticamente. Los usuarios simplemente instalan NetBird una vez, escanean el QR que proporciona el administrador, y a partir de ahí la VPN (red privada virtual) se conecta usando vpn.smallcountry.dedyn.io. Si la IP de casa cambia, deSEC lo resuelve en menos de 5 minutos sin que nadie tenga que hacer nada.

Navegador Ubuntu Android iOS FireTV
No aplica (es capa DNS) Automático vía NetBird Automático vía NetBird Automático vía NetBird No aplica

Integración con otros servicios de SmallCountry

Servicio Relación
NetBird Usa vpn.smallcountry.dedyn.io como endpoint de conexión. El DDNS (DNS dinámico) mantiene la IP actualizada → los clientes siempre encuentran el servidor
WireGuard El bypass de emergencia del administrador resuelve wg.smallcountry.dedyn.io. Si NetBird falla, WireGuard usa el mismo sistema DDNS
Caddy Obtiene certificados TLS (cifrado de comunicaciones) automáticos vía Let's Encrypt usando el plugin deSEC para el desafío DNS-01
Router doméstico El systemd timer consulta la IP pública del router y la envía a la API (interfaz de programación) de deSEC
Dominios propios En el futuro, elsalto.es y corraldelviento.es delegarán sus NS a deSEC para gestión soberana del DNS

Servicios que lo hacen posible

  • deSEC.io — DNS autoritativo + API REST para gestión de registros
  • systemd timer — actualización periódica de la IP (desec-update.timer)
  • Script DDNSdesec-update.sh que consulta la IP y llama a la API
  • Caddy — cliente ACME con plugin deSEC para certificados TLS
Para el administrador (diseño previsto)

Datos del servicio

LXC (contenedor ligero de Proxmox) Sin LXC propio — script + timer en el host
Ubicación Systemd timer en Ra (servidor principal de SmallCountry)
Frecuencia Cada 5 minutos
Proveedor deSEC.io (financiado por BMBF, Alemania)
Impacto 🔴 Crítico — caída del DDNS = NetBird y WireGuard dejan de resolver

Cuenta en deSEC

  1. Registrarse en desec.io (email + contraseña)
  2. Activar 2FA (autenticación en dos pasos) — recomendado, no obligatorio
  3. Crear un token de API con permisos de gestión de dominios
  4. Guardar el token en /root/.desec-token (lectura solo root: chmod 600)
# Crear token vía API
curl -X POST https://desec.io/api/v1/auth/tokens/ \
  -H "Authorization: Basic $(echo -n 'email:password' | base64)" \
  -H "Content-Type: application/json" \
  -d '{"name": "smallcountry-ddns"}'

# Guardar token
echo "TU_TOKEN_AQUI" > /root/.desec-token
chmod 600 /root/.desec-token

Dominios y registros DNS

deSEC aloja la zona smallcountry.dedyn.io. Los registros se crean y actualizan vía API:

smallcountry.dedyn.io    A      <IP pública>     (actualizada por DDNS cada 5min)
vpn.smallcountry.dedyn.io    CNAME smallcountry.dedyn.io.   (NetBird endpoint)
wg.smallcountry.dedyn.io     CNAME smallcountry.dedyn.io.   (WireGuard bypass)

El registro CNAME hace que vpn y wg siempre apunten a la misma IP que el dominio raíz. Cuando el DDNS actualiza el registro A del dominio raíz, los CNAME siguen automáticamente.

Script DDNS: desec-update.sh

Script que corre cada 5 minutos. Consulta la IP pública y la envía a deSEC:

#!/bin/bash
# /usr/local/bin/desec-update.sh
# Actualiza el registro A de smallcountry.dedyn.io en deSEC

TOKEN=$(cat /root/.desec-token)
DOMAIN="smallcountry.dedyn.io"

# Obtener IP pública actual
CURRENT_IP=$(curl -s https://checkipv4.dedyn.io/)

# Obtener IP registrada en deSEC
DESEC_IP=$(curl -s -H "Authorization: Token $TOKEN" \
  "https://desec.io/api/v1/domains/$DOMAIN/rrsets/@/A/" \
  | jq -r '.records[0] // empty')

if [ "$CURRENT_IP" != "$DESEC_IP" ]; then
  # IP ha cambiado: actualizar registro A
  curl -X PATCH "https://desec.io/api/v1/domains/$DOMAIN/rrsets/@/A/" \
    -H "Authorization: Token $TOKEN" \
    -H "Content-Type: application/json" \
    -d "{\"records\": [\"$CURRENT_IP\"]}"

  # También actualizar AAAA si hay IPv6
  CURRENT_IPV6=$(curl -s https://checkipv6.dedyn.io/ 2>/dev/null)
  if [ -n "$CURRENT_IPV6" ]; then
    curl -X PATCH "https://desec.io/api/v1/domains/$DOMAIN/rrsets/@/AAAA/" \
      -H "Authorization: Token $TOKEN" \
      -H "Content-Type: application/json" \
      -d "{\"records\": [\"$CURRENT_IPV6\"]}"
  fi

  logger -t desec-update "deSEC: IP actualizada a $CURRENT_IP"
fi

Systemd timer y service

# /etc/systemd/system/desec-update.service
[Unit]
Description=Actualizar IP en deSEC DDNS
After=network-online.target
Wants=network-online.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/desec-update.sh
User=root
# /etc/systemd/system/desec-update.timer
[Unit]
Description=Timer de actualización DDNS deSEC
Requires=desec-update.service

[Timer]
OnBootSec=1min
OnUnitActiveSec=5min
RandomizedDelaySec=30

[Install]
WantedBy=timers.target
systemctl daemon-reload
systemctl enable --now desec-update.timer

NetBird con dominio deSEC

NetBird se configura para que su endpoint público sea vpn.smallcountry.dedyn.io en lugar de una IP. Esto se define en el fichero de configuración de NetBird (management.json):

Endpoint: vpn.smallcountry.dedyn.io:51820

Cuando un cliente NetBird quiere conectarse, resuelve vpn.smallcountry.dedyn.io → obtiene la IP actual → establece el túnel WireGuard subyacente. Si la IP de casa cambia, el DDNS la actualiza en deSEC, y en la siguiente reconexión (o en el keepalive de WireGuard) el cliente resuelve la nueva IP automáticamente.

WireGuard bypass con dominio deSEC

El túnel de emergencia del administrador usa wg.smallcountry.dedyn.io. A diferencia de NetBird (que es una malla completa con panel de control), WireGuard es un túnel punto a punto mínimo:

# /etc/wireguard/wg-emergencia.conf (lado admin)
[Peer]
Endpoint = wg.smallcountry.dedyn.io:51821

Si NetBird falla por cualquier motivo (caída del panel de control, corrupción de la base de datos, error de actualización), el administrador activa manualmente este túnel y accede directamente a Ra.

Healthcheck

# Verificar que el dominio resuelve a la IP correcta
DOMAIN="smallcountry.dedyn.io"
PUBLIC_IP=$(curl -s https://checkipv4.dedyn.io/)
RESOLVED_IP=$(dig +short $DOMAIN @1.1.1.1)
[ "$PUBLIC_IP" = "$RESOLVED_IP" ] && echo "OK: $DOMAIN$RESOLVED_IP" || echo "FAIL: IP pública $PUBLIC_IP vs DNS $RESOLVED_IP"

# Verificar que el timer está activo
systemctl status desec-update.timer

# Última ejecución
journalctl -u desec-update.service --since "1 hour ago"

Logs y diagnóstico

journalctl -u desec-update.service -f     # Seguir en tiempo real
journalctl -u desec-update.service -n 20   # Últimas 20 ejecuciones
Para el arquitecto (diseño previsto)

Justificación: por qué deSEC y no otro

deSEC elimina la dependencia de DuckDNS, No-IP o cualquier proveedor comercial de DDNS. Ventajas:

  • Sin ánimo de lucro: financiado por el Ministerio de Educación e Investigación alemán (BMBF)
  • API REST/JSON completa: gestión programática de dominios, registros, tokens
  • DNSSEC automático: cada zona se firma automáticamente con rotación de claves gestionada por deSEC
  • Sin vendor lock-in: cambiar de proveedor es exportar la zona en formato estándar (zonefile) e importarla en otro
  • Let's Encrypt nativo: certificados TLS vía desafío DNS-01 sin exponer puerto 80
  • Dominios gratuitos *.dedyn.io: ideales para infraestructura interna que no necesita marca pública

Delegación de dominio propio (Arsys → deSEC)

Para cuando se active la Zona pública: elsalto.es (proyecto global de la finca) que enlazará corraldelviento.es (ya contratado en Arsys) y otros productos futuros.

Paso 1 — Crear la zona en deSEC:

curl -X POST https://desec.io/api/v1/domains/ \
  -H "Authorization: Token $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "corraldelviento.es"}'

La API devuelve los registros DS (DNSSEC). Guardarlos: los necesitarás si Arsys los pide (muchos registradores españoles no requieren DNSSEC, pero conviene tenerlos).

Paso 2 — Apuntar nameservers en Arsys:

  1. Entrar al panel de control de Arsys (arsys.es)
  2. Ir al dominio corraldelviento.es → Servidores DNS
  3. Seleccionar "Usar servidores DNS personalizados"
  4. Configurar:
ns1.desec.io
ns2.desec.org
  1. Guardar. La propagación DNS tarda entre 5 minutos y 48 horas (habitualmente < 1 hora).

Paso 3 — Crear registros DNS para el dominio:

# Registro A para la IP pública (o CNAME a la Zona 0 si comparten IP)
curl -X POST "https://desec.io/api/v1/domains/corraldelviento.es/rrsets/" \
  -H "Authorization: Token $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"subname": "", "type": "A", "ttl": 300, "records": ["1.2.3.4"]}'

# Subdominios de servicio
curl -X POST "https://desec.io/api/v1/domains/corraldelviento.es/rrsets/" \
  -H "Authorization: Token $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"subname": "tienda", "type": "CNAME", "ttl": 3600, "records": ["corraldelviento.es."]}'

# MX para correo (si aplica)
curl -X POST "https://desec.io/api/v1/domains/corraldelviento.es/rrsets/" \
  -H "Authorization: Token $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"subname": "", "type": "MX", "ttl": 3600, "records": ["10 mail.corraldelviento.es."]}'

Arquitectura de dominios completa

Zona 0 (infraestructura, acceso solo por VPN)
└─ smallcountry.dedyn.io       ← gratuito deSEC, DDNS cada 5min
   ├─ vpn.smallcountry.dedyn.io   → NetBird endpoint (malla Zero Trust)
   └─ wg.smallcountry.dedyn.io    → WireGuard bypass admin

Zona pública (futuro, accesible desde internet)
└─ elsalto.es                  ← dominio propio (Arsys), delegado a deSEC
   ├─ corraldelviento.es          → producto: tienda, ciencia abierta
   ├─ tienda.corraldelviento.es   → [Drupal Commerce](/fichas/programas/drupal-commerce/)
   ├─ ciencia.corraldelviento.es   → [InvenioRDM](/fichas/programas/inveniordm/)
   └─ ... otros productos

La separación es intencionada: la Zona 0 no necesita marca ni presencia pública. Usa un dominio gratuito de deSEC y solo es accesible desde dentro de la VPN. La Zona pública usa dominios propios con identidad de marca, delegados a deSEC para mantener la soberanía DNS.

Seguridad del token

  • El token de deSEC se guarda en /root/.desec-token con permisos 600
  • Se recomienda crear un token específico con permisos acotados (política de scoping) en vez de usar el token maestro
  • Para el script DDNS, basta con permisos perm_read_domain + perm_update_rrset sobre la zona específica
  • El token maestro (todos los permisos) solo se usa para operaciones administrativas (crear zonas, gestionar tokens)

Let's Encrypt con deSEC

Caddy (proxy inverso de SmallCountry) gestiona los certificados TLS automáticamente. Para usar deSEC como proveedor del desafío DNS-01:

# Plugin certbot-deSEC para ACME vía DNS-01
pip install certbot-dns-desec

# O configurar Caddy para usar el plugin deSEC
# En Caddyfile:
# tls {
#   dns desec {env.DESEC_TOKEN}
# }

El desafío DNS-01 permite obtener certificados wildcard (*.corraldelviento.es) y no requiere exponer ningún puerto a internet (a diferencia del desafío HTTP-01). Ideal para servicios que están detrás de CGNAT o firewalls restrictivos.

Componentes versionados

Componente Path
Systemd timer /etc/systemd/system/desec-update.timer
Systemd service /etc/systemd/system/desec-update.service
Script DDNS /usr/local/bin/desec-update.sh
Token /root/.desec-token
Repo Forgejo infra-core/scripts/desec/
Ficha versionada docs/fichas/programas/desec.md

Verificación de extremo a extremo

# 1. Comprobar que el DDNS funciona
curl -s https://checkipv4.dedyn.io/
dig +short smallcountry.dedyn.io @1.1.1.1

# 2. Comprobar que los CNAME resuelven
dig +short vpn.smallcountry.dedyn.io @1.1.1.1
dig +short wg.smallcountry.dedyn.io @1.1.1.1

# 3. Comprobar conectividad NetBird
netbird status

# 4. Comprobar WireGuard bypass
sudo wg show wg-emergencia

# 5. Verificar token deSEC
curl -s -H "Authorization: Token $(cat /root/.desec-token)" \
  https://desec.io/api/v1/domains/ | jq '.[].name'

Secciones relacionadas

🌐 Enlaces de interés

deSEC.io · Documentación API · GitHub · Panel de Arsys · Let's Encrypt + deSEC · certbot-dns-desec