BGP over WireGuard: строим отказоустойчивый Anycast за 30 минут

Настраиваем BGP over WireGuard и Anycast с нуля: готовые конфиги BIRD2, WireGuard, Nginx. Автоматический failover между датацентрами без Cloudflare и дорогих решений.

Диагноз: твой сервис падает — а ты даже не знаешь, в каком датацентре

Значит, так. У тебя два (а может, три) сервера в разных точках планеты. Ты хочешь, чтобы пользователь из Москвы шёл к московскому узлу, из Франкфурта — к франкфуртскому, а если один узел падает — трафик автоматически, без твоего участия, уходил на живой. Без Cloudflare. Без AWS Route53 latency routing. Без «позвони провайдеру и попроси». Своими руками, на своих серверах, за 30 минут.

Звучит как сказка? Это называется Anycast. И строится он на BGP. А BGP мы завернём в WireGuard, потому что голый BGP между серверами в интернете — это как ходить по офису в одних носках: можно, но зачем.

Что ты получишь по итогу этого рецепта
  • Рабочий BGP over WireGuard туннель между двумя (и более) узлами
  • Anycast IP, который отвечает с ближайшего живого сервера
  • Автоматический failover: упал узел — трафик ушёл, поднялся — вернулся
  • Готовые конфиги BIRD2 и WireGuard, которые можно скопировать и вставить
  • Понимание, почему это работает — на случай, если что-то пойдёт не так (а оно пойдёт)

Состав статьи:

  1. Диагноз — что строим и зачем
  2. Причины — почему BGP+WireGuard, а не что-то проще
  3. Рецепт — пошаговая настройка WireGuard + BIRD2 + Anycast
  4. Осложнения — типичные факапы и их лечение
  5. Прогноз — что в итоге, куда расти
Стенд для статьи: два VPS, Ubuntu 22.04 LTS, у каждого есть публичный IPv4. Один в Москве (назовём node-msk), второй во Франкфурте (node-fra). Оба под рутом или с sudo. Anycast-адрес — 192.0.2.1/32 (в реальности — твой IP, анонсированный провайдером или купленный PI-блок; для лабы используем lo-интерфейс).

Причины: почему болит и почему именно BGP over WireGuard

Почему не просто DNS failover?

DNS failover — это «переключить A-запись и подождать TTL». При TTL 60 секунд ты теряешь минуту трафика при каждом падении. При кешировании у провайдеров — больше. BGP Anycast переключает трафик на уровне маршрутизации, за секунды, без кеша и без TTL.

Почему не просто BGP без WireGuard?

Потому что BGP-сессия между серверами в интернете идёт по открытому каналу. Злой человек может инжектировать BGP UPDATE и угнать твой трафик. Это не паранойя — это называется BGP hijacking, и происходит регулярно. WireGuard даёт нам зашифрованный туннель с аутентификацией по ключам. BGP едет внутри туннеля — безопасно, надёжно, красиво.

Почему BIRD2, а не FRR или Quagga?

Quagga — дедушка, давно на пенсии. FRR — отличная штука, но для нашей задачи BIRD2 проще в конфигурации, легче на ресурсах и лучше документирован для простых Anycast-сценариев. Если ты уже используешь FRR — в конце статьи будет блок с эквивалентным конфигом.

Почему WireGuard, а не OpenVPN или IPSec?

Потому что WireGuard — это ~4000 строк кода против ~100000 у OpenVPN. Меньше кода — меньше багов — меньше поверхность атаки. И он быстрее. И конфиг — 15 строк, а не 150. Короче, WireGuard — это как хирургический скальпель, а OpenVPN — мачете из подсобки.

Где применяется BGP Anycast на практике?

  • Anycast DNS (именно так работают корневые DNS-серверы — их физически 13, но адресов тысячи точек)
  • Anycast для веб-серверов Nginx — пользователь идёт к ближайшему
  • Geo-распределение трафика без дорогих CDN
  • High availability без балансировщика и без единой точки отказа
  • Multi datacenter сеть для стартапа, которому не по карману AWS Global Accelerator

Рецепт: BGP over WireGuard + Anycast своими руками

Топология стенда

Параметр node-msk (Москва) node-fra (Франкфурт)
Публичный IP 1.2.3.4 5.6.7.8
WireGuard IP 10.0.0.1/30 10.0.0.2/30
BGP ASN 65001 65002
Anycast IP (lo) 192.0.2.1/32 192.0.2.1/32
WireGuard порт 51820 51820

Оба сервера анонсируют один и тот же IP (192.0.2.1/32) через BGP. Маршрутизаторы провайдера выбирают ближайший путь. Пользователь из Москвы приходит на node-msk, из Франкфурта — на node-fra. Если node-msk падает — BGP-анонс исчезает, и вся Москва идёт во Франкфурт. Некомфортно, но живо.

Важно про реальный Anycast: для настоящего Anycast в интернете тебе нужен PI (Provider Independent) блок адресов и BGP-сессия с провайдером (upstream). В этой статье мы строим лабораторную модель и internal BGP между своими узлами. Принцип тот же — отличие только в том, кто анонсирует адреса в интернет.

Шаг 0: Подготовка системы

На обоих серверах выполни:

# Обновляем систему
apt update && apt upgrade -y

# Ставим WireGuard и BIRD2
apt install -y wireguard wireguard-tools bird2

# Включаем форвардинг пакетов — без этого маршрутизация не поедет
echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
echo "net.ipv6.conf.all.forwarding=1" >> /etc/sysctl.conf
sysctl -p

# Проверяем
sysctl net.ipv4.ip_forward
# Должно быть: net.ipv4.ip_forward = 1

Шаг 1: Генерируем ключи WireGuard

На node-msk:

# Создаём директорию с правильными правами
mkdir -p /etc/wireguard
chmod 700 /etc/wireguard

# Генерируем ключевую пару
wg genkey | tee /etc/wireguard/msk_private.key | wg pubkey > /etc/wireguard/msk_public.key

# Смотрим ключи
echo "Приватный ключ MSK:"
cat /etc/wireguard/msk_private.key

echo "Публичный ключ MSK:"
cat /etc/wireguard/msk_public.key

На node-fra:

mkdir -p /etc/wireguard
chmod 700 /etc/wireguard

wg genkey | tee /etc/wireguard/fra_private.key | wg pubkey > /etc/wireguard/fra_public.key

echo "Приватный ключ FRA:"
cat /etc/wireguard/fra_private.key

echo "Публичный ключ FRA:"
cat /etc/wireguard/fra_public.key

Запиши оба публичных ключа — они понадобятся в конфигах на другой стороне.

Шаг 2: Настраиваем WireGuard туннель

На node-msk создай файл /etc/wireguard/wg0.conf:

cat > /etc/wireguard/wg0.conf << 'EOF'
[Interface]
# Приватный ключ node-msk
PrivateKey = <MSK_PRIVATE_KEY>

# WireGuard IP для BGP-сессии
Address = 10.0.0.1/30

# Порт, на котором слушаем
ListenPort = 51820

# MTU: WireGuard добавляет оверхед ~60 байт к IPv4
# BGP пакеты небольшие, но лучше выставить явно
MTU = 1420

# Поднимаем lo с Anycast IP при старте туннеля
PostUp = ip addr add 192.0.2.1/32 dev lo
# Убираем при остановке
PostDown = ip addr del 192.0.2.1/32 dev lo

[Peer]
# Публичный ключ node-fra
PublicKey = <FRA_PUBLIC_KEY>

# Публичный IP и порт node-fra
Endpoint = 5.6.7.8:51820

# Разрешаем трафик от WireGuard IP и Anycast-подсети
AllowedIPs = 10.0.0.2/32, 192.0.2.0/24

# Keepalive — важно! Без него BGP-сессия может отвалиться
# через NAT или фаервол
PersistentKeepalive = 25
EOF

На node-fra создай /etc/wireguard/wg0.conf:

cat > /etc/wireguard/wg0.conf << 'EOF'
[Interface]
# Приватный ключ node-fra
PrivateKey = <FRA_PRIVATE_KEY>

Address = 10.0.0.2/30
ListenPort = 51820
MTU = 1420

PostUp = ip addr add 192.0.2.1/32 dev lo
PostDown = ip addr del 192.0.2.1/32 dev lo

[Peer]
# Публичный ключ node-msk
PublicKey = <MSK_PUBLIC_KEY>

Endpoint = 1.2.3.4:51820

AllowedIPs = 10.0.0.1/32, 192.0.2.0/24

PersistentKeepalive = 25
EOF

Заменяй <MSK_PRIVATE_KEY>, <FRA_PRIVATE_KEY>, <MSK_PUBLIC_KEY>, <FRA_PUBLIC_KEY> на реальные значения из Шага 1.

Поднимаем и проверяем туннель на обоих серверах:

# Устанавливаем правильные права на конфиг
chmod 600 /etc/wireguard/wg0.conf

# Поднимаем интерфейс
wg-quick up wg0

# Включаем автозапуск
systemctl enable wg-quick@wg0

# Проверяем статус
wg show wg0

Ожидаемый вывод wg show — видим peer с latest handshake не старше 25 секунд. Если handshake есть — туннель живой.

# Проверяем связность через туннель
# С node-msk:
ping -c 4 10.0.0.2

# С node-fra:
ping -c 4 10.0.0.1

Если пинги идут — едем дальше. Если нет — смотри секцию «Осложнения».

Шаг 3: Настраиваем BIRD2 для BGP

Конфиг BIRD2 на node-msk

Создай /etc/bird/bird.conf на node-msk:

cat > /etc/bird/bird.conf << 'EOF'
# =====================================================
# BIRD2 конфиг для BGP over WireGuard
# Узел: node-msk, ASN: 65001
# =====================================================

# Router ID — уникальный идентификатор маршрутизатора
# Используем WireGuard IP
router id 10.0.0.1;

# Логирование — пиши всё в syslog, потом не пожалеешь
log syslog all;

# Протокол Device — нужен для обнаружения интерфейсов
protocol device {
    scan time 10;
}

# Протокол Direct <a title="DHCP Snooping — что это такое и как защитить сеть от Rogue DHCP сервера" href="https://it-apteka.com/dhcp-snooping-chto-jeto-takoe-i-kak-zashhitit-set-ot-rogue-dhcp-servera-2/" target="_blank" rel="noopener" data-wpil-monitor-id="1144">— экспортируем напрямую подключённые сети</a>
protocol direct {
    ipv4;
    interface "lo";  # Смотрим на lo, где живёт наш Anycast IP
}

# Kernel protocol <a title="ARP MikroTik: настройка, таблица, proxy-arp и reply-only — полный разбор" href="https://it-apteka.com/arp-mikrotik-nastrojka-tablica-proxy-arp-i-reply-only-polnyj-razbor/" target="_blank" rel="noopener" data-wpil-monitor-id="1145">— синхронизация таблицы</a> маршрутов BIRD с ядром
protocol kernel {
    ipv4 {
        export all;  # Все маршруты из BIRD -> в таблицу ядра
        import all;  # Все маршруты ядра -> в BIRD
    };
    learn;  # Учим существующие маршруты ядра
}

# =====================================================
# Статический маршрут для нашего Anycast IP
# Это то, что мы будем анонсировать через BGP
# =====================================================
protocol static anycast_routes {
    ipv4;
    route 192.0.2.1/32 via "lo";  # Anycast IP живёт на lo
}

# =====================================================
# Фильтр экспорта: анонсируем ТОЛЬКО наш Anycast IP
# Не надо анонсировать соседу всё подряд
# =====================================================
filter export_anycast {
    if net = 192.0.2.0/24 then accept;
    if net = 192.0.2.1/32 then accept;
    reject;
}

# Фильтр импорта: принимаем Anycast-маршруты от соседа
filter import_anycast {
    if net = 192.0.2.1/32 then accept;
    reject;
}

# =====================================================
# BGP-сессия с node-fra через WireGuard туннель
# =====================================================
protocol bgp node_fra {
    description "BGP to node-fra via WireGuard";

    # Наш ASN
    local as 65001;

    # Наш IP в туннеле
    local 10.0.0.1;

    # ASN соседа
    neighbor 10.0.0.2 as 65002;

    # Тип: eBGP (разные ASN) через WireGuard
    # multihop не нужен — они в одной /30 подсети

    ipv4 {
        import filter import_anycast;
        export filter export_anycast;
        next hop self;  # Говорим соседу: next hop — я сам
    };

    # Таймеры: keepalive и hold time в секундах
    # Маленькие значения = быстрый failover
    # Слишком маленькие = нестабильная сессия
    hold time 30;
    keepalive time 10;

    # Перезапуск при потере сессии
    error wait time 5, 30;
    error forget time 60;
}
EOF

Конфиг BIRD2 на node-fra

На node-fra — зеркальный конфиг с поменянными ASN и IP:

cat > /etc/bird/bird.conf << 'EOF'
# =====================================================
# BIRD2 конфиг для BGP over WireGuard
# Узел: node-fra, ASN: 65002
# =====================================================

router id 10.0.0.2;

log syslog all;

protocol device {
    scan time 10;
}

protocol direct {
    ipv4;
    interface "lo";
}

protocol kernel {
    ipv4 {
        export all;
        import all;
    };
    learn;
}

protocol static anycast_routes {
    ipv4;
    route 192.0.2.1/32 via "lo";
}

filter export_anycast {
    if net = 192.0.2.1/32 then accept;
    reject;
}

filter import_anycast {
    if net = 192.0.2.1/32 then accept;
    reject;
}

protocol bgp node_msk {
    description "BGP to node-msk via WireGuard";

    local as 65002;
    local 10.0.0.2;
    neighbor 10.0.0.1 as 65001;

    ipv4 {
        import filter import_anycast;
        export filter export_anycast;
        next hop self;
    };

    hold time 30;
    keepalive time 10;

    error wait time 5, 30;
    error forget time 60;
}
EOF

Запускаем BIRD2 на обоих серверах:

# Проверяем синтаксис конфига
bird -p

# Запускаем
systemctl start bird
systemctl enable bird

# Смотрим статус
systemctl status bird

Шаг 4: Проверяем BGP-сессию

# Заходим в BIRD CLI
birdc

# Смотрим статус всех протоколов
show protocols all

# Смотрим конкретно BGP-сессию
show protocols node_fra  # или node_msk на другом сервере

# Смотрим таблицу маршрутов
show route

# Смотрим только маршруты от BGP
show route protocol node_fra

# Выходим
quit

Что должно быть в выводе show protocols node_fra:

# Ожидаемый вывод (примерно):
Name       Proto      Table      State  Since         Info
node_fra   BGP        ---        up     2024-01-15    Established

Слово Established — это успех. Всё остальное — читай «Осложнения».

# Проверяем таблицу маршрутов ядра
# На node-msk должен появиться маршрут к 192.0.2.1 через 10.0.0.2
ip route show | grep 192.0.2

# Ожидаемый вывод на node-msk:
# 192.0.2.1 via 10.0.0.2 dev wg0 proto bird metric 32
# broadcast 192.0.2.1 dev lo proto kernel scope link src 192.0.2.1

Шаг 5: Настраиваем Nginx для Anycast

Ставим Nginx на оба сервера и вешаем его на Anycast IP:

apt install -y nginx

# Создаём тестовый конфиг
cat > /etc/nginx/sites-available/anycast << 'EOF'
server {
    # Слушаем ТОЛЬКО на Anycast IP
    listen 192.0.2.1:80;
    server_name _;

    location / {
        # Показываем, с какого узла ответил запрос
        return 200 "Hello from node-msk! Server: $hostname\n";
        # На node-fra замени на соответствующий текст
    }
}
EOF

ln -s /etc/nginx/sites-available/anycast /etc/nginx/sites-enabled/anycast

# Проверяем конфиг
nginx -t

# Перезапускаем
systemctl restart nginx

Проверяем:

# С любого сервера или клиента:
curl http://192.0.2.1

# Если тестируем локально с node-msk:
curl --interface 10.0.0.1 http://192.0.2.1

Шаг 6: Проверяем Anycast failover

Это самый приятный момент — имитируем падение узла и смотрим, как трафик переключается.

# На node-msk — "роняем" BGP анонс (но сервер живой)
# Способ 1: убираем маршрут из BIRD
birdc
  disable anycast_routes
  quit

# Или просто убиваем bird
systemctl stop bird

# На node-fra смотрим, что изменилось в таблице маршрутов
# Маршрут 192.0.2.1 через node-msk должен пропасть
ip route show | grep 192.0.2

# Curl теперь должен отвечать с node-fra
curl http://192.0.2.1
# Восстанавливаем node-msk
systemctl start bird

# Через несколько секунд BGP-сессия поднимается заново
# Проверяем
birdc
  show protocols node_fra
  quit

# Маршрут вернулся
ip route show | grep 192.0.2

Шаг 7: Настройка фаервола

Без этого не поедет. UFW или iptables должны пропускать WireGuard UDP и BGP TCP 179.
# Если используешь UFW
ufw allow 51820/udp comment "WireGuard"
ufw allow in on wg0 to any port 179 proto tcp comment "BGP"
ufw allow in on wg0 from 10.0.0.0/30 comment "BGP peers"
ufw reload

# Если используешь iptables напрямую
iptables -A INPUT -p udp --dport 51820 -j ACCEPT
iptables -A INPUT -i wg0 -p tcp --dport 179 -j ACCEPT
iptables -A INPUT -i wg0 -s 10.0.0.0/30 -j ACCEPT
iptables -A FORWARD -i wg0 -j ACCEPT
iptables -A FORWARD -o wg0 -j ACCEPT

# Сохраняем правила
apt install -y iptables-persistent
netfilter-persistent save

Шаг 8 (бонус): Три и более узлов

Для третьего узла (скажем, node-sin в Сингапуре, 10.0.0.5, ASN 65003) добавляем WireGuard peer к каждому существующему узлу и добавляем BGP-сессию в BIRD.

В /etc/wireguard/wg0.conf на node-msk добавляем:

# Добавляем в секцию [Peer] конфига wg0 на node-msk:
[Peer]
# Публичный ключ node-sin
PublicKey = <SIN_PUBLIC_KEY>
Endpoint = <SIN_PUBLIC_IP>:51820
AllowedIPs = 10.0.0.5/32, 192.0.2.0/24
PersistentKeepalive = 25

В BIRD-конфиг на node-msk добавляем:

# Добавляем в /etc/bird/bird.conf на node-msk:
protocol bgp node_sin {
    description "BGP to node-sin via WireGuard";
    local as 65001;
    local 10.0.0.1;
    neighbor 10.0.0.5 as 65003;
    ipv4 {
        import filter import_anycast;
        export filter export_anycast;
        next hop self;
    };
    hold time 30;
    keepalive time 10;
}
# Применяем изменения без перезапуска
wg-quick down wg0 && wg-quick up wg0

# Для BIRD — горячая перезагрузка конфига
birdc configure

Бонус: Эквивалентный конфиг для FRR

Если у тебя уже стоит FRR — держи эквивалентный конфиг:

# /etc/frr/frr.conf на node-msk (FRR версия)
frr version 8.4
frr defaults traditional
hostname node-msk
log syslog informational
service integrated-vtysh-config
!
interface lo
 ip address 192.0.2.1/32
!
router bgp 65001
 bgp router-id 10.0.0.1
 no bgp ebgp-requires-policy
 neighbor 10.0.0.2 remote-as 65002
 neighbor 10.0.0.2 description node-fra
 neighbor 10.0.0.2 timers 10 30
 !
 address-family ipv4 unicast
  network 192.0.2.1/32
  neighbor 10.0.0.2 activate
  neighbor 10.0.0.2 next-hop-self
  neighbor 10.0.0.2 prefix-list ANYCAST_ONLY out
  neighbor 10.0.0.2 prefix-list ANYCAST_ONLY in
 exit-address-family
!
ip prefix-list ANYCAST_ONLY seq 5 permit 192.0.2.1/32
ip prefix-list ANYCAST_ONLY seq 10 deny any
!
# Включаем bgpd в /etc/frr/daemons
sed -i 's/bgpd=no/bgpd=yes/' /etc/frr/daemons

# Перезапускаем FRR
systemctl restart frr

# Проверяем
vtysh -c "show bgp summary"

Осложнения: что пойдёт не так и как лечить

WireGuard: нет handshake / туннель не поднимается

# Диагностика WireGuard
wg show wg0

# Если latest handshake давно или вообще нет:
# 1. Проверяем, открыт ли порт
ss -ulnp | grep 51820

# 2. Проверяем, доступен ли endpoint с другой стороны
nc -zuv 5.6.7.8 51820

# 3. Смотрим системные логи
journalctl -u wg-quick@wg0 -n 50

# 4. Проверяем правила фаервола
iptables -L INPUT -n | grep 51820
ufw status verbose | grep 51820
Чеклист WireGuard
  • Публичные ключи НЕ перепутаны (частая ошибка — вставил свой вместо чужого)
  • Endpoint — публичный IP, а не WireGuard IP (10.0.0.x)
  • UDP 51820 открыт в фаерволе на обоих серверах
  • AllowedIPs включает IP соседа
  • MTU: если провайдер режет пакеты, попробуй MTU 1380

BGP: сессия не устанавливается (Active вместо Established)

# Смотрим лог BIRD
journalctl -u bird -n 100 | grep -E "BGP|error|Error"

# Или напрямую в BIRD CLI
birdc
  show protocols all
  show log
  quit

# Проверяем TCP 179 между узлами через туннель
# С node-msk:
nc -zv 10.0.0.2 179

# Если не подключается:
# 1. Проверяем фаервол на wg0
iptables -L INPUT -n | grep 179

# 2. Проверяем, что BIRD слушает
ss -tlnp | grep 179

# 3. Проверяем Router ID в конфиге
# Router ID должен быть уникальным на каждом узле

BGP Established, но маршруты не приходят

# Смотрим детально что анонсируется и принимается
birdc
  show route all
  show route protocol node_fra
  show route export node_fra
  show route import node_fra

# Типичная причина: фильтр отбросил маршрут
# Временно меняем фильтр на accept all для диагностики
# В конфиге bird.conf:
#   import all;
#   export all;

# Применяем
birdc configure

# Если маршруты пошли — проблема в фильтре
# Возвращаем нормальный фильтр и отлаживаем его

Маршруты есть в BIRD, но нет в таблице ядра

# Проверяем protocol kernel
birdc
  show protocols kernel1
  quit

# Проверяем, что экспорт из BIRD в ядро настроен
# В конфиге должно быть:
# protocol kernel {
#     ipv4 { export all; };
# }

# Смотрим таблицу маршрутов ядра
ip route show table all | grep 192.0.2

# Если маршрут есть в другой таблице:
ip rule show

Nginx не слушает на Anycast IP

# Проверяем, что IP добавлен на lo
ip addr show lo

# Если нет:
ip addr add 192.0.2.1/32 dev lo

# Проверяем конфиг nginx
nginx -t

# Смотрим на каких адресах слушает
ss -tlnp | grep nginx

# Типичная ошибка: nginx стартовал ДО того, как WireGuard добавил IP
# Решение: добавить в PostUp WireGuard
# PostUp = ip addr add 192.0.2.1/32 dev lo && systemctl restart nginx

MTU проблемы: пакеты режутся, TCP зависает

# Симптом: ping идёт, но curl/wget висит
# Диагностика: пинг с большим пакетом
ping -c 4 -M do -s 1400 10.0.0.2

# Если пакет не проходит — нужно снизить MTU
# В /etc/wireguard/wg0.conf:
# MTU = 1380  # или даже 1360

# Для TCP: включаем MSS clamping
iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN \
    -j TCPMSS --clamp-mss-to-pmtu

# Применяем
wg-quick down wg0 && wg-quick up wg0

Мониторинг BGP-сессий

# Простой <a class="wpil_keyword_link" href="https://it-apteka.com/category/scripts/" target="_blank"  rel="noopener" title="Скрипты" data-wpil-keyword-link="linked"  data-wpil-monitor-id="1148">скрипт</a> для мониторинга состояния BGP
cat &gt; /usr/local/bin/bgp-check.sh &lt;&lt; &#039;EOF&#039;
#!/bin/bash
PEERS=$(birdc show protocols | grep BGP | awk &#039;{print $1, $6}&#039;)
echo &quot;=== BGP Status ===&quot;
echo &quot;$PEERS&quot;

DOWN=$(echo &quot;$PEERS&quot; | grep -v Established)
if [ -n &quot;$DOWN&quot; ]; then
    echo &quot;ALERT: BGP session DOWN!&quot;
    echo &quot;$DOWN&quot;
    # Сюда можно добавить отправку в Telegram/Slack
    exit 1
fi
echo &quot;All BGP sessions: OK&quot;
exit 0
EOF

chmod +x /usr/local/bin/bgp-check.sh

# Добавляем в cron — проверка каждые 5 минут
echo &quot;*/5 * * * * /usr/local/bin/bgp-check.sh &gt;&gt; /var/log/bgp-check.log 2&gt;&amp;1&quot; | crontab -

Прогноз: что мы построили и куда расти

Итог

По факту, мы за 30 минут собрали следующее:

  • Зашифрованный туннель между двумя (или более) серверами через WireGuard — трафик идёт внутри криптографически защищённого канала
  • BGP-маршрутизацию поверх туннеля через BIRD2 — каждый узел анонсирует Anycast IP соседу и получает маршруты от него
  • Автоматический failover — если узел падает, BGP-сессия рвётся через hold time (30 секунд в нашем конфиге), и маршрут к упавшему узлу исчезает из таблиц
  • Anycast IP на lo — один адрес, несколько точек присутствия
  • Nginx на Anycast — реальный сервис, который отвечает с ближайшего узла
Что это даёт в цифрах
  • Failover за 30–60 секунд (hold time + BGP convergence) без ручного вмешательства
  • Нулевые расходы на балансировщик — всю работу делает протокол маршрутизации
  • Масштабирование: добавить третий узел — 10 минут работы
  • Безопасность: BGP-трафик внутри WireGuard, никакого открытого TCP 179 наружу

Куда расти дальше

BGP Communities для управления трафиком. Можно назначать community-теги маршрутам и управлять, куда какой трафик идёт — например, приоритизировать один узел над другим.

BFD (Bidirectional Forwarding Detection). Протокол для быстрого обнаружения падений линка — позволяет сократить failover с 30 секунд до 1-2. BIRD2 поддерживает BFD нативно.

Route reflector при большом количестве узлов. Если узлов 5+, полная mesh-топология BGP-сессий становится громоздкой. Route reflector — один центральный узел, который рассылает маршруты всем.

Интеграция с Prometheus + Grafana. BIRD2 умеет экспортировать метрики. Дашборд с состоянием BGP-сессий и счётчиками маршрутов — 30 минут работы.

Реальный Anycast с PI-блоком. Если у тебя есть PI-блок (Provider Independent) адресов и BGP-сессия с провайдером — схема из этой статьи масштабируется один в один. Добавляешь анонс своего блока в BIRD, провайдер распространяет его в интернет.

Self-hosted Anycast без IP-транзита — реально через overlay-сети. Проекты вроде Vultr, Hetzner, DigitalOcean дают BGP-сессии для своих клиентов. Это следующий уровень — отдельный рецепт.

Финальный чеклист перед продом

Пункт Статус
WireGuard туннель установлен, handshake свежий
BGP-сессия Established на обоих узлах
Anycast IP виден в таблице маршрутов ядра
Nginx слушает на Anycast IP, отвечает на curl
Failover проверен вручную — трафик переключается
Фаервол закрывает BGP (179) снаружи, открыт только через wg0
Мониторинг BGP-сессий настроен
WireGuard и BIRD добавлены в автозапуск

Есть вопросы по конфигу или упёрся в ошибку, которой нет в «Осложнениях»? Пиши в комментарии — отвечаю по делу, без «попробуй переустановить систему».

over_dude
Author: over_dude

Руководитель ИТ / Кризис-менеджер 25 лет в IT: от инженера в МегаФоне до руководителя отдела. Знаю, как выглядит бардак: нестабильные сети, устаревшая инфраструктура, конфликты в команде, раздутые сроки. Помогаю бизнесу выходить из кризиса: навожу порядок в легаси, стабилизирую то, что разваливается, выстраиваю прогнозируемые процессы. Дважды возвращал к жизни ИТ-структуры — знаю цену хаосу. 📍 Ищу проект для полной реорганизации / стабилизации. 📬 Telegram: @over_dude ✉️ mail@it-apteka.com

Оставайтесь на связи

Рецепты от IT-боли. Без воды, без рекламы, без маркетинговой шелухи.

Подписаться на IT-Аптеку →

Мы ВКонтакте

IT-Аптека — советы, новости и помощь рядом.

Вступить в группу ВКонтакте →
Поделитесь:

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Прокрутить вверх