Как заблокировать трафик по стране на брандмауэре Linux с помощью правил GeoIP
Уровень: Профессиональный
Ориентировочное время: ~35 минут
Цель: Настроить правила брандмауэра geoip на сервере Linux для ограничения доступа по стране, используя iptables с модулем xtables-geoip или nftables с IP сетами - и автоматизировать обновления, чтобы списки оставались актуальными.
Введение
Если ваши сервисы ориентированы на определенный регион, нет смысла принимать трафик со всего остального мира. Геоблокировка брандмауэра Linux позволяет отбрасывать пакеты по стране происхождения до того, как они достигнут вашего приложения - сокращая шум от брутфорса и уменьшая поверхность атаки. В этом руководстве вы заблокируете трафик по стране на брандмауэре Linux с помощью правил брандмауэра geoip: сначала с помощью iptables и xtables-addons, затем с помощью nftables и IP-сетов на основе CIDR, включая автоматические обновления базы данных, чтобы ваша блокировка IP-адресов по стране оставалась точной.
Предварительные требования
Перед началом работы убедитесь, что выполнены следующие условия:
- Операционная система: Ubuntu 22.04/24.04 LTS, Debian 12/13, AlmaLinux/RHEL 9/10
- Доступ: доступ sudo или root к серверу
- Брандмауэр: iptables 1.8+ с xtables-addons или nftables 1.0+
- Необходимые пакеты:
curl,iptables,linux-headers-$(uname -r)(Debian/Ubuntu); включен репозиторий EPEL (RHEL/AlmaLinux 9)
В Debian 12+, Ubuntu 22.04+ и RHEL/AlmaLinux 9+ команда iptables является обёрткой над бэкендом nftables (iptables-nft). Проверка -m geoip корректно работает с этим бэкендом.
- Сеть: четкое понимание того, из каких стран ваши службы должны принимать трафик
- Необходимые знания: уверенное использование командной строки Linux, базовые концепции брандмауэра и редактирование файлов
- Резервное копирование: работающая out-of-band консоль (IPMI/KVM) или режим восстановления (rescue mode) провайдера на случай, если правило заблокирует вам доступ
Применение правил брандмауэра на уровне стран через SSH-сессию по своей природе рискованно. Если вы по ошибке заблокируете свою страну, вы потеряете доступ. Всегда держите наготове резервный out-of-band доступ и тестируйте правила, прежде чем делать их постоянными.
Шаг 1: Определите разрешенные и заблокированные страны
Прежде чем изменять брандмауэр, определитесь с вашей политикой. Существует два подхода:
- Белый список (рекомендуется): Разрешить только те страны, которые вам нужны, отбрасывать все остальное. Это более строго и безопасно.
- Черный список: Разрешить все, отбрасывать определенные страны. Проще, но оставляет большую поверхность атаки.
В этом руководстве мы будем использовать подход белого списка - он соответствует принципу наименьших привилегий. Предположим, ваши службы обслуживают пользователей только из США, Германии и Польши. Двухбуквенные коды стран ISO: US, DE, PL.
Коды стран соответствуют стандарту ISO 3166-1 alpha-2. Полный список доступен по адресу https://www.iso.org/obp/ui/#search/code/. Будьте внимательны: опечатка здесь незаметно заблокирует легитимный трафик.
Шаг 2: Настройка GeoIP с iptables (xtables-addons)
Этот метод использует модуль xt_geoip из xtables-addons, который добавляет проверку -m geoip к iptables. Это один из наиболее признанных способов блокировки диапазона IP-адресов по стране в Linux.
2.1 Установка xtables-addons и зависимостей
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 недоступен в репозиториях AlmaLinux 10. Используйте вместо этого метод nftables (Шаг 3) или соберите xtables-addons из исходного кода.
После установки убедитесь, что модуль доступен:
modinfo xt_geoip
Ожидаемый вывод включает строку вида:
filename: /lib/modules/.../xt_geoip.ko description: Xtables: country matching via GeoIP
Если modinfo возвращает ошибку, модуль установлен неправильно. Убедитесь, что заголовки вашего ядра соответствуют версии работающего ядра.
2.2 Загрузка и создание базы данных GeoIP
Для модуля xt_geoip требуется локальная база данных сопоставления стран и IP-адресов. Они поставляются в виде CSV файлов и должны быть преобразованы в бинарный формат.
Создайте рабочий каталог и каталог базы данных:
sudo mkdir -p /usr/share/xt_geoip
Загрузите последние данные GeoIP в формате CSV. Источник предоставляет данные через инструменты xtables-addons:
cd /tmp /usr/libexec/xtables-addons/xt_geoip_dl
Преобразуйте загруженный CSV в бинарный формат:
/usr/libexec/xtables-addons/xt_geoip_build -D /usr/share/xt_geoip *.csv
Ожидаемый вывод - список обрабатываемых кодов стран:
4540 IPv4 ranges for ZA 1071 IPv6 ranges for ZA 147 IPv4 ranges for ZW 94 IPv6 ranges for ZW ...
2.3 Применение правил iptables с фильтрацией GeoIP
Теперь создайте сами правила брандмауэра geoip. Следующий скрипт разрешает трафик из выбранных вами стран и отбрасывает всё остальное в цепочке INPUT.
Сначала сделайте резервную копию текущих правил:
sudo iptables-save > /tmp/iptables-backup-$(date +%Y%m%d).rules
Примените белый список стран:
# Разрешить loopback sudo iptables -A INPUT -i lo -j ACCEPT # Разрешить установленные и связанные соединения sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT # Разрешить трафик только из США, Германии, Польши sudo iptables -A INPUT -m geoip --src-cc US,DE,PL -j ACCEPT # Логировать отброшенные пакеты sudo iptables -A INPUT -j LOG --log-prefix "GEOIP-DROP: " --log-level 4 # Отбрасывать всё остальное sudo iptables -A INPUT -j DROP
Завершающее правило DROP блокирует весь трафик, не соответствующий белому списку. Убедитесь, что страна, из которой вы подключаетесь по SSH, включена в список, иначе вы будете немедленно отключены. Если вы не уверены, добавьте временное правило ACCEPT для вашего IP перед DROP: sudo iptables -I INPUT -s <YOUR_IP_ADDRESS> -j ACCEPT.
Убедитесь, что правила активны:
sudo iptables -L INPUT -v --line-numbers
Ожидаемый вывод:
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 Сохранение правил iptables после перезагрузки
Правила, примененные с помощью iptables, теряются при перезагрузке. Сохраните их:
Debian/Ubuntu:
sudo apt install iptables-persistent -y sudo netfilter-persistent save
AlmaLinux/RHEL:
sudo service iptables save
Шаг 3: Настройка GeoIP с nftables (IP сеты)
Если в вашей системе используется nftables (по умолчанию в Debian 11+, Ubuntu 22.04+ и RHEL 9+), вы можете добиться того же результата, используя IP сеты, заполненные CIDR-блоками на уровне страны. Этот подход не требует модулей ядра, кроме тех, которые уже предоставляет nftables.
3.1 Получение диапазонов IP-адресов стран
Загрузите списки CIDR для стран, которые вы хотите разрешить. Несколько общедоступных источников предоставляют их, например ipdeny.com:
sudo mkdir -p /etc/nftables/geoip cd /etc/nftables/geoip # Загрузить блоки CIDR для США, Германии, Польши 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
Убедитесь, что файлы содержат диапазоны CIDR:
head -5 /etc/nftables/geoip/us.zone
Ожидаемый вывод (диапазоны CIDR, по одному в строке):
1.178.0.0/23 1.178.4.0/22 1.178.8.0/21 ...
3.2 Создание и загрузка конфигурации nftables
Создайте скрипт, который читает файлы CIDR и генерирует сет nftables. Сохраните его как /etc/nftables/geoip-update.sh:
sudo nano /etc/nftables/geoip-update.sh
Вставьте следующее:
#!/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"
Сделайте его исполняемым:
sudo chmod +x /etc/nftables/geoip-update.sh
Запустите скрипт:
sudo /etc/nftables/geoip-update.sh
Теперь сошлитесь на этот сет в вашей конфигурации nftables:
# Debian/Ubuntu: sudo nano /etc/nftables.conf # AlmaLinux/RHEL: sudo nano /etc/sysconfig/nftables.conf
Добавьте включение (include) и используйте сет в своей цепочке 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 # Разрешить ICMP ip protocol icmp accept ip6 nexthdr icmpv6 accept # GeoIP: разрешить только перечисленные страны ip saddr $ALLOWED_COUNTRIES accept # Логировать отброшенные пакеты log prefix "geoip-drop: " level info # Всё остальное отбрасывается политикой } chain forward { type filter hook forward priority 0; policy drop; } chain output { type filter hook output priority 0; policy accept; } }
Проверьте синтаксис перед применением:
sudo nft -c -f /etc/nftables.conf
Если ошибок нет, примените и проверьте:
sudo nft -f /etc/nftables.conf sudo systemctl enable --now nftables sudo nft list ruleset | head -20
Для очень больших IP-сетов (100K+ записей) nftables справляется значительно лучше, чем iptables. Сопоставление на основе сетов в nftables использует внутри хеш-таблицы, поэтому производительность поиска остаётся постоянной независимо от размера сета.
Шаг 4: Автоматизация обновлений базы данных GeoIP
Сопоставления IP-адресов и стран постоянно меняются. База данных прошлого месяца будет иметь пробелы. Запланируйте автоматические обновления с помощью cron.
4.1 Создание скрипта обновления
Создайте /usr/local/sbin/geoip-refresh.sh:
sudo nano /usr/local/sbin/geoip-refresh.sh
Для 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"
Для 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"
Сделайте его исполняемым:
sudo chmod +x /usr/local/sbin/geoip-refresh.sh
4.2 Расписание с помощью cron
Перед планированием задачи cron убедитесь, что служба nftables включена и работает (если используется метод nftables):
sudo systemctl enable --now nftables
Запускайте обновление еженедельно:
sudo crontab -e
Добавьте:
0 3 * * 0 /usr/local/sbin/geoip-refresh.sh >> /var/log/geoip-update.log 2>&1
Это будет запускаться каждое воскресенье в 3:00 ночи. После первого запланированного запуска убедитесь, что он сработал:
cat /var/log/geoip-update.log
Шаг 5: Проверка и тестирование
5.1 Тестирование из разрешенной страны
С машины в одной из ваших разрешенных стран подключитесь по SSH или сделайте HTTP-запрос:
curl -v http://<YOUR_SERVER_IP>
Соединение должно пройти успешно.
5.2 Имитация заблокированной страны
Используйте curl с известным IP-адресом из заблокированной страны через прокси-сервер или протестируйте локально, временно удалив свою страну из белого списка и попытавшись подключиться со второго терминала.
Онлайн-сервисы, такие как https://ipinfo.io, позволяют проверить, в какой стране зарегистрирован данный IP-адрес. Используйте curl https://ipinfo.io/<YOUR_IP_ADDRESS> для подтверждения.
5.3 Проверка счетчиков брандмауэра
iptables:
sudo iptables -L INPUT -v -n
Посмотрите на счетчики пакетов на правиле DROP - они должны увеличиваться по мере поступления заблокированного трафика.
nftables:
sudo nft list chain inet filter input
5.4 Мониторинг системных журналов
Проверьте наличие отброшенных пакетов в системном журнале:
sudo journalctl -k --since "1 hour ago" | grep -i "geoip-drop"
Если вы наблюдаете большой объём сообщений в журнале ядра об отброшенных пакетах, а система перестаёт отвечать, причиной может быть шквал логирования. В худшем случае это может вызвать панику ядра (kernel panic). Если вы настроили параметр crashkernel и службу kdump, паника ядра создаст аварийный дамп (vmcore) в /var/crash, который вы сможете проанализировать позже. Без kdump вы получите только перезагрузку и никакой диагностики. Краткий обзор приведён в разделе ниже.
Шаг 6: Защита от паники ядра при изменениях брандмауэра
Агрессивные изменения брандмауэра на загруженном рабочем сервере - особенно те, которые вызывают внезапные всплески трафика или шквал логирования - в редких случаях могут привести к панике ядра (kernel panic). Если это произойдет, и вы не подготовились, вы не получите ничего: только перезагрузку и никаких данных о том, что пошло не так.
Kdump - это стандартный механизм Linux для сохранения аварийного дампа при панике ядра. Он использует kexec для загрузки вторичного ядра захвата (capture kernel), которое записывает образ памяти (vmcore) на диск перед перезапуском системы.
Чтобы обеспечить наличие диагностики:
- Убедитесь, что kdump установлен и включен. На RHEL/AlmaLinux он обычно предустановлен. На Debian/Ubuntu:
sudo apt install kdump-tools kexec-tools -y
- Проверьте, установлен ли параметр
crashkernelв конфигурации вашего загрузчика:
Вы должны увидеть что-то вродеcat /proc/cmdline | grep crashkernel
crashkernel=256M. Если он отсутствует, вам нужно настроить параметр crashkernel в GRUB и перезагрузиться. Точный объем памяти, который следует зарезервировать для kdump в Linux, зависит от общего объема вашей оперативной памяти -256Mявляется безопасным значением по умолчанию для серверов с 4 ГБ или более. - Убедитесь, что служба kdump активна:
sudo systemctl status kdump
Если паника ядра всё же произойдёт, система использует kexec для загрузки ядра захвата, запишет vmcore в /var/crash, а затем нормально перезагрузится. После этого вы сможете выполнить анализ vmcore в Linux с помощью утилиты crash, чтобы определить первопричину. Это стандартная часть диагностики паники ядра Linux в рабочих системах. Полное руководство по тому, как включить kdump в Linux, и по настройке kexec kdump в Linux смотрите в отдельном руководстве по kdump.
Устранение неполадок
- Заблокирован доступ по SSH: используйте out-of-band консоль / режим восстановления (rescue mode).
modinfo xt_geoip: not found: установитеlinux-headers-$(uname -r).iptables: command not found(Debian 13): установите iptables с помощьюsudo apt install iptables.nftables.serviceis not active: выполнитеsudo systemctl enable --now nftables.- Пустой
/etc/sysconfig/nftables.confв AlmaLinux: используйте этот путь вместо/etc/nftables.confдля настройки правил.
Откат изменений (Rollback)
Чтобы отменить блокировку по странам и восстановить открытый доступ:
iptables - восстановление из резервной копии:
sudo iptables-restore < /tmp/iptables-backup-*.rules
Если вы применили правила GeoIP на сервере без предыдущей конфигурации брандмауэра, файл резервной копии будет пустым. В этом случае используйте приведённые ниже команды очистки и установки политики вместо iptables-restore.
Или очистите все правила:
sudo iptables -F INPUT sudo iptables -P INPUT ACCEPT
Очистка с политикой ACCEPT снимает всю защиту брандмауэра. Немедленно примените после этого ваш стандартный набор правил безопасности.
nftables - восстановление по умолчанию:
sudo nft flush ruleset
Затем восстановите вашу базовую конфигурацию nftables (без GeoIP):
sudo nft -f /etc/nftables.conf.backup
Чтобы полностью удалить компоненты 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 -
Удаление xtables-addons (если установлено):
Debian/Ubuntu:
sudo apt remove xtables-addons-common -y
AlmaLinux/RHEL:
sudo dnf remove xtables-addons -y
Заключение
Теперь ваш сервер использует правила брандмауэра geoip для блокировки трафика по стране в Linux - либо через iptables с xt_geoip, либо через nftables с IP сетами на основе CIDR. База данных обновляется автоматически, у вас есть план отката, и благодаря настроенному kdump для сбора аварийного дампа в случае паники ядра, ваша рабочая среда защищена как от рутинных угроз, так и от наихудших сценариев.
Версия документа: 1.0
Последнее обновление: Май 2026
Владелец: Команда технической документации