Cómo bloquear el tráfico por país en un firewall de Linux con reglas GeoIP
Nivel: Profesional
Tiempo estimado: ~35 minutos
Objetivo: Configurar reglas de firewall GeoIP en un servidor Linux para restringir el acceso por país, usando iptables con el módulo xtables-geoip o nftables con conjuntos de IP (IP sets), y automatizar las actualizaciones para que las listas se mantengan al día.
Introducción
Si sus servicios están dirigidos a una región concreta, no hay motivo para aceptar tráfico del resto del mundo. El bloqueo geográfico en el firewall de Linux permite descartar paquetes según el país de origen antes de que lleguen a su aplicación, lo que reduce el ruido de los ataques de fuerza bruta y la superficie de ataque. En este tutorial va a bloquear el tráfico por país en un firewall de Linux mediante reglas de firewall GeoIP: primero con iptables y xtables-addons, y después con nftables y conjuntos de IP basados en CIDR, incluidas las actualizaciones automáticas de la base de datos para que su bloqueo de IP por país siga siendo preciso.
Requisitos previos
Antes de empezar, asegúrese de que se cumplen las siguientes condiciones:
- Sistema operativo: Ubuntu 22.04/24.04 LTS, Debian 12/13, AlmaLinux/RHEL 9/10
- Acceso: acceso sudo o root al servidor
- Firewall: iptables 1.8+ con xtables-addons, o nftables 1.0+
- Paquetes necesarios:
curl,iptables,linux-headers-$(uname -r)(Debian/Ubuntu); repositorio EPEL habilitado (RHEL/AlmaLinux 9)
En Debian 12+, Ubuntu 22.04+ y RHEL/AlmaLinux 9+, el comando iptables es un envoltorio (wrapper) del backend nftables (iptables-nft). La coincidencia -m geoip funciona correctamente con este backend.
- Red: una idea clara de desde qué países deben aceptar tráfico sus servicios
- Conocimientos necesarios: manejo seguro de la línea de comandos de Linux, conceptos básicos de firewall y edición de archivos
- Respaldo: una consola fuera de banda (IPMI/KVM) operativa o el modo de rescate del proveedor por si una regla le bloquea el acceso
Aplicar reglas de firewall por país a través de una sesión SSH es arriesgado por naturaleza. Si bloquea su propio país por error, perderá el acceso. Tenga siempre preparado un acceso alternativo fuera de banda y pruebe las reglas antes de hacerlas permanentes.
Paso 1: Identificar los países permitidos y bloqueados
Antes de tocar el firewall, defina su política. Hay dos enfoques:
- Lista de permitidos (recomendado): permitir solo los países necesarios y descartar todo lo demás. Es más estricto y seguro.
- Lista de bloqueados: permitir todo y descartar países concretos. Más sencillo, pero deja más superficie de ataque.
En este tutorial utilizaremos el enfoque de lista de permitidos, ya que se ajusta al principio de mínimo privilegio. Supongamos que sus servicios solo atienden a usuarios de Estados Unidos, Alemania y Polonia. Los códigos ISO de país de dos letras son: US, DE, PL.
Los códigos de país siguen el estándar ISO 3166-1 alpha-2. Encontrará la lista completa en https://www.iso.org/obp/ui/#search/code/. Sea preciso: un error tipográfico aquí bloquea en silencio tráfico legítimo.
Paso 2: Configurar GeoIP con iptables (xtables-addons)
Este método utiliza el módulo xt_geoip de xtables-addons, que añade a iptables la coincidencia -m geoip. Es una de las formas más consolidadas de bloquear rangos de IP por país en Linux.
2.1 Instalar xtables-addons y sus dependencias
Debian/Ubuntu:
sudo apt install -y linux-headers-$(uname -r) sudo apt update && sudo apt install -y \ xtables-addons-common libtext-csv-xs-perl unzip iptables curl
xtables-addons no está disponible en los repositorios de AlmaLinux 10. Utilice en su lugar el método con nftables (Paso 3) o compile xtables-addons desde el código fuente.
Tras la instalación, compruebe que el módulo está disponible:
modinfo xt_geoip
La salida esperada incluye una línea como:
filename: /lib/modules/.../xt_geoip.ko description: Xtables: country matching via GeoIP
Si modinfo devuelve un error, el módulo no se instaló correctamente. Compruebe que las cabeceras del kernel coinciden con la versión del kernel en ejecución.
2.2 Descargar y generar la base de datos GeoIP
El módulo xt_geoip necesita una base de datos local con la correspondencia entre países y direcciones IP. Se distribuye como archivos CSV que deben convertirse a un formato binario.
Cree el directorio de trabajo y el de la base de datos:
sudo mkdir -p /usr/share/xt_geoip
Descargue los datos GeoIP más recientes en formato CSV. La fuente original proporciona los datos mediante las herramientas de xtables-addons:
cd /tmp /usr/libexec/xtables-addons/xt_geoip_dl
Convierta el CSV descargado al formato binario:
/usr/libexec/xtables-addons/xt_geoip_build -D /usr/share/xt_geoip *.csv
Salida esperada: una lista de los códigos de país que se están procesando:
4540 IPv4 ranges for ZA 1071 IPv6 ranges for ZA 147 IPv4 ranges for ZW 94 IPv6 ranges for ZW ...
2.3 Aplicar reglas de iptables con coincidencia GeoIP
Ahora cree las reglas de firewall GeoIP propiamente dichas. El siguiente script permite el tráfico de los países elegidos y descarta todo lo demás en la cadena INPUT.
Haga primero una copia de seguridad de sus reglas actuales:
sudo iptables-save > /tmp/iptables-backup-$(date +%Y%m%d).rules
Aplique la lista de países permitidos:
# Allow loopback sudo iptables -A INPUT -i lo -j ACCEPT # Allow established and related connections sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT # Allow traffic from US, DE, PL only sudo iptables -A INPUT -m geoip --src-cc US,DE,PL -j ACCEPT # Log dropped packets sudo iptables -A INPUT -j LOG --log-prefix "GEOIP-DROP: " --log-level 4 # Drop everything else sudo iptables -A INPUT -j DROP
La regla final DROP bloquea todo el tráfico que no coincida con la lista de permitidos. Asegúrese de que el país desde el que se conecta por SSH está incluido; de lo contrario perderá el acceso de inmediato. Si tiene dudas, añada una regla ACCEPT temporal para su IP antes de DROP: sudo iptables -I INPUT -s <YOUR_IP_ADDRESS> -j ACCEPT.
Compruebe que las reglas están activas:
sudo iptables -L INPUT -v --line-numbers
Salida esperada:
Chain INPUT (policy ACCEPT) num target prot opt source destination 1 ACCEPT all -- anywhere anywhere /* loopback */ 2 ACCEPT all -- anywhere anywhere ctstate RELATED,ESTABLISHED 3 ACCEPT all -- anywhere anywhere -m geoip --source-country US,DE,PL 4 LOG all -- anywhere anywhere LOG level warning prefix "GEOIP-DROP: " 5 DROP all -- anywhere anywhere
2.4 Hacer persistentes las reglas de iptables tras los reinicios
Las reglas aplicadas con iptables se pierden al reiniciar. Guárdelas:
Debian/Ubuntu:
sudo apt install iptables-persistent -y sudo netfilter-persistent save
AlmaLinux/RHEL:
sudo service iptables save
Paso 3: Configurar GeoIP con nftables (conjuntos de IP)
Si su sistema usa nftables (el valor predeterminado en Debian 11+, Ubuntu 22.04+ y RHEL 9+), puede obtener el mismo resultado con conjuntos de IP rellenados con bloques CIDR por país. Este enfoque no requiere más módulos de kernel que los que ya proporciona nftables.
3.1 Obtener los rangos de IP de los países
Descargue las listas CIDR de los países que desea permitir. Varias fuentes públicas las ofrecen, como ipdeny.com:
sudo mkdir -p /etc/nftables/geoip cd /etc/nftables/geoip # Download CIDR blocks for US, DE, PL for CC in us de pl; do sudo curl -sS -o /etc/nftables/geoip/${CC}.zone \ "https://www.ipdeny.com/ipblocks/data/aggregated/${CC}-aggregated.zone"; done
Compruebe que los archivos contienen rangos CIDR:
head -5 /etc/nftables/geoip/us.zone
Salida esperada (rangos CIDR, uno por línea):
1.178.0.0/23 1.178.4.0/22 1.178.8.0/21 ...
3.2 Generar y cargar la configuración de nftables
Cree un script que lea los archivos CIDR y genere un conjunto (set) de nftables. Guárdelo como /etc/nftables/geoip-update.sh:
sudo nano /etc/nftables/geoip-update.sh
Pegue lo siguiente:
#!/bin/bash # Generate nftables set from country CIDR files set -euo pipefail GEOIP_DIR="/etc/nftables/geoip" OUTPUT="/etc/nftables/geoip-sets.nft" echo "define ALLOWED_COUNTRIES = {" > "$OUTPUT" for zone_file in "$GEOIP_DIR"/*.zone; do while IFS= read -r cidr; do && continue echo " ${cidr}," >> "$OUTPUT" done < "$zone_file" done echo "}" >> "$OUTPUT" echo "GeoIP set generated: $(wc -l < "$OUTPUT") lines"
Hágalo ejecutable:
sudo chmod +x /etc/nftables/geoip-update.sh
Ejecute el script:
sudo /etc/nftables/geoip-update.sh
Ahora haga referencia a este conjunto en su configuración de nftables:
# Debian/Ubuntu: sudo nano /etc/nftables.conf # AlmaLinux/RHEL: sudo nano /etc/sysconfig/nftables.conf
Añada el include y utilice el conjunto en su cadena input:
#!/usr/sbin/nft -f flush ruleset include "/etc/nftables/geoip-sets.nft" table inet filter { chain input { type filter hook input priority 0; policy drop; ct state invalid drop iif lo accept ct state established,related accept # Allow ICMP ip protocol icmp accept ip6 nexthdr icmpv6 accept # GeoIP: allow only listed countries ip saddr $ALLOWED_COUNTRIES accept # Log dropped packets log prefix "geoip-drop: " level info # Everything else is dropped by policy } chain forward { type filter hook forward priority 0; policy drop; } chain output { type filter hook output priority 0; policy accept; } }
Valide la sintaxis antes de aplicarla:
sudo nft -c -f /etc/nftables.conf
Si no aparecen errores, aplique la configuración y verifíquela:
sudo nft -f /etc/nftables.conf sudo systemctl enable --now nftables sudo nft list ruleset | head -20
Con conjuntos de IP muy grandes (más de 100.000 entradas), nftables funciona bastante mejor que iptables. La coincidencia basada en conjuntos de nftables utiliza internamente tablas hash, por lo que el rendimiento de la búsqueda se mantiene constante con independencia del tamaño del conjunto.
Paso 4: Automatizar las actualizaciones de la base de datos GeoIP
Las asignaciones de IP a país cambian constantemente. Una base de datos del mes pasado tendrá lagunas. Programe actualizaciones automáticas con cron.
4.1 Crear el script de actualización
Cree /usr/local/sbin/geoip-refresh.sh:
sudo nano /usr/local/sbin/geoip-refresh.sh
Para iptables (xtables-addons):
#!/bin/bash set -euo pipefail cd /tmp /usr/libexec/xtables-addons/xt_geoip_dl /usr/libexec/xtables-addons/xt_geoip_build \ -D /usr/share/xt_geoip *.csv rm -f /tmp/*.csv /tmp/*.zip logger "GeoIP database updated successfully"
Para nftables:
#!/bin/bash set -euo pipefail GEOIP_DIR="/etc/nftables/geoip" for CC in us de pl; do curl -sS -o "${GEOIP_DIR}/${CC}.zone" \ "https://www.ipdeny.com/ipblocks/data/aggregated/${CC}-aggregated.zone" done /etc/nftables/geoip-update.sh systemctl reload nftables logger "GeoIP nftables sets updated and reloaded"
Hágalo ejecutable:
sudo chmod +x /usr/local/sbin/geoip-refresh.sh
4.2 Programarlo con cron
Antes de programar la tarea de cron, asegúrese de que el servicio nftables está habilitado y en ejecución (si utiliza el método con nftables):
sudo systemctl enable --now nftables
Ejecute la actualización semanalmente:
sudo crontab -e
Añada:
0 3 * * 0 /usr/local/sbin/geoip-refresh.sh >> /var/log/geoip-update.log 2>&1
Esto se ejecuta todos los domingos a las 3:00. Tras la primera ejecución programada, compruebe que ha funcionado:
cat /var/log/geoip-update.log
Paso 5: Verificación y pruebas
5.1 Probar desde un país permitido
Desde una máquina situada en uno de sus países permitidos, conéctese por SSH o realice una petición HTTP:
curl -v http://<YOUR_SERVER_IP>
La conexión debería establecerse con normalidad.
5.2 Simular un país bloqueado
Utilice curl con una IP conocida de un país bloqueado a través de un proxy, o pruebe en local quitando temporalmente su propio país de la lista de permitidos e intentando conectarse desde un segundo terminal.
Servicios en línea como https://ipinfo.io permiten comprobar en qué país está registrada una IP determinada. Use curl https://ipinfo.io/<YOUR_IP_ADDRESS> para confirmarlo.
5.3 Revisar los contadores del firewall
iptables:
sudo iptables -L INPUT -v -n
Observe los contadores de paquetes de la regla DROP: deberían ir aumentando a medida que llega tráfico bloqueado.
nftables:
sudo nft list chain inet filter input
5.4 Supervisar los registros del sistema
Compruebe en el registro del sistema si hay paquetes descartados:
sudo journalctl -k --since "1 hour ago" | grep -i "geoip-drop"
Si observa un gran volumen de mensajes del registro del kernel sobre paquetes descartados y el sistema deja de responder, la causa puede ser una avalancha de registros. En el peor de los casos, esto puede provocar un pánico del kernel (kernel panic). Si ha configurado el parámetro crashkernel y el servicio kdump, un kernel panic generará un volcado de memoria (vmcore) en /var/crash que podrá analizar más tarde. Sin kdump, solo obtendrá un reinicio y ningún dato de diagnóstico. Consulte la sección siguiente para ver un resumen.
Paso 6: Protegerse frente al kernel panic durante los cambios en el firewall
Los cambios agresivos en el firewall de un servidor de producción con mucha carga, especialmente los que provocan picos repentinos de tráfico o avalanchas de registros, pueden en raras ocasiones provocar un kernel panic. Si ocurre y no se ha preparado, no obtendrá nada: solo un reinicio y ningún dato sobre lo que salió mal.
Kdump es el mecanismo estándar de Linux para capturar un volcado de memoria cuando se produce un kernel panic. Utiliza kexec para arrancar un segundo kernel de captura (capture kernel), que escribe la imagen de memoria (vmcore) en disco antes de que el sistema se reinicie.
Para disponer de diagnóstico:
- Compruebe que kdump está instalado y habilitado. En RHEL/AlmaLinux suele venir preinstalado. En Debian/Ubuntu:
sudo apt install kdump-tools kexec-tools -y
- Compruebe que el parámetro
crashkernelestá definido en la configuración del gestor de arranque:
Debería ver algo comocat /proc/cmdline | grep crashkernel
crashkernel=256M. Si falta, debe configurar el parámetro crashkernel en GRUB y reiniciar. La cantidad exacta de memoria que debe reservarse para kdump en Linux depende de la RAM total:256Mes un valor predeterminado seguro para servidores con 4 GB o más. - Compruebe que el servicio kdump está activo:
sudo systemctl status kdump
Si llega a producirse un kernel panic, el sistema utilizará kexec para arrancar el kernel de captura, escribirá el vmcore en /var/crash y, después, se reiniciará con normalidad. A continuación podrá realizar un análisis de vmcore en Linux con la utilidad crash para determinar la causa raíz. Es una parte habitual de la resolución de problemas de kernel panic en Linux en sistemas de producción. Para una guía completa sobre cómo habilitar kdump en Linux y sobre la configuración de kexec y kdump en Linux, consulte un tutorial específico de kdump.
Solución de problemas
- Bloqueado fuera de SSH: utilice la consola fuera de banda o el modo de rescate.
modinfo xt_geoip: not found: instalelinux-headers-$(uname -r).iptables: command not found(Debian 13): instale iptables consudo apt install iptables.nftables.serviceis not active: ejecutesudo systemctl enable --now nftables./etc/sysconfig/nftables.confvacío en AlmaLinux: utilice esta ruta en lugar de/etc/nftables.confpara configurar las reglas.
Reversión (rollback)
Para deshacer el bloqueo por países y restaurar el acceso abierto:
iptables: restaurar desde la copia de seguridad:
sudo iptables-restore < /tmp/iptables-backup-*.rules
Si aplicó las reglas GeoIP en un servidor sin configuración previa de firewall, el archivo de copia de seguridad estará vacío. En ese caso, utilice los comandos de vaciado y política que aparecen más abajo en lugar de iptables-restore.
O vacíe todas las reglas:
sudo iptables -F INPUT sudo iptables -P INPUT ACCEPT
Vaciar con la política ACCEPT elimina toda la protección del firewall. Aplique inmediatamente después su conjunto estándar de reglas de seguridad.
nftables: restaurar la configuración predeterminada:
sudo nft flush ruleset
A continuación, restaure su configuración base de nftables (sin GeoIP):
sudo nft -f /etc/nftables.conf.backup
Para eliminar por completo los componentes de GeoIP:
sudo rm -rf /etc/nftables/geoip sudo rm -f /etc/nftables/geoip-sets.nft /etc/nftables/geoip-update.sh sudo crontab -l | grep -v geoip-refresh | sudo crontab -
Elimine xtables-addons (si está instalado):
Debian/Ubuntu:
sudo apt remove xtables-addons-common -y
AlmaLinux/RHEL:
sudo dnf remove xtables-addons -y
Conclusión
Su servidor ya utiliza reglas de firewall GeoIP para bloquear el tráfico por país en Linux, ya sea mediante iptables con xt_geoip o mediante nftables con conjuntos de IP basados en CIDR. La base de datos se actualiza automáticamente, dispone de un plan de reversión y, con kdump configurado para capturar volcados de memoria en caso de kernel panic, su entorno de producción queda protegido tanto frente a las amenazas habituales como frente a los peores escenarios.
Versión del documento: 1.0
Última actualización: mayo de 2026
Responsable: Equipo de documentación técnica