mirror of
https://github.com/andrey271192/kaskad.git
synced 2026-09-20 13:49:56 +00:00
Initial release of Kaskad
Каскадная маршрутизация русских сайтов через свой набор 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/ — шаблоны конфигов
This commit is contained in:
106
docs/architecture.md
Normal file
106
docs/architecture.md
Normal file
@@ -0,0 +1,106 @@
|
||||
# Архитектура
|
||||
|
||||
## Обзор
|
||||
|
||||
Каждый ам. сервер — это **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 часто недоступен, поэтому бот живёт на одном из ам. серверов.
|
||||
Reference in New Issue
Block a user