montana/_internal-private/network-snapshots/NETWORK-SNAPSHOT-v2.0.0.md
2026-05-28 23:22:19 +03:00

19 KiB
Raw Blame History

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 → <city>-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 <ip>: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 → фронт роутит на <city>-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 <alias> <ip> — идемпотентно добавляет 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_MNEMONICinit --mnemonic (фикс-identity).
  • MONTANA_GENESIS_MANIFEST_B64 → кастомный генезис (тестовая когорта) вместо запечённого.
  • MONTANA_D_TEST_OVERRIDEstart --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 <port>/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 <CF>" ".../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), прикладной слой.