montana/_internal-private/NETWORK-STATE-RUNBOOK.md
2026-05-27 16:44:03 +03:00

13 KiB
Raw Blame History

Montana — Network State Snapshot & Recovery Runbook

Версия слепка: 1.1.0 Дата: 2026-05-27 Назначение: зафиксировать рабочее состояние сети + точные процедуры восстановления + все известные причины падений. ВНУТРЕННИЙ документ (содержит IP и ссылки на секреты — НЕ публиковать в efir369999/Montana по правилу no-IP-in-public).

Версионирование: при любом изменении топологии/ключей/каскадов — bump версии слепка (1.0.0 → 1.1.0) и обновить соответствующий раздел.


1. Топология (6 узлов)

alias IP хостинг роль сервисы
moscow 176.124.208.93 Timeweb (RU) genesis, control-plane, VPN own-key montana-node :8444, xray :443 (Reality masq montana.quest), nginx :8443/:80, orchestrator :5020, sub-gen :5008
frankfurt 89.19.208.158 Timeweb (DE) genesis, VPN cascade FRONT, VPN direct montana-node :8444, xray :443 (Reality universal) + cascade outbounds
helsinki 91.132.142.42 THE.Hosting (FI) genesis, VPN exit montana-node :8444, xray :443 (Reality universal)
yerevan 149.154.184.205 WorkTitans (AM) VPN exit (docker) docker: montana-node :8444, xray :443, nginx-decoy :80
vilnius 149.154.185.5 LT VPN exit (docker) docker: montana-node :8444, xray :443, nginx-decoy :80
nicosia 45.9.13.170 VMmanager (CY) VPN exit (docker) docker: montana-node :8444, xray :443, nginx-decoy :80

SSH-алиасы: montana-moscow/my-timeweb, montana-frankfurt, montana-finland, montana-armenia, montana-lithuania, montana-nicosia.


2. Архитектура VPN (на момент слепка)

Достижимые у домашних RU-провайдеров фронты: Frankfurt (89.19.208.158), Moscow (176.124.208.93) — диапазоны Timeweb не режутся. Заблокированные напрямую у домашних RU-ISP: Helsinki, Yerevan, Vilnius (диапазоны THE.Hosting / 149.154.0.0/16).

Решение — каскад: все заблокированные города ходят через достижимый фронт Frankfurt (raw double-crypto в текущей версии), выход — в правильной стране.

клиент → de.montana.quest:443 (Frankfurt, Reality) → routing по cascade-UUID → <out> → exit-страна
Город в подписке Коннект (host) UUID flow Выход (IP / страна)
🇩🇪 Франкфурт de.montana.quest e6d355e2 (universal) vision 89.19.208.158 / DE (direct)
🇷🇺 Москва montana.quest c83d4d13 (own) vision 176.124.208.93 / RU (direct)
🇫🇮 Хельсинки de.montana.quest 094f9073 (cascade) none 91.132.142.42 / FI (via FRA)
🇦🇲 Ереван de.montana.quest 43ba0c0e (cascade) none 149.154.184.205 / AM (via FRA)
🇱🇹 Вильнюс de.montana.quest fc8a174d (cascade) none 149.154.185.5 / LT (via FRA)
🇨🇾 Никосия de.montana.quest dad79315 (cascade) none 45.9.13.170 / CY (via FRA)

3. Ключи Reality

Universal Montana key (Helsinki/Frankfurt/Yerevan/Vilnius exit + клиентская подписка):

  • UUID e6d355e2-2d79-4c96-a373-3b0e6b6f4b0d
  • PBK EkTs2aGKnFNgFZ0f7wgft2sJp3VjwFQqIrwkZKM4gD8
  • SID 302805bc0c25e504
  • SNI www.googletagmanager.com
  • privateKey cL7D6FCqH5nWcQlHCKH9uNr-RNwCt5peRAqt8tl9mXs (секрет; на каждом exit-узле в xray config; pre-stage для install: /etc/montana-vpn/privkey)

Moscow own key (masq под свой сайт montana.quest, т.к. :443 делит с сайтом):

  • UUID c83d4d13-fce9-4c07-85f0-c152d4bda3ee
  • PBK svxjTnEZxk6aStkaHSYd2b-br3Pe4yqGcNrugokjEgg
  • SID f976f81b29f78c1f
  • SNI montana.quest
  • privateKey iMWS9kMDTBsvRqXMdjXdoRg50DgB3ZRjvJEZ2LxPm3g (секрет; в xray config Moscow)

Cascade-UUID (на Frankfurt-фронте, маршрутизируют к exit-outbound; flow пустой):

  • yerevan 43ba0c0e-c1e3-4e30-8ae8-c2e68d24d7c7 → outbound armenia-out
  • helsinki 094f9073-aff0-4c07-a4af-6ca4c924f6a9 → outbound helsinki-out
  • vilnius fc8a174d-f42b-4945-8548-ab5c9f448f81 → outbound vilnius-out
  • nicosia dad79315-0b80-5eca-9703-afee839e0131 → outbound nicosia-out

Orchestrator admin token: Moscow /etc/montana/orchestrator-admin-token. CF API token: Keychain cloudflare-api-token / montana-quest.


4. Cloudflare DNS (зона montana.quest, все DNS-only, не proxied)

fi.montana.quest  → 91.132.142.42   (Helsinki)
de.montana.quest  → 89.19.208.158   (Frankfurt — cascade front)
am.montana.quest  → 149.154.184.205 (Yerevan)
lt.montana.quest  → 149.154.185.5   (Vilnius)
cy.montana.quest  → 45.9.13.170     (Nicosia)
cdn.montana.quest → multi-A: 89.19.208.158, 91.132.142.42, 149.154.185.5, 149.154.184.205, 45.9.13.170 (watchdog auto-prune)
montana.quest     → 176.124.208.93  (Moscow — сайт + own-key VPN)

5. Control-plane (Moscow)

  • orchestrator /opt/montana-orchestrator/server.py, systemd montana-orchestrator.service, :5020. Registry /var/lib/montana-orchestrator/nodes.json. API /register /deregister /nodes /pool (нужен secret=admin token). Watchdog probe Reality :443 каждые 30с, prune dead из cdn multi-A.
  • sub-генератор /opt/montana-vpn-balance/app.py, gunicorn :5008, отдаёт /vpn/sub. Карты: ALIAS_HOST, CASCADE (yerevan/helsinki/vilnius → de.montana.quest), OWN_KEY (moscow → montana.quest). Ключи из /etc/montana-vpn/keys.json (sync с Helsinki, таймер montana-vpn-key-sync).
  • nginx :443 → SNI-роутинг montana.quest+hub+efir; ВНИМАНИЕ: на Moscow xray держит :443, nginx на 127.0.0.1:8443 (Reality dest=local nginx). Все enabled на boot.
  • сайт-данные: build-скрипты montana-net-pull, montana-cities-build, aggregator.sh, collector.sh, peer-health.py (на mos/fra/fin). US удалён отовсюду.

6. Frankfurt cascade-config

inbound: reality-in :443 (universal key)
clients: montana-universal(vision), yerevan-cascade(none), helsinki-cascade(none), vilnius-cascade(none), nicosia-cascade(none)
outbounds: direct, blocked, dns-out, armenia-out(→149.154.184.205:443), helsinki-out(→91.132.142.42:443), vilnius-out(→149.154.185.5:443), nicosia-out(→45.9.13.170:443)
routing: user=<cascade-email> → соответствующий <city>-out (Reality client universal к exit)

Бэкапы конфига: /usr/local/etc/xray/config.json.bak-* (последний рабочий — без dokodemo).


7. ВСЕ известные причины падений + восстановление

7.1 Frankfurt xray restart-race (СЛУЧАЛОСЬ 2026-05-26)

Симптом: xray failed, journal bind: address already in use, Start request repeated too quickly. Все каскады + клиентский VPN вниз. Причина: правка live-конфига (новый inbound/порт) + Restart=always → зомби-инстанс держит порт, новый не биндит, systemd крутит рестарты до лимита. Восстановление:

ssh montana-frankfurt 'systemctl stop xray; pkill -9 xray; for p in 443 2096 2097 2098; do fuser -k $p/tcp; done; sleep 3; \
  cp $(ls -t /usr/local/etc/xray/config.json.bak-* | head -1) /usr/local/etc/xray/config.json; \
  xray -test -config /usr/local/etc/xray/config.json; systemctl reset-failed xray; systemctl start xray'

Профилактика: НЕ править live-xray на проде хирургией; правильный путь load-распределения — deploy mt-egress relay, не dokodemo на живой xray.

7.2 ufw блокирует :8444 (узел не пирится входящими)

Симптом: montana-node только исходящие ESTAB, входящих нет; не виден peer-ам. Причина: install-vps-full поднимал ufw с 22/80/443, забывал 8444. Восстановление: ssh <node> 'ufw allow 8444/tcp; ufw reload'. (install-docker.sh уже открывает 8444.)

7.3 Reality-ключи рассинхрон (только Frankfurt работал)

Симптом: клиент TLS-handshake проходит, но прокси не работает на части узлов; работает только один город. Причина: privateKey на узле ≠ PBK в подписке. Восстановление: сверить xray x25519 -i <priv> каждого узла → PBK должен == подписочный. Universal privkey cL7D6FCq… на всех exit. Команда сверки:

ssh <node> 'docker exec montana-xray xray x25519 -i $(jq -r .inbounds[0].streamSettings.realitySettings.privateKey /etc/montana-vpn/xray-config.json)'

7.4 Узел недостижим у конкретного провайдера (IP в РКН-блоке)

Симптом: город не открывается у одного ISP, работает у других / из дата-центра. Причина: IP узла в блок-листе оператора (149.154.0.0/16 = легаси-Telegram; THE.Hosting). НЕ баг сервера. Восстановление: завернуть город каскадом через достижимый фронт (Frankfurt/Moscow) — см. §2. Долгосрочно: T1T3 транспорты (spec B1, не готовы) либо чистый IP.

7.5 Moscow :443 конфликт (сайт vs VPN)

Симптом: упал сайт montana.quest ИЛИ /vpn/sub ИЛИ orchestrator. Причина: xray и nginx делят :443; неверный порядок старта / занятый порт. Восстановление: nginx должен слушать 127.0.0.1:8443 (не :443); xray :443 dest=127.0.0.1:8443. Бэкапы nginx: /root/nginx-bak-*. Проверка: curl -sk --resolve montana.quest:443:127.0.0.1 https://montana.quest/vpn/sub → 200.

7.6 docker build OOM / провал (Armenia/Vilnius при install)

Симптом: install-docker.sh падает на cargo build. Причины: (а) RAM < 1.5G без swap → OOM; (б) Montana wordlist.txt вне build-context (фикс: context = repo root); (в) glibc mismatch (фикс: runtime debian:trixie-slim); (г) volume permission (фикс: chown+runuser); (д) xray x25519 формат вывода (фикс: awk /Password|ublic/). Восстановление: все фиксы уже в install-docker.sh main; при OOM добавить swap.

7.7 cdn.montana.quest содержит мёртвый/блокируемый IP

Симптом: «Auto» попадает на нерабочий узел. Причина: watchdog probe только с Moscow (один vantage) — держит IP, недостижимый у клиента. Восстановление: deregister руками: curl -X POST -d '{"ip":"<ip>","secret":"<token>"}' https://montana.quest/vpn/node/deregister. Долгосрочно: reachability-sensing (новый код mt-net, не задеплоен).


8. Команды проверки здоровья (health-check)

# узлы (фаза + пиры)
for n in moscow frankfurt finland armenia lithuania; do ssh montana-$n '...montana-node status...'; done

# подписка (5 городов)
curl -sk https://montana.quest/vpn/sub | base64 -d

# каскады выходят правильной страной (с Moscow)
ssh montana-moscow 'bash /tmp/test-all-cascades.sh'   # helsinki→FI, vilnius→LT, yerevan→AM

# Reality :443 фронта извне
echo Q | openssl s_client -connect de.montana.quest:443 -servername www.googletagmanager.com -brief

# orchestrator
curl -sk https://montana.quest/vpn/node/health

9. Что задеплоено vs что в коде (на момент слепка)

  • Прод (живое): montana-node v1.0.0 (mos/fra/fin/am/lt/cy), статический каскад через Frankfurt, install-docker.sh (авто-join + VPN-ключи).
  • В коде, НЕ задеплоено: mt-net reachability/steering (M10 A-C), mt-egress (M11 A-B + client + e2e) — юнит-протестировано локально (30+ тестов), вшивание в montana-node (M11 C) pending.
  • Не построено: T1-T3 транспорты (spec B1), English-перевод Network спеки (B5), M7 fast-sync, M8 multi-node apply, авто-апдейт флота.