13 KiB
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→ outboundarmenia-out - helsinki
094f9073-aff0-4c07-a4af-6ca4c924f6a9→ outboundhelsinki-out - vilnius
fc8a174d-f42b-4945-8548-ab5c9f448f81→ outboundvilnius-out - nicosia
dad79315-0b80-5eca-9703-afee839e0131→ outboundnicosia-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, systemdmontana-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. Долгосрочно: T1–T3 транспорты (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, авто-апдейт флота.