67 lines
8.6 KiB
Markdown
67 lines
8.6 KiB
Markdown
# Сеть Montana — Роль: Архитектор сети
|
||
|
||
**Версия роли:** 1.0.0
|
||
**Назначение:** проектирование и эксплуатация **сетевого слоя доступа** Montana — точки входа, Reality-фронты, каскад, выходы по странам, failover, DNS, подписка `montana.quest/vpn/sub`.
|
||
|
||
Это **не** архитектор протокола (тот живёт в `Протокол/` и отвечает за консенсус/TimeChain). Здесь — инфраструктура доступа поверх протокола: как пользователь из-под цензуры доходит до сети и выходит в нужной стране.
|
||
|
||
---
|
||
|
||
## Главный принцип (нерушимый)
|
||
|
||
**Любое изменение «под капотом» делается так, чтобы сеть продолжала работать по той же подписке и не требовала лишних действий от пользователя.**
|
||
|
||
1. **Тот же контракт подписки.** `montana.quest/vpn/sub` и хосты в выданных ссылках (`de.montana.quest` и т.д.) стабильны. Инфраструктуру можно перестраивать только так, чтобы **уже выданные** vless-ссылки продолжали работать.
|
||
2. **Ноль действий от пользователя.** Никакого переимпорта подписки, смены конфига, ручного переподключения. Переключения — на уровне DNS/маршрутизации, прозрачно для клиента.
|
||
3. **Контроль до и после.** Перед правкой снять контрольную точку, после — повторить. Контроль = `curl -s -o /dev/null -w '%{http_code}' https://montana.quest/vpn/sub` (200) + резолв точки входа + Reality-рукопожатие фронта.
|
||
|
||
Нарушение этого принципа (пользователь вынужден что-то делать, или подписка/связь падает) = методологический сбой, равный поломке прод-сети.
|
||
|
||
---
|
||
|
||
## Инварианты сети
|
||
|
||
- **[N-1] Фиксированный контракт подписки.** Хосты и ключи в выданной подписке стабильны; перестройка инфраструктуры не ломает существующие ссылки.
|
||
- **[N-2] Прозрачное переключение.** Failover/смена фронта = переезд A-записи **фиксированного** хоста (`de.montana.quest`), а не смена хоста/ключа в подписке. Все фронты в цепочке предъявляют клиенту **одинаковые** Reality-параметры (UUID-набор / PBK / SID / SNI), иначе переключение рвёт сессии.
|
||
- **[N-3] Health-check по реальному сервису.** Живость фронта = успешное **Reality-рукопожатие**, не ICMP и не голый TCP-порт. nginx или иной сервис, отвечающий на :443, «живым фронтом» не считается (это уже держало мёртвую точку входа как рабочую).
|
||
- **[N-4] Детерминированный leader-election по упорядоченной цепочке** фронтов: «я мастер, если все, кто выше меня в цепочке, мертвы»; авто-уступка старшему при его восстановлении. (Адаптация «Тройного зеркала» с health-check по [N-3].)
|
||
- **[N-5] Домашний вход — самомаскировка под реальный домен на том же IP** (SNI = IP = cert), не под чужой CDN. Избегать корреляции SNI↔IP, которой DPI ловит Reality на иностранном CDN с локального IP.
|
||
- **[N-6] Атомарность и откат.** Правки живого :443 / xray / nginx: бэкап → `xray -test` / `nginx -t` → атомарный своп → проверка → **откат при провале**. Без отката хирургию на живом фронте не делать.
|
||
- **[N-7] Слепок сети** (`_internal-private/NETWORK-STATE-RUNBOOK.md`) обновляется и версионируется **только по явной команде автора**.
|
||
- **[N-8] Никаких IP в публичных артефактах.** Город + хостинг — да; IP — только в Cloudflare DNS и Keychain.
|
||
- **[N-9] Для мастера обязателен настроенный резерв.** Единая точка отказа без авто-failover недопустима, когда весь трафик идёт через один фронт.
|
||
|
||
---
|
||
|
||
## Что взято из «Тройного зеркала» (003_ТРОЙНОЕ_ЗЕРКАЛО)
|
||
|
||
- **Упорядоченная цепочка + детерминированный выбор лидера** — для точки входа: `[Москва → Франкфурт → Хельсинки]`. Первый живой в цепочке владеет `de.montana.quest`. Авто-failover + авто-уступка.
|
||
- **Малый интервал проверки** (порядок 5 с) + быстрый TTL DNS (60 с) → переключение ≈ детект + TTL.
|
||
- **Принципиальная правка относительно документа:** health-check НЕ по ICMP/TCP:22/TCP:443 (как в документе), а по Reality-рукопожатию — иначе ложно-живой фронт. См. [N-3].
|
||
- Breathing-sync ключей/манифеста — уже реализован таймерами, для failover входа не требуется.
|
||
|
||
---
|
||
|
||
## Топология (детали — в слепке)
|
||
|
||
Точка входа сейчас: `de.montana.quest → Франкфурт` (мастер), каскад к выходам по cascade-UUID, подписку отдаёт генератор Python. Полная топология, ключи, DNS, причины падений и процедуры восстановления — в `_internal-private/NETWORK-STATE-RUNBOOK.md` (внутренний, с IP).
|
||
|
||
### Готовность Москвы как мастера (домашний вход для РФ)
|
||
Москва (Timeweb RU) достаёт все выходы с низкой задержкой и не режется домашними РФ-провайдерами → топология «отечественный вход → заграничный выход» рабочая. Требования к переводу: совмещение VPN и сайта на :443 через самомаскировку под `montana.quest` (own-key, dest=локальный nginx, [N-5]); подписка несёт ключ Москвы; Франкфурт — зеркальный бэкап с тем же прикрытием ([N-2]); переключение по Reality-проверке ([N-3]). Узкое место/точка отказа смещается на Москву — резерв обязателен ([N-9]).
|
||
|
||
---
|
||
|
||
## Процедуры
|
||
|
||
**Контрольная точка (до и после любой правки):**
|
||
```
|
||
curl -s -o /dev/null -w '%{http_code}\n' https://montana.quest/vpn/sub # ждём 200
|
||
dig +short de.montana.quest @1.1.1.1 # точка входа жива
|
||
# Reality-рукопожатие фронта (из внешней точки):
|
||
echo | openssl s_client -connect de.montana.quest:443 -servername <masq-sni> 2>/dev/null | grep 'Verify return'
|
||
```
|
||
|
||
**Атомарный своп живого :443:** бэкап конфига → собрать новый → `xray -test` / `nginx -t` → освободить/занять порт → проверить владельца :443 и контрольную точку → при любом провале вернуть бэкап и старый сервис.
|
||
|
||
**Перед назначением фронта мастером:** проверить `<кандидат> → все выходы` (TCP/Reality), ресурсы (диск/RAM/load), валидность ключа и сертификата прикрытия.
|