Каскадная маршрутизация русских сайтов через свой набор RU-серверов с failover, Telegram-ботом и веб-интерфейсом. - bin/ — failover-script, route/domain helpers, ams/ru bootstrap - bot/ — Telegram-бот (Python, long-poll) - webui/ — Flask single-page dashboard - docs/ — установка, архитектура, API бота и WebUI - examples/ — шаблоны конфигов
7.3 KiB
Архитектура
Обзор
Каждый ам. сервер — это WG-клиент, держит ОДИН активный туннель к одному из RU-серверов. RU-серверы — это WG-серверы, у каждого N пиров (по числу ам.).
┌─────────────┐
│ RU primary│
│ (priority 1)│
└──┬──┬──┬──┬──┘
│ │ │ │ WG туннели
┌─────┘ │ │ └─────┐
▼ ▼ ▼ ▼
┌──────┐ ┌──────┐ ┌──────┐
│ ams1 │ │ ams2 │ │ ams3 │
│X-ray │ │X-ray │ │X-ray │
└──────┘ └──────┘ └──────┘
▲ ▲ ▲
│ │ │ failover при падении primary
│ ┌────┘ │
│ │ │
┌─▼─────────────▼──┐
│ RU backup │
│ (priority 2) │
└──────────────────┘
Компоненты
На RU-серверах
wg_ruинтерфейс, listen UDP/1939, peers = все ам. серверы (tunnel_ip→pubkey)iptables -t nat -A POSTROUTING -o <wan_iface> -j MASQUERADE— выходящий трафик от ам. серверов наружуiptables -I FORWARD -i wg_ru -j ACCEPT,-o wg_ru -j ACCEPT— пропуск форварда
На ам. серверах
ruинтерфейс, peer = один из RU-серверов (тот что активен сейчас)/etc/wireguard/ru.conf— текущая конфигурация туннеля/etc/wireguard/ru-servers.json— общий список всех RU и ам. серверов (синхронизируется ботом/WebUI)/etc/wireguard/ru-base.aips— базовый набор подсетей вAllowedIPs(создаётся при первой установке)/etc/wireguard/ru-extra.list— дополнительные IP/CIDR, добавленные через бот/etc/wireguard/ru-domains.json— карта домен → список IP (резолвится черезdig)
Скрипты на ам. серверах (/usr/local/bin/)
| Скрипт | Что делает |
|---|---|
ru-failover.py |
Cron каждую минуту. Проверяет handshake/probe текущего peer'а, переключает на другой при падении. Trial-failback при возврате primary. |
ru-set.sh <id> |
Принудительная установка peer'а из JSON по id |
ru-routes.sh add|remove|clear|list|apply |
Управление ru-extra.list + live ip route + iptables mangle + sync allowed-ips через wg syncconf |
ru-domains.py add|remove|list|show|refresh |
Резолв доменов и проксирование результатов в ru-routes.sh |
Маршрутизация трафика
Запрос с телефона на gosuslugi.ru:
1. X-ray на ам. сервере получает пакет на amn0 интерфейсе
2. iptables -t mangle -A PREROUTING -i amn0 -d 95.163.0.0/16 -j MARK --set-mark 100
3. ip rule fwmark 100 lookup 200
4. table 200: default dev ru
5. WG проверяет AllowedIPs пира (95.163.0.0/16 ∈ allowed) → шифрует
6. Пакет идёт в туннель к RU-серверу
7. На RU: pакет приходит на wg_ru, MASQUERADE на wan, идёт в интернет с RU IP
8. Ответ возвращается обратно через NAT → wg_ru → ам. сервер → телефон
Для НЕ-российских сайтов: пакет в mangle не получает MARK 100, идёт по обычному маршруту через провайдера ам. сервера.
Failover
ru-failover.py запускается из cron каждую минуту:
1. Прочитать /etc/wireguard/ru-servers.json (отсортированный по priority)
2. Определить current = peer чей endpoint в /etc/wireguard/ru.conf
3. age = now - last_handshake (от wg show)
4. Если current dead (age > 180 && TCP probe не отвечает && cooldown 5min прошёл):
→ переключиться на ближайший живой
5. Если current не highest-priority И есть более приоритетный живой И cooldown && fail_backoff прошли:
→ переключиться на него (mode = failback test)
6. Если в режиме failback test:
- handshake появился за <60s → success
- не появился → откат на запасной + 30min backoff на повторный failback
Переключение через wg syncconf — без рестарта интерфейса. Маршруты, mangle, расширенные allowed-ips восстанавливаются через ru-routes.sh apply (вызывается из PostUp и сразу после switch).
Синхронизация конфига
ru-servers.json — единый источник правды. Хранится на каждом ам. сервере. Изменения вносятся ТОЛЬКО через бот/WebUI на «локальном» ам. сервере (где бот живёт), затем save_and_distribute() SCP-ит файл на остальные через root SSH-ключ.
Конфиг WG-серверов (/etc/wireguard/wg_ru.conf на RU) бот редактирует напрямую при /ams-add / /ams-remove — добавляет/удаляет [Peer] секции и делает wg syncconf wg_ru.
SSH между серверами
Бот (на одном из ам. серверов) генерирует ed25519 ключ при первом запуске. Этот ключ:
- автоматически прописывается в
/root/.ssh/authorized_keysна всех остальных ам. серверах при/ams-add(или вручную при онбординге) - автоматически прописывается на новых RU при
/server-add(через add-ru-helper.sh) - для существующих RU — добавляется один раз вручную при первичной настройке
После этого бот работает только по ключу, никаких сохранённых паролей.
Уведомления
ru-failover.py каждый switch/success/fail логирует через logger -t ru-failover И шлёт в Telegram если есть /etc/wireguard/notify.env с TG_BOT_TOKEN и TG_CHAT_ID.
С RU-серверов в России TG API часто недоступен, поэтому бот живёт на одном из ам. серверов.