feat: one-command install/uninstall + fix delete-ams in WebUI

- install.sh: интерактивный one-liner — ставит WG, ключи, скрипты,
  бот, WebUI, cron; сам поднимает RU-сервер если он чистый
- uninstall.sh: полная очистка (сервисы, конфиги, cron, /opt/kaskad)
  с подтверждением; опц. KASKAD_PURGE_KEYS=1 для затирания ключей
- webui: кнопка «удалить» для зарубежных серверов теперь явно красная
  (class danger.solid), для локального — « нельзя» вместо disabled
- webui: DELETE /api/ams/<id> переписан — портативный python-based
  peer-removal, явные ошибки, поддержка ?force=1
- README + docs/install.md: переписаны под обычного пользователя,
  one-command flow на первом плане, ручной — как fallback

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
andrey271192
2026-05-12 06:28:56 +03:00
parent b856909437
commit f6514e9bba
7 changed files with 768 additions and 185 deletions

214
README.md
View File

@@ -1,104 +1,200 @@
# Kaskad
Каскадная маршрутизация русских сайтов через свой набор RU-серверов (WireGuard) с автоматическим failover, Telegram-ботом и веб-интерфейсом.
**Свой VPN для россиян за границей.** Российские сайты (госуслуги, банки, ВК) открываются через ваш сервер в РФ. Всё остальное — напрямую через зарубежный. Если RU-сервер падает — за минуту переключается на запасной. Управляется из браузера или Telegram.
## Что это
![Каскад работает](https://img.shields.io/badge/status-в%20продакшне-success) ![License](https://img.shields.io/github/license/andrey271192/kaskad) ![Stars](https://img.shields.io/github/stars/andrey271192/kaskad?style=social)
Несколько зарубежных серверов с X-ray («ам.») держат WireGuard-туннели к одному из RU-серверов. Российские IP/домены идут через RU, всё остальное — через зарубежный. Если RU упал — за минуту переключение на следующий по приоритету. Когда восстановился — пробный failback с автоматическим откатом если WG не отвечает.
---
## Зачем это нужно
Живёте за границей и сталкивались с тем, что:
- 🏦 Тинькофф не пускает с заграничного IP
- 🧾 Госуслуги «вы не из России»
- 📺 Кинопоиск, ivi, ВК — недоступны
- 🛍 Озон, Wildberries — корзина не работает
При этом обычный VPN в РФ **тормозит всё подряд**, включая Netflix, рабочие звонки и игры.
**Каскад** делит трафик по умному:
```
телефон/клиент ──> ам. сервер (X-ray) ──┬──> RU primary ──> RU-сайты
├──> RU backup (failover)
└──> RU N (по приоритету)
└──> остальное идёт напрямую через ам.
┌──────────────────────────────────────────┐
вы ───▶ │ зарубежный сервер (Амстердам, X-ray) │
если адрес РФ → 🇷🇺 RU-сервер → инет │
│ всё остальное → 🌍 напрямую │
└──────────────────────────────────────────┘
```
## Возможности
Vk.com видит ваш московский IP. Netflix видит амстердамский. Скорость не страдает.
- **N RU-серверов** в конфиге, упорядочены по приоритету
- **Авто-failover** по handshake age + TCP-проба; cooldown между переключениями; автоматический failback с проверкой
- **Telegram-бот** для всех операций: смотреть статус, переключать вручную, добавлять/удалять серверы, домены, IP
- **Веб-интерфейс** с тем же функционалом
- **Маршруты по доменам**: бот резолвит `vk.com → IP`, добавляет в маршруты на всех ам. серверах. Cron каждые 6ч переподнимает резолв
- **Доп. подсети/IP** добавляются на лету через бот или WebUI; переживают рестарт туннеля и сервера
- **Уведомления в TG** при каждом failover/failback
---
## Структура репозитория
## Что умеет
```
kaskad/
├── bin/ # скрипты для ам. серверов (failover, switch, routes, domains)
├── bot/ # Telegram-бот + systemd unit
├── webui/ # Flask-приложение
├── examples/ # шаблоны конфигов
├── docs/ # подробная документация
└── README.md
-**Авто-failover** — если основной RU-сервер упал, за минуту переключение на запасной. Когда вернулся — автоматически обратно.
- 🎛 **WebUI** — добавлять серверы, домены, IP в один клик. Никакого SSH.
- 🤖 **Telegram-бот** — то же самое из телефона.
- 🌐 **N RU-серверов** в каскаде с приоритетами.
- 🌍 **N зарубежных нод** под одним каскадом — все автоматически переключаются вместе.
- 🔔 **Уведомления в Telegram** при каждом переключении.
- 📋 **Маршруты по доменам** — ввёл `vk.com`, бот сам резолвит IP и держит их в маршрутах.
---
## Установка в одну команду
На зарубежном сервере (Ubuntu 20.04+) с уже работающим X-ray:
```bash
curl -fsSL https://raw.githubusercontent.com/andrey271192/kaskad/main/install.sh | sudo bash
```
## Быстрый старт
Скрипт спросит:
См. [docs/install.md](docs/install.md) для полной установки.
1. Telegram bot token (от [@BotFather](https://t.me/BotFather))
2. Telegram chat ID (узнать у [@userinfobot](https://t.me/userinfobot))
3. Хост вашего RU-сервера + пароль root (пароль нужен один раз)
4. Логин/пароль для WebUI
Краткая последовательность:
Через 2-3 минуты получите:
1. **Настроить первый RU-сервер** вручную (см. `docs/install.md` § «RU-сервер»)
2. **Настроить первый ам. сервер** (см. § «Ам. сервер»)
3. **Создать `/etc/wireguard/ru-servers.json`** по шаблону `examples/ru-servers.example.json`
4. **Запустить TG-бот** на одном из ам. серверов (`bot/ru-tg-bot.service`)
5. **(опц.) Запустить WebUI** на том же ам. сервере (`webui/ru-webui.service`)
6. Дальше — добавлять RU/ам./домены/IP через бот или WebUI
- 🌐 WebUI на `http://ВАШ_СЕРВЕР:8088`
- 🤖 Активного Telegram-бота — `/status` покажет состояние
- 🔁 Авто-failover каждую минуту через cron
## Команды бота
Готово. Никаких ручных правок конфигов.
> 💡 **Если RU-сервер ещё чистый** — скрипт сам поставит на него WireGuard, ip_forward, iptables и поднимет туннель. Достаточно SSH-пароля.
---
## Удаление в одну команду
```bash
curl -fsSL https://raw.githubusercontent.com/andrey271192/kaskad/main/uninstall.sh | sudo bash
```
или, если уже склонировано:
```bash
sudo bash /opt/kaskad/uninstall.sh
```
Спросит подтверждение (`YES`), затем уберёт:
- сервисы, скрипты, cron, WG-туннели, конфиги, `/opt/kaskad/`
X-ray, ваши SSH-ключи и системные пакеты **не трогает**. Если хотите снести и WG-ключи — `KASKAD_PURGE_KEYS=1 sudo bash uninstall.sh`.
---
## WebUI
После установки откройте `http://ВАШ_СЕРВЕР:8088`.
| Что | Как |
|---|---|
| Переключиться на запасной RU | кнопка `backup` в верхней таблице |
| Добавить ещё один RU-сервер | секция «RU-серверы» → «+ добавить RU-сервер», ввести IP/домен и пароль root |
| Добавить ещё одну зарубежную ноду | секция «Ам. серверы» → «+ добавить ам. сервер» |
| **Удалить зарубежный сервер** | красная кнопка `удалить` в строке — peer уберётся со всех RU и из конфига |
| Добавить русский сайт | секция «Домены» → ввести `vk.com ozon.ru` |
| Принудительный refresh DNS для доменов | кнопка `🔄 Refresh DNS` |
Все действия идут с подтверждением, ошибки видны сразу.
---
## Telegram-бот
| Категория | Команды |
|---|---|
| Туннели | `/status`, `/use <id>`, `/primary`, `/backup` |
| RU-серверы | `/server-list`, `/server-add`, `/server-remove`, `/bot-key` |
| Ам. серверы | `/ams-list`, `/ams-add`, `/ams-remove` |
| Маршруты | `/ips`, `/list`, `/add <IP/CIDR>`, `/remove <IP/CIDR>`, `/clear` |
| Домены | `/list-domains`, `/add-domain <domain>`, `/remove-domain <domain>`, `/show-domain <domain>`, `/refresh-domains` |
| Маршруты | `/ips`, `/list`, `/add <IP>`, `/remove <IP>`, `/clear` |
| Домены | `/list-domains`, `/add-domain <d>`, `/remove-domain <d>`, `/show-domain <d>`, `/refresh-domains` |
| Прочее | `/help` |
Полный синтаксис: [docs/bot.md](docs/bot.md).
Полный синтаксис [docs/bot.md](docs/bot.md).
## Веб-интерфейс
---
Запускается на любом ам. сервере (там же где бот), HTTP basic auth.
## Как это работает (короткая версия)
После запуска: `http://<ам-сервер>:8088`
1. На каждом зарубежном сервере поднят WireGuard-туннель `ru` → к выбранному RU-серверу.
2. iptables `mangle` помечает трафик от X-ray меткой `100`, `ip rule` отправляет его в таблицу маршрутизации `200`, где default → через туннель.
3. Маршруты на конкретные RU-подсети/IP добавляются в `ru-base.aips` и `ru-extra.list`.
4. Cron каждую минуту запускает `ru-failover.py`: проверяет handshake + TCP-пробу на RU. Если пусто > N секунд — переключает endpoint на следующий по приоритету.
Подробнее: [docs/webui.md](docs/webui.md).
Деталки — [docs/architecture.md](docs/architecture.md).
## Архитектура
---
См. [docs/architecture.md](docs/architecture.md) — как устроены failover, маршрутизация, синхронизация конфига между серверами.
## Структура репозитория
```
kaskad/
├── install.sh ← одна команда — всё ставится
├── uninstall.sh ← одна команда — всё убирается
├── bin/ ← скрипты для ам. серверов
├── bot/ ← Telegram-бот
├── webui/ ← Flask-приложение
├── examples/ ← шаблоны конфигов (если ставите вручную)
└── docs/ ← подробная документация
```
---
## Безопасность
- Конфиги (`ru-servers.json`, `notify.env`, `webui.env`) с правами `600`, **не коммитятся** в репо
- SSH между серверами — по ключам; пароли используются только при первичной онбординге нового сервера через `password=` в боте/WebUI и **сразу затираются** после установки ключа
- Веб-интерфейс через basic auth, рекомендуется ставить за HTTPS reverse-proxy (nginx/caddy)
- Telegram-бот принимает команды только от заранее заданного `TG_CHAT_ID`
- Все конфиги (`ru-servers.json`, `notify.env`, `webui.env`) с правами `600`, **не коммитятся**.
- Между серверами — только SSH-ключи. Пароли используются один раз, при добавлении нового сервера, и **сразу затираются**.
- WebUI защищён HTTP basic auth. Рекомендация: поставьте за HTTPS reverse-proxy (Caddy, Nginx, Traefik).
- Telegram-бот принимает команды только от заранее заданного `TG_CHAT_ID`.
---
## Требования
- Ubuntu / Debian 20.04+ на ам. сервере (где будет WebUI и бот) — root доступ
- Ubuntu / Debian 20.04+ на RU-сервере — root + SSH-пароль (нужен один раз)
- На ам. сервере: уже настроенный X-ray (3x-ui подойдёт) с интерфейсом `amn0`
- На RU-сервере: открыт UDP/1939 наружу (или проброс на роутере)
---
## FAQ
**Не работает «удалить» в WebUI?** — кнопки `удалить` рядом с зарубежными серверами теперь явно красные. Если показывает «⛔ нельзя» — это сервер, на котором сам WebUI запущен; такой нельзя убрать (надо сначала перенести WebUI на другой узел).
**Сервер удалён, но peer остался на RU?** — при удалении WebUI сам делает `wg set wg_ru peer ... remove` на всех RU. Если RU был недоступен — попросит подтверждение и удалит запись принудительно (`force`).
**Скорость упала?** — каскад не должен влиять на не-RU трафик. Если падает — проверьте `iptables -t mangle -L PREROUTING -v` (помечается ли трафик) и `ip rule show`.
**Бот молчит**`journalctl -u ru-tg-bot -f`. Чаще всего: неверный `TG_BOT_TOKEN` или `TG_CHAT_ID`, или сервер не может выйти к `api.telegram.org`.
Подробнее: [docs/troubleshooting.md](docs/troubleshooting.md).
---
## Связанные проекты
- 🔧 **[keenetic-unified](https://github.com/andrey271192/keenetic-unified)** — мониторинг роутеров Keenetic с TG-ботом и веб-дашбордом
- 🌐 **[keenetic_ssh-web](https://github.com/andrey271192/keenetic_ssh-web)** — веб-панель shell-команд на самом роутере
- 🛣 **[keenetic-dns-routes](https://github.com/andrey271192/keenetic-dns-routes)** — DNS-маршрутизация без HydraRoute Neo
- 🔧 [keenetic-unified](https://github.com/andrey271192/keenetic-unified) — мониторинг роутеров Keenetic
- 🌐 [keenetic_ssh-web](https://github.com/andrey271192/keenetic_ssh-web) — веб-панель shell-команд на роутере
- 🛣 [keenetic-dns-routes](https://github.com/andrey271192/keenetic-dns-routes) — DNS-маршрутизация без HydraRoute Neo
---
## Поддержка проекта
## Поддержать проект
Если **Kaskad** оказался полезен — поддержи разработку:
- **GitHub:** [andrey271192/kaskad](https://github.com/andrey271192/kaskad) — поставь звезду
- 💖 **Boosty:** [boosty.to/andrey27/donate](https://boosty.to/andrey27/donate)
- 💳 **Ozon Bank (СБП):** [перевод](https://finance.ozon.ru/apps/sbp/ozonbankpay/019dc200-2a5d-7931-a619-782d285f6798)
- ✉️ **Telegram:** [@Iot_andrey](https://t.me/Iot_andrey) — вопросы, предложения, баги
---
- ⭐ Поставьте звезду на [andrey271192/kaskad](https://github.com/andrey271192/kaskad)
- 💖 [Boosty](https://boosty.to/andrey27/donate)
- 💳 [Ozon Bank СБП](https://finance.ozon.ru/apps/sbp/ozonbankpay/019dc200-2a5d-7931-a619-782d285f6798)
- ✉️ Telegram: [@Iot_andrey](https://t.me/Iot_andrey) — вопросы, баги, идеи
## Лицензия