# Montana — Network State Snapshot v2.0.0 **Дата:** 2026-05-27 **Предыдущий:** v1.1.0 (`../NETWORK-STATE-RUNBOOK.md`) **Статус:** ВНУТРЕННИЙ — содержит IP, ключи, токены. НЕ публиковать (правило no-IP-in-public, [[reference_metzdowd]]). **Назначение:** полное рабочее состояние сети + точные процедуры восстановления + все известные причины падений на момент крупной переделки VPN-слоя (Москва-мастер, stream-demux, anti-block DNS, failover-watchdog, фикс маршрутизации городов). > Версионирование слепка — ТОЛЬКО по явной команде автора ([[feedback_network_snapshot_on_command]]). --- ## 0. Что изменилось v1.1.0 → v2.0.0 (крупно) 1. **Москва стала мастер-точкой входа** (`de.montana.quest → 176.124.208.93`), домашний РФ-вход. Раньше мастером был Франкфурт. 2. **Moscow :443 = nginx stream ssl_preread демультиплекс** (SNI googletagmanager → xray :8444 Reality; montana.quest/hub → nginx-web :8443). Совмещает VPN-вход и сайт/подписку на одном порту. 3. **Автоматический failover точки входа (3-зеркало)**: цепочка `[Москва#1 → Франкфурт#2 → Хельсинки#3]`, `montana-entry-watchdog` на всех трёх, health = Reality-рукопожатие (не TCP), идемпотентная запись `de.montana.quest`. 4. **Anti-block DNS**: в публичном DNS виден только `de`→Москва + веб; `cdn` (светил все IP) и пер-узловые имена удалены; `mess` за Cloudflare; оркестратор больше не публикует IP узлов. 5. **Фикс маршрутизации городов**: каждый город привязан к своему cascade-выходу (front-independent); Москва убрана как город-выход (только вход). 6. **Test-mode в установщике** (фикс-мнемоника / кастомный генезис / d-override) + тестовая сеть `montana-testnet-01`. --- ## 1. Топология (6 узлов) | alias | IP | хостинг | роль (VPN) | роль (протокол montana-node) | |-------|----|---------|-----------|------------------------------| | moscow | 176.124.208.93 | Timeweb (RU) | **МАСТЕР-ВХОД** (фронт #1), сайт+подписка+хаб | Active (singleton genesis) | | frankfurt | 89.19.208.158 | Timeweb (DE) | фронт #2 (резерв) + exit DE | CandidateVdf | | helsinki | 91.132.142.42 | THE.Hosting (FI) | фронт #3 (резерв) + exit FI | CandidateVdf | | vilnius | 149.154.185.5 | LT | exit LT (docker) | CandidateVdf (test-режим в процессе) | | yerevan | 149.154.184.205 | WorkTitans (AM) | exit AM (docker) | CandidateVdf (test-режим в процессе) | | nicosia | 45.9.13.170 | VMmanager (CY) | exit CY (docker) | CandidateVdf | SSH: `montana-moscow`/`my-timeweb` (через джамп `-J montana-frankfurt` если прямой ssh недоступен), `montana-frankfurt`, `montana-finland`, `montana-vilnius`/`montana-lithuania`, Армения `-i ~/.ssh/montana-frankfurt root@149.154.184.205`, `montana-nicosia`. Удалённые ранее: Amsterdam, Almaty, SPb, Novosibirsk, US/NYC (newyork запись удалена из DNS 2026-05-27). --- ## 2. Архитектура входа и failover **Принцип:** домашний РФ-вход (Москва) → заграничный выход в выбранной стране. Клиент всегда коннектится на фиксированный `de.montana.quest`; сеть привязывает его к живому фронту и переключает при падении — пользователь ничего не делает. ``` клиент → de.montana.quest:443 (= текущий мастер, сейчас Москва) → nginx stream demux: SNI googletagmanager → xray :8444 → Reality, routing по cascade-UUID → -out → exit-страна ``` **Цепочка failover (приоритет):** `moscow:176.124.208.93 → frankfurt:89.19.208.158 → helsinki:91.132.142.42`. - `montana-entry-watchdog` (systemd) на всех трёх фронтах: `/opt/montana-entry-watchdog.sh`. - Health = Reality-рукопожатие: `openssl s_client -connect :443 -servername www.googletagmanager.com` → cert содержит `google` (Reality steal googletagmanager). НЕ голый TCP (nginx/левый сервис прошёл бы TCP-проверку — это роняло сеть). - Логика: первый живой в цепочке владеет `de.montana.quest`; пишут идемпотентно (только при отличии cur≠target) → без гонок/флапа. Гистерезис `FAIL_THRESHOLD=3` × `CHECK_INTERVAL=15с`. TTL записи 60с. - CF-запись `de.montana.quest` id `be42d2634fe62b7c1fd1f54058f24e27`. - **`de.montana.quest` авто-управляемая — вручную НЕ ставить** (watchdog перепишет). - Старый `/opt/montana-failover.sh` на Франкфурте — disabled, устарел (был дефектный TCP-health + master=Москва). --- ## 3. Moscow :443 — stream-demux (вход + сайт на одном порту) ``` nginx stream (:443, ssl_preread) /etc/nginx/stream.d/montana-demux.conf map $ssl_preread_server_name: www.googletagmanager.com → 127.0.0.1:8444 (xray Reality, VPN) default (montana.quest/hub/www) → 127.0.0.1:8443 (nginx-web: сайт, /vpn/sub, hub) xray: listen 127.0.0.1:8444, Reality serverNames=[googletagmanager], dest=googletagmanager:443 (сильная маскировка), универсальный ключ, 8 cascade-клиентов + outbounds nginx-web: 127.0.0.1:8443 (montana.quest cert + hub.montana.quest cert; /vpn/sub → :5008) ``` **xray Restart=always — при падении возможен зомби на :8444 (`bind: address already in use`).** Лечить: `systemctl stop xray; pkill -9 xray; fuser -k 8444/tcp; sleep 2; systemctl reset-failed xray; systemctl start xray`. --- ## 4. Маршрутизация городов (cascade, front-independent) Каждый город → `de.montana.quest` (= текущий фронт) + свой cascade-UUID → фронт роутит на `-out` → выход в стране. **Москва — только вход, НЕ выход** (нет города «Москва» в подписке). | Город в подписке | host | cascade-UUID | outbound на фронте | Выход | |---|---|---|---|---| | 🇫🇮 Хельсинки Монтана | de.montana.quest | `094f9073-aff0-4c07-a4af-6ca4c924f6a9` | helsinki-out | 91.132.142.42 / FI | | 🇩🇪 Франкфурт Монтана | de.montana.quest | `75e281f1-b702-5eb9-ba5c-8a5d38fa3c31` | frankfurt-out→direct | 89.19.208.158 / DE | | 🇦🇲 Ереван Монтана | de.montana.quest | `43ba0c0e-c1e3-4e30-8ae8-c2e68d24d7c7` | armenia-out | 149.154.184.205 / AM | | 🇱🇹 Вильнюс Монтана | de.montana.quest | `fc8a174d-f42b-4945-8548-ab5c9f448f81` | vilnius-out | 149.154.185.5 / LT | | 🇨🇾 Никосия Монтана | de.montana.quest | `dad79315-0b80-5eca-9703-afee839e0131` | nicosia-out | 45.9.13.170 / CY | ВАЖНО (урок v2.0.0): универсальный UUID `e6d355e2…` = «прямой выход НА ФРОНТЕ». Привязывать город к нему НЕЛЬЗЯ (выйдет там, где сейчас фронт = Москва). Город всегда → свой cascade-UUID. --- ## 5. Ключи Reality **Universal Montana key** (клиентский вход + exit-узлы helsinki/frankfurt/vilnius/yerevan/nicosia): - UUID `e6d355e2-2d79-4c96-a373-3b0e6b6f4b0d` - PBK `EkTs2aGKnFNgFZ0f7wgft2sJp3VjwFQqIrwkZKM4gD8` - SID `302805bc0c25e504`, SNI `www.googletagmanager.com` - privateKey `cL7D6FCqH5nWcQlHCKH9uNr-RNwCt5peRAqt8tl9mXs` (секрет; на каждом узле + pre-stage `/etc/montana-vpn/privkey`) **Cascade-UUID на фронте** (reality-entry клиенты, flow="", роутятся к exit-outbound): - montana-universal `e6d355e2…` (→direct на фронте), yerevan `43ba0c0e…`→armenia-out, helsinki `094f9073…`→helsinki-out, vilnius `fc8a174d…`→vilnius-out, nicosia `dad79315…`→nicosia-out, frankfurt `75e281f1…`→frankfurt-out, nyc `db053bb3…`, cascade-verify `25e1779b…` **Moscow own-key** (PBK `svxjTnEZxk6aStkaHSYd2b-br3Pe4yqGcNrugokjEgg`, SID `f976f81b29f78c1f`, SNI montana.quest, privkey `iMWS9kMDTBsvRqXMdjXdoRg50DgB3ZRjvJEZ2LxPm3g`) — оставлен в коде sub-gen (MOSCOW_CASCADE_KEYS / OWN_KEY) но **город Москва на выход отключён**; используется только если фронт = montana.quest. Токены: orchestrator admin `/etc/montana/orchestrator-admin-token` (Moscow); CF API `cfut_k2tVV55op71oquxocV1OHvL9ut32WrXqFzFqQF8M1b53e6ee` (зона `2bc47161267258960d48bedfdf476f1a`), также Keychain `cloudflare-api-token`/`montana-quest`. --- ## 6. DNS (Cloudflare, зона montana.quest) — anti-block минимизация Видно снаружи ТОЛЬКО: ``` de.montana.quest → 176.124.208.93 (вход, авто-управляется watchdog, TTL 60, DNS-only) montana.quest / www / hub → 176.124.208.93 (веб/подписка/хаб, Москва уже видна через de) mess.montana.quest → CF-proxied (origin Франкфурт 89.19.208.158 скрыт; origin-rule port 8443) messenger-api.montana.quest → CF-proxied ``` **Удалены (2026-05-27):** `cdn.montana.quest` (multi-A, светил ВСЕ 5 IP), `entry/frankfurt/helsinki/moscow/newyork.montana.quest` (пер-узловые IP). Бэкап-фронты и выходы НЕ в постоянном DNS — появляются в `de` лишь при failover. Censor видит один домашний RU-IP. CF origin-rule: phase `http_request_origin`, `(http.host eq "mess.montana.quest") → origin.port=8443`. Зона SSL = strict. --- ## 7. Control-plane (Moscow) - **orchestrator** `/opt/montana-orchestrator/server.py`, systemd `montana-orchestrator`, :5020. Registry `/var/lib/montana-orchestrator/nodes.json`. **DNS-passive** (2026-05-27): в `/register` и `watchdog_loop` отключены `cf_add` (cdn re-leak) и `apply_failover` (управлял `de`→Frankfurt, конфликтовал с entry-watchdog → флаппинг `de`). Хранит реестр для sub-gen + auto-cascade provision (см. §8). - **sub-генератор** `/opt/montana-vpn-balance/app.py`, gunicorn :5008, `/vpn/sub`. Читает `/nodes` из оркестратора. CASCADE dict (yerevan/helsinki/vilnius/frankfurt → cascade-UUID), `if alias=="moscow": continue` (Москва не выход). Заголовки `profile-title: base64:TW9udGFuYQ==` (=Montana) + `profile-update-interval: 12`. Rust :5009 (`mt-vpn-balance`) присутствует но nginx /vpn/sub → :5008. - **Front-provision** (на Франкфурте) `/usr/local/sbin/montana-cascade-add ` — идемпотентно добавляет cascade client+outbound+routing на фронт (бэкап→`xray -test`→один рестарт только при изменении). Оркестратор вызывает его по SSH при регистрации узла из BLOCKED_CIDRS (`149.154.0.0/16`). - nginx: stream demux :443 (см §3) + http :80/:8443; efir_org/hub отдельными vhost. Бэкапы конфигов `/root/nginx-baks/`, `*.bak-*`. --- ## 8. Авто-каскад при регистрации ([[project_montana_auto_cascade]]) Оркестратор `/register`: `needs_cascade = ip_in_blocked(ip) or not moscow_reachable`. BLOCKED_CIDRS=`['149.154.0.0/16']` (РКН-residential). Если да → SSH Франкфурт `montana-cascade-add` → пишет в registry `cascade_front`/`cascade_uuid`/`cascade_reason` + `moscow_reachable`/`moscow_rtt_ms`. Узлы в публичный DNS НЕ публикуются. --- ## 9. Протокольный слой (montana-node, :8444 Noise_PQ XX) **Транспортный мэш РАБОТАЕТ** (heartbeat между узлами, Noise_PQ XX). **Консенсус НЕ единый** — каждый узел отдельная singleton-генезис-цепочка (общий генезис `network_name="montana"`, но окна расходятся, NodeTable=1 у каждого). Москва Active (sole proposer), остальные CandidateVdf (грызут admission-VDF τ₂=20160 окон ≈ 14 дней). Причина не-сходимости: нет M7 fast-sync client (отставший узел не догоняет cemented-голову) + DEV-012 multi-confirmer. Genesis-manifest: `network_name` + `peers[]` (label/multiaddr/peer_id/account_id_hex/node_id_hex/bootstrap). peer_id в манифесте косметика (dial по multiaddr). Москва :8444 ufw открыт 2026-05-27 (был закрыт → Москва была изолирована). **VPN-слой полностью отдельно от консенсуса** (xray :443 vs montana-node :8444; разные процессы; узел можно перезапускать не трогая VPN). --- ## 10. Test-mode сети ([[установщик]]) Установщик (`Code/docker/runtime/entrypoint.sh` + `docker-compose.yml`, запушено `ab8910d`): - `MONTANA_MNEMONIC` → `init --mnemonic` (фикс-identity). - `MONTANA_GENESIS_MANIFEST_B64` → кастомный генезис (тестовая когорта) вместо запечённого. - `MONTANA_D_TEST_OVERRIDE` → `start --d-test-override N` (малый D → окна за мс → admission за ~минуту). Тестовая сеть `montana-testnet-01` (2 bootstrap): - armenia: account `c543c4151b69a7a9…`, node `1c77621274ee2f66…`, mnemonic «typical lift fork extra awesome gauge gauge senior brain social two more resource soap runway eagle alter famous cause push mystery sleep have couple» - vilnius: account `597913015db153b0…`, node `4b125501fcf21d4e…`, mnemonic «frame transfer rug post crumble furnace barely theme square play endless december lucky season inspire rough food sister candy lunar list hollow cart icon» - На момент слепка: Вильнюс+Армения в полной переустановке (cargo build), консенсус-тест не завершён. --- ## 11. Все известные причины падений + восстановление ### 11.1 Frankfurt xray restart-race / xray зомби на :8444 (Moscow) `bind: address already in use`, `Start request repeated too quickly`. Лечить: `systemctl stop xray; pkill -9 xray; fuser -k /tcp; sleep 2; reset-failed; start`. ### 11.2 `de.montana.quest` указывает на Москву, но :443 не Reality Если на Москве :443 = nginx без stream-demux или xray с dest=google (не local) → клиенты получают не Reality → нет интернета / TLS-ошибка подписки. Должно быть: nginx stream demux (§3). Проверка: `openssl s_client -connect 127.0.0.1:443 -servername www.googletagmanager.com` → google cert; `-servername montana.quest` → montana.quest cert. ### 11.3 Город выходит не в своей стране (напр. Франкфурт → Москва) Причина: город привязан к универсальному UUID (`e6d355e2`, direct-на-фронте) вместо своего cascade-UUID. Лечить: в sub-gen город → его cascade-UUID (§4). Урок: смена мастер-фронта обнажает такие маппинги. ### 11.4 `de` флаппит между узлами Причина: два писателя DNS (entry-watchdog ↔ оркестратор apply_failover). Лечить: оркестратор DNS-passive (apply_failover/cf_add отключены); `de` пишет только entry-watchdog. ### 11.5 cdn / пер-узловые DNS возвращаются (утечка IP флота) Причина: оркестратор `watchdog_loop` cf_add. Лечить: cf_add отключён (§7). Удалить записи через CF API. ### 11.6 Узел недостижим у РФ-провайдера (IP в 149.154.0.0/16) Завернуть каскадом через достижимый фронт (авто, §8). Долгосрочно: чистый IP / T1-T3 транспорты. ### 11.7 docker build OOM/провал RAM<1.5G→swap; фиксы glibc/context/volume уже в install-docker.sh. ### 11.8 hub/mess отдают чужой сертификат Причина: vhost слушает только 127.0.0.1:8443, на :443 дефолтный блок. Лечить: добавить `listen 443 ssl` блоку (hub) ИЛИ stream-demux маршрутизирует по SNI на :8443 (Moscow). mess за CF (origin-rule :8443). --- ## 12. Health-check команды ``` # вход жив + Reality dig +short de.montana.quest @1.1.1.1 echo | openssl s_client -connect de.montana.quest:443 -servername www.googletagmanager.com 2>/dev/null | grep 'Verify return' # подписка curl -s -o /dev/null -w '%{http_code}' https://montana.quest/vpn/sub # 200 # города выходят правильной страной (xray-client на любом фронте, dial 176.124.208.93:443 + cascade-UUID → ifconfig.io/ip) # watchdog for s in montana-moscow montana-frankfurt montana-finland; do ssh $s 'systemctl is-active montana-entry-watchdog'; done # DNS-утечки (должно быть пусто кроме de+web) curl -s -H "Authorization: Bearer " ".../dns_records?per_page=100" # протокол docker exec montana-node /usr/local/bin/montana-node status --data-dir /var/lib/montana ``` --- ## 13. Задеплоено vs pending - **Прод (живое):** Москва-мастер вход + stream-demux; failover-watchdog 3 фронта; cascade-выходы 5 стран; anti-block DNS; sub-gen :5008 (профиль Montana); auto-cascade; mess за CF. - **В коде, НЕ задеплоено как единый консенсус:** многоузловой apply_proposal (DEV-012), M7 fast-sync client → протокол работает singleton-цепочками. - **В процессе:** консенсус-тест на Вильнюс/Армения (montana-testnet-01, d-override). - **Не построено:** T1-T3 транспорты, mt-egress relay (VPN как протокол-native), прикладной слой.