El balanceo de carga geográfico por DNS (GeoDNS) responde a la misma consulta con direcciones distintas según desde dónde se haga. Si tienes tu aplicación desplegada en Europa y en Norteamérica, un visitante de Madrid recibirá la IP del servidor europeo y uno de Houston la del americano, lo que reduce la latencia y reparte la carga entre regiones. En esta guía configurarás un servidor DNS autoritativo BIND 9 en Ubuntu 24.04 que usa la base de datos GeoLite2 de MaxMind y vistas por continente para servir registros diferentes a cada región.
Requisitos previos
- Un servidor con Ubuntu 24.04 LTS que hará de DNS autoritativo, por ejemplo un VPS de CubePath. En producción necesitarás al menos dos, idealmente en regiones distintas.
- Un usuario no root con privilegios
sudo. - Un dominio (
your_domain) cuya zona puedas delegar a tus propios servidores de nombres en el registrador. - Al menos dos servidores con tu aplicación en regiones distintas. En los ejemplos:
203.0.113.10(Europa) y198.51.100.10(Norteamérica). - Una cuenta gratuita de MaxMind para descargar GeoLite2 y una clave de licencia generada en su portal.
- El puerto 53 abierto por TCP y UDP.
Cómo funciona y qué limitaciones tiene
Un servidor autoritativo no ve la IP del usuario final, sino la del resolvedor recursivo que le pregunta (el de su operador, el de su empresa o uno público). BIND busca esa IP en la base GeoIP, la asigna a una vista y responde con la zona de esa vista. Normalmente el resolvedor está cerca del usuario, así que el resultado es correcto, pero hay dos consecuencias a tener en cuenta:
- Un usuario que usa un resolvedor lejano recibirá la región de ese resolvedor.
- Los resolvedores guardan la respuesta en caché durante el TTL del registro. Usa TTL cortos (60 a 300 segundos) en los registros geográficos para que los cambios se apliquen rápido.
BIND no comprueba si los servidores de destino están vivos. El GeoDNS decide por ubicación; la conmutación por fallo requiere cambiar la zona o usar otro mecanismo, como se explica al final.
Paso 1: Instalar BIND
sudo apt update
sudo apt install bind9 bind9-utils bind9-dnsutils
El paquete de Ubuntu está compilado con soporte para las bases MaxMind GeoIP2 (libmaxminddb). Compruébalo:
named -V | grep -i 'linked to maxminddb'
linked to maxminddb version: 1.9.1
Si aparece esa línea (la versión puede variar), BIND puede usar ACL con geoip. Comprueba también que el servicio está activo:
systemctl status named --no-pager
Paso 2: Descargar la base GeoLite2
La herramienta oficial geoipupdate descarga y actualiza las bases de MaxMind:
sudo apt install geoipupdate
Edita su configuración con tu ID de cuenta y tu clave de licencia:
sudo nano /etc/GeoIP.conf
AccountID your_account_id
LicenseKey your_license_key
EditionIDs GeoLite2-Country
DatabaseDirectory /usr/share/GeoIP
Protege el archivo, porque contiene tu clave, y descarga la base:
sudo chmod 600 /etc/GeoIP.conf
sudo mkdir -p /usr/share/GeoIP
sudo geoipupdate -v
ls -l /usr/share/GeoIP/
-rw-r--r-- 1 root root 9453010 Sep 25 10:12 GeoLite2-Country.mmdb
MaxMind actualiza GeoLite2 dos veces por semana. Programa la actualización con cron:
echo '17 4 * * 3,6 root /usr/bin/geoipupdate && /usr/sbin/rndc reload >/dev/null' | sudo tee /etc/cron.d/geoipupdate-bind
rndc reload hace que BIND vuelva a abrir la base tras la descarga.
Paso 3: Configurar las opciones globales
Este servidor será solo autoritativo, sin recursión, y debe saber dónde está la base GeoIP. Edita las opciones:
sudo nano /etc/bind/named.conf.options
options {
directory "/var/cache/bind";
geoip-directory "/usr/share/GeoIP";
recursion no;
allow-transfer { none; };
listen-on { any; };
listen-on-v6 { any; };
};
Paso 4: Definir ACL por región y vistas
Cuando usas vistas en BIND, todas las zonas deben estar dentro de alguna vista. Ubuntu incluye por defecto named.conf.default-zones fuera de las vistas, lo que provoca un error al arrancar. Como este servidor no hace recursión, esas zonas no son necesarias. Edita el archivo principal:
sudo nano /etc/bind/named.conf
Comenta la línea de las zonas por defecto para que quede así:
include "/etc/bind/named.conf.options";
include "/etc/bind/named.conf.local";
//include "/etc/bind/named.conf.default-zones";
Ahora define las regiones y las vistas en named.conf.local:
sudo nano /etc/bind/named.conf.local
acl "region-eu" {
geoip continent EU;
geoip continent AF;
};
acl "region-na" {
geoip continent NA;
geoip continent SA;
};
view "eu" {
match-clients { region-eu; };
zone "your_domain" {
type primary;
file "/etc/bind/zones/db.your_domain.eu";
};
};
view "na" {
match-clients { region-na; };
zone "your_domain" {
type primary;
file "/etc/bind/zones/db.your_domain.na";
};
};
view "default" {
match-clients { any; };
zone "your_domain" {
type primary;
file "/etc/bind/zones/db.your_domain.default";
};
};
Las vistas se evalúan en orden y gana la primera que coincide, así que la vista default con any debe ir la última: recoge Asia, Oceanía y las IP que no aparecen en la base. Los códigos de continente son de dos letras: AF, AN, AS, EU, NA, OC y SA. Si prefieres afinar por país, usa geoip country ES; con el código ISO del país.
Paso 5: Crear los archivos de zona
Crea el directorio y la zona para Europa:
sudo mkdir -p /etc/bind/zones
sudo nano /etc/bind/zones/db.your_domain.eu
$TTL 3600
@ IN SOA ns1.your_domain. hostmaster.your_domain. (
2026092501 ; serial
3600 ; refresh
600 ; retry
1209600 ; expire
300 ) ; negative cache TTL
@ IN NS ns1.your_domain.
@ IN NS ns2.your_domain.
ns1 IN A 192.0.2.53
ns2 IN A 192.0.2.54
@ 60 IN A 203.0.113.10
www 60 IN A 203.0.113.10
Crea la de Norteamérica partiendo de la anterior y cambia solo las IP de la aplicación:
sudo cp /etc/bind/zones/db.your_domain.eu /etc/bind/zones/db.your_domain.na
sudo sed -i 's/203\.0\.113\.10/198.51.100.10/' /etc/bind/zones/db.your_domain.na
La zona por defecto puede apuntar a la región que mejor atienda al resto del mundo. En este ejemplo, a Europa:
sudo cp /etc/bind/zones/db.your_domain.eu /etc/bind/zones/db.your_domain.default
Los registros NS, SOA y de correo deben ser idénticos en todas las variantes; solo cambian los registros que quieres geolocalizar. Sustituye 192.0.2.53 y 192.0.2.54 por las IP reales de tus servidores de nombres.
Paso 6: Validar y cargar la configuración
Comprueba la sintaxis global y cada zona antes de recargar:
sudo named-checkconf
sudo named-checkzone your_domain /etc/bind/zones/db.your_domain.eu
sudo named-checkzone your_domain /etc/bind/zones/db.your_domain.na
sudo named-checkzone your_domain /etc/bind/zones/db.your_domain.default
zone your_domain/IN: loaded serial 2026092501
OK
named-checkconf no imprime nada si todo es correcto. Reinicia BIND y revisa el log:
sudo systemctl restart named
sudo journalctl -u named -n 30 --no-pager
Debes ver una línea zone your_domain/IN/eu: loaded serial 2026092501 por cada vista y ningún error sobre GeoIP. Abre el puerto 53:
sudo ufw allow 53/udp
sudo ufw allow 53/tcp
Paso 7: Comprobar las respuestas por región
Una consulta desde el propio servidor viene de 127.0.0.1, que no está en la base GeoIP, así que debe caer en la vista default:
dig @127.0.0.1 www.your_domain A +short
203.0.113.10
La prueba real se hace consultando directamente a tu servidor desde máquinas situadas en cada región, por ejemplo un VPS en Europa y otro en Norteamérica:
dig @your_server_ip www.your_domain A +short
Desde Norteamérica la respuesta debe ser 198.51.100.10 y desde Europa 203.0.113.10. Si solo tienes acceso a una región, herramientas de medición distribuida como Globalping o RIPE Atlas permiten lanzar consultas DNS desde sondas en otros países.
Cuando todo responda como esperas, crea en tu registrador los registros de pegamento (glue) para ns1.your_domain y ns2.your_domain y delega el dominio en ellos. El segundo servidor de nombres debe tener exactamente la misma configuración de vistas y zonas.
Conmutación por fallo
BIND no sabe si 203.0.113.10 ha dejado de responder. Tienes varias opciones:
- Manual o con tu monitorización: cuando una región cae, cambia la IP en la zona afectada, incrementa el serial y ejecuta
sudo rndc reload. Con TTL de 60 segundos el cambio se propaga en pocos minutos. - Varias IP por región: publica dos registros
Aen cada vista (por ejemplo, un servidor principal y uno de otra región). Los navegadores prueban la siguiente dirección si la primera no conecta, aunque con cierto retraso. - PowerDNS con registros LUA: PowerDNS Authoritative permite registros que comprueban la disponibilidad antes de responder, por ejemplo
www IN LUA A "ifportup(443, {'203.0.113.10', '198.51.100.10'})"conenable-lua-records=yesen su configuración. Si necesitas geolocalización y comprobaciones de salud en la misma pieza, es una opción a valorar.
Solución de problemas
when using 'view' statements, all zones must be in views. Queda alguna zona fuera de las vistas, normalmente por elincludedenamed.conf.default-zones. Coméntalo como en el paso 4.- Errores sobre GeoIP en
journalctl -u named. Revisa que/usr/share/GeoIP/GeoLite2-Country.mmdbexiste. Si el log muestraPermission denied, AppArmor está bloqueando la lectura: añade la línea/usr/share/GeoIP/** r,a/etc/apparmor.d/local/usr.sbin.namedy recarga el perfil consudo apparmor_parser -r /etc/apparmor.d/usr.sbin.named. - Todas las consultas reciben la vista
default. La base no se ha cargado o las ACL no coinciden. Comprueba el continente de una IP concreta conmmdblookup, del paquetemmdb-bin:mmdblookup --file /usr/share/GeoIP/GeoLite2-Country.mmdb --ip 198.51.100.10 continent code. - Los cambios no se ven. Olvidaste incrementar el serial o los resolvedores aún tienen la respuesta en caché. Consulta directamente a tu servidor con
dig @your_server_ippara descartar la caché.
Conclusión
Tu servidor BIND responde ahora a cada región con la IP de su centro de datos más cercano, usando GeoLite2 actualizado automáticamente y TTL cortos para poder reaccionar ante cambios. Como siguientes pasos, replica la configuración en un segundo servidor de nombres (con transferencias de zona por vista protegidas con TSIG o gestionando los archivos con Ansible), firma la zona con DNSSEC y conecta tu monitorización para automatizar el cambio de IP cuando una región deje de responder.
