Compare commits
14 Commits
adecf36ffd
...
3c7ca3416b
| Author | SHA1 | Date | |
|---|---|---|---|
| 3c7ca3416b | |||
| 9cd6d4e22c | |||
| 7bba8cf853 | |||
| 539f1a07ed | |||
| 5cdedb376a | |||
| 9359f9ec4f | |||
| cacd582303 | |||
| b23ca3a890 | |||
| c87d7e7442 | |||
| fc245c23c7 | |||
| 5116abae07 | |||
| 4fc7cbf688 | |||
| b04033d15a | |||
| b0559fdbed |
@@ -1,57 +1,51 @@
|
||||
---
|
||||
_last_updated_: 2026-05-31T12:00:00+03:00
|
||||
session_id: 2026-05-31-vehicles-loader-verify-email-fix
|
||||
_last_updated_: 2026-06-05T02:00:00+03:00
|
||||
session_id: 2026-06-05-iis-cutover-and-winacme-renewal
|
||||
---
|
||||
|
||||
# Next session handoff
|
||||
|
||||
_Сессия: live-verify прогона `vehicles-loader 0.4.0` на проде СТО Стайер + находка/фикс email-бага.
|
||||
Таска `vehicles-loader-progress-deploy` закрыта 🟢. Прод стабилен, ничего не висит._
|
||||
_Сессия: (1) full DNS cutover на RUVDS достигнут; (2) поднят постоянный win-acme HTTP-01 auto-renewal
|
||||
на RUVDS IIS — дедлайн cert-expiry 2026-07-22 СНЯТ. Source НЕ заглушен (warm rollback). Всё проверено,
|
||||
ничего не висит._
|
||||
|
||||
## Recent commits
|
||||
|
||||
- `c588326c` tasks(vehicles-loader-progress-deploy): close 🟢 — verify ok + email-recipient fix
|
||||
- `9cd6d4e2` task(iis-migration): full DNS cutover reached 2026-06-05
|
||||
- (+ commit этой сессии: win-acme renewal pipeline + wiki concept)
|
||||
|
||||
## Что сделано (verify прогона Sun 31.05 06:21→07:53 MSK)
|
||||
## Что сделано (iis-migration, 05.06)
|
||||
|
||||
- ✅ Progress-logging 0.4.0 работает: журнал показал движение по всем фазам (▶/батчи/✓/delete-sweep),
|
||||
НЕ тишина. `Finished … Deactivated successfully` (exit 0). `importRun id=4 ok`, `reportJson errors:[]`.
|
||||
- ✅ **Email-баг починен:** `STOSTAYER_MAIL_TO=site@stostayer.ru` (отчёт слался сам себе) →
|
||||
`vitya.kuznetsov@gmail.com` в `/etc/stostayer/vehicles-loader.env` на хосте (бэкап
|
||||
`vehicles-loader.env.bak.20260531`). `FROM=site@stostayer.ru` без изменений (SMTP-аккаунт релея).
|
||||
Доставка на gmail подтверждена тест-письмом (`ACCEPTED=[gmail]`, `250 queued as 8732C122F18`).
|
||||
**Подхватится автоматом на след. прогоне 06:21 — отдельно проверять не нужно** (но если хочешь
|
||||
100% — глянь, что боевой отчёт за 01.06 реально упал в gmail).
|
||||
|
||||
## Follow-up'ы по vehicles-loader (НЕ блокеры, живут в `stostayer.new`, не в .admin)
|
||||
|
||||
| Что | Деталь |
|
||||
|---|---|
|
||||
| units-фаза медленная | 1h 31m на 100529 rows (vehicles 3884 за 3с для сравнения). Кандидат — батч-инсёрт / индексы. Весь прогон = практически только units. |
|
||||
| generation `unmatched:51` | 51 поколение не сматчилось при импорте. Не ошибка, но проверить — не теряем ли данные. |
|
||||
| `config/default.json` дефолт `to` | всё ещё `site@stostayer.ru` (прод перекрыт env, но дефолт вводит в заблуждение). Выровнять в репо `stostayer.new`. |
|
||||
|
||||
## Открытые треки (.admin, перенос — ещё живые)
|
||||
|
||||
| Трек | Готовность | Entry-point |
|
||||
|---|---|---|
|
||||
| `harden-books-vds-exposed-ports` | ⚪ ready (user сказал «пока нет» на mongo-allowlist) | `.tasks/harden-books-vds-exposed-ports.md` |
|
||||
| `books-bookva-user-whitelist-gathering` | ⚪ ready — gathering от учредителя | `.tasks/STATUS.md` |
|
||||
| `stateful-split-volume-copy` / `infra-inventory` | ⚪ ready | `.tasks/STATUS.md` |
|
||||
- ✅ **Full cutover:** все 25 hostname authoritative на RUVDS `80.64.31.36`. На windows-source ничего authoritative.
|
||||
- ✅ **win-acme auto-renewal** на RUVDS: 25-SAN LE cert (до **2026-09-03**) во всех SNI-биндингах +
|
||||
SYSTEM scheduled task `win-acme-renew-snolla` (renew 55д до expiry). RUVDS больше НЕ зависит от
|
||||
домашнего traefik по сертификатам.
|
||||
- Gotcha решён: OWIN-catch-all CMS жрал `/.well-known/acme-challenge/` → challenge вынесен в отдельное
|
||||
IIS-приложение (пул «No Managed Code») + патч шаблона `C:\win-acme\Web_Config.xml`.
|
||||
- Артефакты: `scripts/iis-migration-to-ruvds/03-ruvds-winacme.ps1` + `winacme-Web_Config.xml`;
|
||||
recipe в `.wiki/concepts/winacme-iis-owin-catchall-http01.md`.
|
||||
- Доступ к RUVDS: SSH `~/.ssh/ruvds-iis-migration` → `Administrator@80.64.31.36` (elevated сессия).
|
||||
|
||||
## Спроси user'а
|
||||
|
||||
- (vehicles-loader) Делать ли follow-up'ы (units-perf / generation-unmatched / default.json)? Все три —
|
||||
в репо `stostayer.new`, не в .admin. Не срочные.
|
||||
- **Decommission `snolla` site** на windows-source — ждём soak (~2026-06-12) + drain кэша, или раньше?
|
||||
Когда решит: elevated PS → `Stop-Website snolla` → архив `C:\sites\snolla` (8.66 ГБ) → kreknin +
|
||||
cleanup temp SSH-ключей/FW-правил. (win-acme на RUVDS от этого не зависит — он самостоятелен.)
|
||||
- `maljarka.tandemmebel.ru` 502 — чинить CMS-тенант отдельно? (pre-existing, не блокер; HTTPS-cert у него валиден).
|
||||
|
||||
## Не делать (preemptive guards)
|
||||
|
||||
- **Не форсить baseline-reset** vehicles-loader без явного запроса — шлёт клиенту внеплановое email.
|
||||
- **Не возвращать `:9200` / stateful-порты на `0.0.0.0`** без IP-allowlist (books VDS, ransom-бот).
|
||||
- **Не `ssh + docker compose up -d`** на VDS Portainer-stacks — только Portainer API (искл. traefik/portainer).
|
||||
- **branch ahead от origin** — push без явного grant'а (Rule 4). Этой сессии grant НЕ давали.
|
||||
- **Не `--test` в win-acme под SSH** — включает интерактив, виснет. Для staging — `--baseuri <staging>`.
|
||||
- **Не трогать `acme-challenge` IIS-приложение / пул «No Managed Code» / патченый `Web_Config.xml`** —
|
||||
на них держится авто-renewal. Detail: `.wiki/concepts/winacme-iis-owin-catchall-http01.md`.
|
||||
- **Не `Stop-Website snolla` пока хвост кэша течёт / без явного запроса** (warm rollback).
|
||||
- IIS-правки — elevated shell. **branch ahead от origin** — push без явного grant'а (Rule 4); grant НЕ давали.
|
||||
|
||||
## Memory updates за сессию
|
||||
|
||||
- (нет нового на этом раунде) — email-фикс зафиксирован в task-файле + STATUS.md, схема деплоя и
|
||||
инфра-гочи уже в `stostayer.new/.wiki/concepts/client-infra-access.md`.
|
||||
- (нет нового файла; знание — в wiki concept + task decisions log)
|
||||
|
||||
## ⚠️ Sensitive (НЕ в git)
|
||||
|
||||
- Корневой `C:\sites\snolla\web.config` содержит plaintext-креды (MSSQL/SMTP/Azure/API-ключи). Pre-existing,
|
||||
не вводилось этой сессией. Если будешь декоммишить/архивировать — не плодить копии в трекаемых местах.
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
# Admin Task Board
|
||||
_Updated: 2026-06-05 (вечер) — 🟡 `fix-nl-vds-reality-pq-dest`: по команде user применён server-side fix + ротация кредов. Reality dest intel→microsoft (x-ui.db + restart), сквозной тоннель через реальный :443 = HTTP 204; 32030 жив. Креды ротированы (root SSH / panel user+pass / panel secret-JWT — светились в плейнтексте; новые в `pass nl-vds-3xui/full-env`, старые отклоняются, БД-бэкап на сервере). Остался client-side: user меняет SNI в v2rayN (`pqmkayaxo2`→microsoft) + подтверждает → close._
|
||||
_Updated: 2026-06-05 — заведена `fix-nl-vds-reality-pq-dest`. Новый NL VDS (213.176.64.253, 3x-UI/Xray 26.6.1): диагностирован отказ Reality-инбаунда 443 — **ML-DSA-65 (PQ) × dest `www.intel.com` (Akamai шлёт HRR)**; plain VLESS 32030 работает. Узел+root-cause в вики (`nl-vds-3xui`, `reality-pq-mldsa65-dest-incompatibility`); креды в `pass nl-vds-3xui/full-env`._
|
||||
_Updated: 2026-05-31 — 🟢 `vehicles-loader-progress-deploy` **closed**: live-verify прогона Sun 31.05 06:21→07:53 MSK прошёл — progress-logging показывает движение по всем фазам (▶/батчи/✓/delete-sweep), НЕ тишина; exit 0; `importRun id=4 ok`, `reportJson errors:[]`. **Попутно найден+починен email-баг:** `STOSTAYER_MAIL_TO=site@stostayer.ru` (слалось само себе) → `vitya.kuznetsov@gmail.com` в host env (бэкап `.bak.20260531`); доставка на gmail подтверждена тест-письмом (`250 queued`). Follow-up'ы (не блокеры): units-фаза 1h31m на 100k rows = узкое место; generation `unmatched:51`; репо `config/default.json` дефолт `to` всё ещё site@ (прод перекрыт env)._
|
||||
_Updated: 2026-05-30 — 🟡 `vehicles-loader-progress-deploy`: деплой 0.4.0 ВЫПОЛНЕН (build здесь → push `docker.stostayer.ru` → host pull + re-tag `:latest`=0.4.0, 0.3.0 retained). Acceptance #1 ✅. Verify-окно = natural (user-выбор, не форсим baseline → клиент без внепланового email). timer next trigger Sun 2026-05-31 06:21 MSK → live-verify journalctl в след. сессию. Open Q #1 (push кода) снят: `a74ef73` уже в origin/master._
|
||||
_Updated: 2026-05-30 — заведена ⚪ `vehicles-loader-progress-deploy` (handoff из stostayer.new). Progress-logging 0.4.0 зашипан в коде (stostayer.new `a74ef73`, 24/24 теста); ops-follow-up — rebuild образа той же схемой (build здесь → push `docker.stostayer.ru` → host pull+re-tag) и снять `journalctl` с боевого прогона (закрывает не-верифицированный 5-й критерий «journalctl показывает движение»). Попутно добивает остаток email-SEND из `vehicles-loader-image-distribution`._
|
||||
@@ -25,6 +27,15 @@ _Updated: 2026-05-26 — заведена `bookva-tenant-cutover-prep` ⚪ (7-st
|
||||
|
||||
_Updated: 2026-05-25 (`iis-migration-to-ruvds` 🟢 closed Phase 1 per user decision — 9/24 hostnames live на RUVDS, source IIS оставлен running. `migrate-elasticsearch-to-books-vds` 🟢 closed ранее сегодня. 16 IIS hostnames + LE renewal pipeline + decommission — descoped в Closure note, не отдельные tracker tasks.)_
|
||||
|
||||
## 🟡 [fix-nl-vds-reality-pq-dest] — Reality-инбаунд 443 на NL VDS (213.176.64.253): server-side done, ждёт client-side
|
||||
**Status:** 🟡 server-side fix + cred-rotation применены и проверены 2026-06-05; остался один client-side шаг (user меняет SNI в v2rayN) + подтверждение → закрыть.
|
||||
**Where I stopped:** ✅ dest `www.intel.com`→`www.microsoft.com` на инбаунде 443 (x-ui.db + restart), сквозной тоннель через реальный :443 (SNI microsoft) = HTTP 204; 32030 жив. ✅ Креды ротированы (root SSH pass / panel user+pass / panel secret-JWT — оригиналы светились в плейнтексте), всё в `pass nl-vds-3xui/full-env`, БД-бэкап на сервере. Root cause: ML-DSA-65 (PQ) × intel/Akamai (HRR), разбор в `.wiki/concepts/reality-pq-mldsa65-dest-incompatibility.md`.
|
||||
**Next action:** user в v2rayN профиль `pqmkayaxo2`: SNI → `www.microsoft.com`, reconnect. Подтвердит, что Reality поднялся → 🟢 close. См. [fix-nl-vds-reality-pq-dest.md](fix-nl-vds-reality-pq-dest.md).
|
||||
**Branch:** n/a (admin ops)
|
||||
<!-- created-by: vitya@.admin-exec / 2026-06-05 / trigger: user-задача "не получается vless+Reality" -->
|
||||
|
||||
---
|
||||
|
||||
## 🟢 [vehicles-loader-progress-deploy] — closed 2026-05-31 — 0.4.0 задеплоен + live-verify прошёл. Прогон Sun 31.05 06:21:48→07:53:14 MSK на changed-выгрузке: журнал показал движение по всем фазам (▶ branches/vehicles/units/delete-sweep, батч-прогресс `manufacturers 18/183…`, `units 3/26…`, `✓ done: N rows`, per-model delete-sweep), НЕ тишина. exit 0, `importRun id=4 ok`, `reportJson errors:[]`. **Email-баг найден+починен:** `STOSTAYER_MAIL_TO` слался сам себе (`site@stostayer.ru`) → исправлен на `vitya.kuznetsov@gmail.com` в host env (бэкап `.bak.20260531`), доставка на gmail подтверждена тест-письмом. Все 4 acceptance ✅. См. [vehicles-loader-progress-deploy.md](vehicles-loader-progress-deploy.md).
|
||||
**Follow-ups (не блокеры, в stostayer.new):** (1) units-фаза 1h31m на 100529 rows — узкое место, батч-инсёрт/индексы; (2) generation `unmatched:51` — проверить не теряем ли данные; (3) `config/default.json` дефолт `to: site@stostayer.ru` выровнять (прод перекрыт env).
|
||||
**Branch:** n/a
|
||||
|
||||
34
.tasks/fix-nl-vds-reality-pq-dest.md
Normal file
34
.tasks/fix-nl-vds-reality-pq-dest.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# fix-nl-vds-reality-pq-dest
|
||||
|
||||
**Status:** 🟡 server-side done 2026-06-05 — awaiting client-side SNI change + user confirm
|
||||
**Created:** 2026-06-05
|
||||
|
||||
## Проблема
|
||||
Reality-инбаунд на 443 (NL VDS `213.176.64.253`, 3x-UI) не коннектится. Root cause доказан:
|
||||
ML-DSA-65 (post-quantum REALITY) × dest/SNI `www.intel.com` (Akamai, не поддерживает PQ key-exchange
|
||||
`X25519MLKEM768` → HelloRetryRequest → borrowed-TLS handshake REALITY не достраивается). Plain VLESS
|
||||
на 32030 работает (там `security: none`). Полный разбор + изоляционная матрица:
|
||||
`.wiki/concepts/reality-pq-mldsa65-dest-incompatibility.md`; узел: `.wiki/entities/nl-vds-3xui.md`.
|
||||
|
||||
## Fix (рекомендация — НЕ применён, ждёт команды)
|
||||
Сменить `www.intel.com` → `www.microsoft.com` (PQ-совместим, проверен 2026-06-05), симметрично:
|
||||
1. **Сервер, инбаунд 443:** `realitySettings.target` → `www.microsoft.com:443`, `serverNames` → `["www.microsoft.com"]`.
|
||||
2. **Клиент v2rayN, профиль `pqmkayaxo2`:** SNI → `www.microsoft.com`.
|
||||
|
||||
Менять через панель 3x-UI (Inbounds → edit) ИЛИ правкой `x-ui.db` + reload xray. Активное соединение
|
||||
на 32030 это не заденет. Альтернатива (проще, но теряем PQ): выключить ML-DSA-65 на инбаунде, оставить intel.
|
||||
|
||||
## Acceptance
|
||||
- v2rayN профиль `pqmkayaxo2` (Reality 443) подключается, трафик идёт.
|
||||
- Plain VLESS 32030 продолжает работать.
|
||||
|
||||
## Done 2026-06-05 (server-side, по команде user "и то и другое")
|
||||
- ✅ Reality dest `www.intel.com:443`→`www.microsoft.com:443` + serverNames→`["www.microsoft.com"]` (правка `x-ui.db` id=1 + `x-ui restart`). Проверено сквозным тоннелем (temp-клиент → реальный `:443`, SNI microsoft, uuid 5da48418+vision+mldsa65Verify) → **HTTP 204**. 32030 жив.
|
||||
- ✅ Креды ротированы (оригиналы были в плейнтексте): root SSH pass (новый работает, старый Access denied), panel username+password (CLI `x-ui setting`, bcrypt в БД), panel `secret` JWT (убил install API token/сессии). Всё в `pass nl-vds-3xui/full-env`. БД-бэкап `/root/x-ui.db.bak.20260605_083658`.
|
||||
|
||||
## ⏳ Остаётся (client-side, делает user)
|
||||
В v2rayN профиль `pqmkayaxo2`: **SNI** `www.intel.com` → `www.microsoft.com`, save, переподключиться → должно подняться. (Не правил guiNDB.db: v2rayN держит активное соединение.) После подтверждения — закрыть таску 🟢.
|
||||
|
||||
## Where I stopped
|
||||
Server-side fix + ротация применены и проверены. Жду от user: смену SNI в v2rayN + подтверждение, что профиль Reality поднялся.
|
||||
<!-- created-by: vitya@.admin-exec / 2026-06-05 / trigger: user-задача "не получается vless+Reality" -->
|
||||
@@ -61,6 +61,9 @@ Migrate IIS hosting from [[../entities/windows-recovery-host]] (DESKTOP-NSEF0UK)
|
||||
- **На RUVDS 80.64.31.36** (9): `kupimknigi.spb.ru`, `emspb.ru` + `www.emspb.ru`, `pilorama98.ru` + `www.pilorama98.ru`, `labtools.pro` + `www.labtools.pro`, `rimiz.ru` + `www.rimiz.ru`. TTL на swap'нутых: 3600s (auth ns1.reg.ru).
|
||||
- **На windows source 94.19.247.14** (16): `labtools.ru` + `www.labtools.ru`, `snolla.com` + 12× *.snolla.com (incl `rimiz.snolla.com`), `maljarka.tandemmebel.ru`, `tandemmebel.ru` + `www.tandemmebel.ru` (scope exception). TTL 86400s — не lowered.
|
||||
- **Live smoke** через real DNS: `kupimknigi.spb.ru`/`www.emspb.ru`/`www.pilorama98.ru`/`www.labtools.pro` → 200 OK + correct per-tenant title. Bare-domain 3 redirects работают (emspb/pilorama98/labtools.pro). `rimiz.ru` / `www.rimiz.ru` → 404 — pre-existing CMS-defect (тоже 404 на source), не migration regression.
|
||||
- **2026-06-05 (tandemmebel cutover — post-closure follow-up):** user (владелец tandemmebel) сам перенастроил DNS в reg.ru. Проверено `Resolve-DnsName`: `tandemmebel.ru` + `www.tandemmebel.ru` + `maljarka.tandemmebel.ru` → `80.64.31.36` (RUVDS) на authoritative ns1.reg.ru + 8.8.8.8 + 1.1.1.1 + Yandex. apex+CNAME сработал (www/maljarka follow apex автоматом). Smoke через real DNS: `tandemmebel.ru`/`www` → **200 OK** correct content; `maljarka.tandemmebel.ru` → **502** (pre-existing CMS-дефект, на source ровно так же — не регрессия cutover'а, см. Open questions). **Снимает прежнюю scope-exception 2026-05-24** (tandemmebel больше НЕ остаётся на windows). **Source НЕ заглушен** — user-decision держать как warm rollback: сайт `snolla` — общий catch-all, 11 `*.snolla.com` (incl `tandemmebel.snolla.com`) ещё резолвятся на `94.19.247.14`, полный `Stop-Website` невозможен; индивидуальное снятие 3 HTTPS-биндингов отложено до full-site decommission. Текущий баланс: **14 hostnames на RUVDS / 11 на windows-source**.
|
||||
- **2026-06-05 (LE auto-renewal pipeline построен — win-acme):** на RUVDS поднят постоянный self-renewing HTTP-01 pipeline (win-acme v2.2.9). Один **25-SAN cert** (store WebHosting, Issuer LE YR2, valid до **2026-09-03**) установлен во все 25 SNI-биндинга; **scheduled task `win-acme-renew-snolla`** (SYSTEM, daily, renew 55д до expiry). **Закрывает дедлайн cert-expiry 2026-07-22** и снимает зависимость RUVDS от домашнего traefik по сертификатам. Главный gotcha: OWIN-catch-all CMS (`owin:HandleAllRequests=true`) перехватывал `/.well-known/acme-challenge/` → решено выносом challenge-пути в **отдельное IIS-приложение в пуле «No Managed Code»** + патч шаблона `C:\win-acme\Web_Config.xml` (`<remove name="Owin"/>`). Staging + prod валидация всех 25 хостов зелёная; живые HTTPS-эндпоинты отдают новый cert (проверено TLS-смоком, incl maljarka/rimiz). Скрипт `scripts/iis-migration-to-ruvds/03-ruvds-winacme.ps1` + шаблон `winacme-Web_Config.xml`. Полный recipe: [[../.wiki/concepts/winacme-iis-owin-catchall-http01]].
|
||||
- **2026-06-05 (FULL CUTOVER достигнут):** проверка всех 25 hostname против authoritative ns1.reg.ru — **все → `80.64.31.36` (RUVDS), на windows-source authoritative не осталось ничего**. Вся зона `snolla.com` (apex + 10 субдоменов, независимые A-записи) переехала. Хвост кэша: `on.snolla.com` + `tandemmebel.snolla.com` ещё `94.19.247.14` на Google 8.8.8.8 (TTL 86400, дотекает; 1.1.1.1/Yandex уже RUVDS). RUVDS smoke: `snolla.com` 200 (default лендинг), `tandemmebel.snolla.com` 200 (tenant content). **Разблокирует decommission** `snolla` site + LE-renewal через win-acme+HTTP-01 (теперь challenge не отскочит на windows). **Source НЕ заглушен** — user-decision: 7-day soak warm rollback + ждём drain кэша. Целевой decommission ~2026-06-12; cert-renewal deadline ~2026-07-15 (certs expire 2026-07-22).
|
||||
- **2026-05-25 (close decision):** user-decision close — несмотря на 16 hostnames pending DNS swap + source IIS:8089 still live + LE renewal pipeline pending + cleanup pending, **task закрывается** на этом этапе. Reason: Phase 1 (RUVDS infra + scp + IIS recreate + cert import + 9 DNS swaps) выполнен и live; остальное — coordination/wait/decommission character, не agent-work load. Future actions перечислены в Closure note ниже, не trackable как `iis-migration-to-ruvds` continuation.
|
||||
|
||||
## Open questions
|
||||
@@ -69,7 +72,7 @@ Migrate IIS hosting from [[../entities/windows-recovery-host]] (DESKTOP-NSEF0UK)
|
||||
- [ ] **Source IIS state backup НЕ снят** (skip'нули — appcmd требует elevated source-shell которого не было). Acceptable risk — source IIS всё ещё running как rollback. Если RUVDS proves stable за 1 неделю → можно decommission source без forensic snapshot'а.
|
||||
- [ ] **CMS-side 502/404 на 4 hostnames** — `maljarka.tandemmebel.ru` / `rimiz.ru` / `www.rimiz.ru` / `rimiz.snolla.com`. На source тоже не работают (return default page). Pre-existing dead-routes от `[iis-traefik-dead-routes-cleanup]` 2026-05-21. Изоляция не блокер для migration; защититься от cutover-blame — отдельная investigation если нужно.
|
||||
- [ ] **Backup strategy для RUVDS** — расширить `vds-backup-rsync-kreknin` cron как третий source? Решение отложено до после full cutover.
|
||||
- [ ] **LE renewal на RUVDS** — текущие certs valid до 2026-07-22 (~60 дней). До expiry нужен permanent renewal pipeline:
|
||||
- [x] **LE renewal на RUVDS** — ✅ DONE 2026-06-05 (win-acme HTTP-01, см. Decisions log + [[../.wiki/concepts/winacme-iis-owin-catchall-http01]]). Выбран Option A (win-acme + HTTP-01 после full cutover). Новый 25-SAN cert до 2026-09-03, авто-renewal через SYSTEM scheduled task. Дедлайн 2026-07-22 снят. ~~Историческая формулировка ниже:~~ текущие certs valid до 2026-07-22 (~60 дней). До expiry нужен permanent renewal pipeline:
|
||||
- Option A: win-acme (wacs.exe) standalone-на-RUVDS с DNS-01 (manual TXT на reg.ru — нет reg.ru-plugin) или HTTP-01 (но только после DNS swap'а — иначе LE challenge bounce'нется на home).
|
||||
- Option B: cron-job который re-extract'ит из traefik acme.json + scp upload + Import-PfxCertificate на RUVDS. Pollute source's traefik lifecycle.
|
||||
- Recommendation: Option A win-acme + HTTP-01 после full cutover (~95 days margin до cert expiry — 60 days minus DNS-stabilization window).
|
||||
@@ -97,15 +100,13 @@ Task **closed 🟢** per user decision. Phase 1 — RUVDS infra + cert pipeline
|
||||
|
||||
1. **16 hostnames still DNS на windows source** (94.19.247.14). Из них:
|
||||
- 14 plan to migrate later: `labtools.ru` + `www.labtools.ru`, `snolla.com` + 12× *.snolla.com (incl `rimiz.snolla.com`, `maljarka.tandemmebel.ru`).
|
||||
- 2 scope-exception: `tandemmebel.ru` + `www.tandemmebel.ru` — stays на windows-IIS до отдельного решения user'а.
|
||||
- ~~2 scope-exception: `tandemmebel.ru` + `www.tandemmebel.ru` — stays на windows-IIS~~ → **SUPERSEDED 2026-06-05: tandemmebel мигрировал на RUVDS** (см. Decisions log). Остаётся `tandemmebel.snolla.com` (snolla-алиас) на windows.
|
||||
- Action: user manually swap A-records в reg.ru → 80.64.31.36 при готовности. Recommend pre-step: lower TTL 86400s → 300s in advance to shrink cache-tail.
|
||||
- Нет reg.ru API key в pass entries — agent НЕ может сделать swap autonomously.
|
||||
|
||||
2. **Source IIS НЕ decommission'ен.** `localhost:8089` snolla site + port 80 catch-all still live на windows-recovery-host. Не трогать пока 16 hostnames на 94.19.247.14. После full cutover + 7-day soak — `Stop-Website snolla` + archive `C:\sites\snolla` (8.66GB) → kreknin.
|
||||
|
||||
3. **LE renewal pipeline НЕ построен.** Текущие RUVDS PFX certs valid до 2026-07-22 (~57 days от 2026-05-25). До этой даты нужен renewal-mechanism:
|
||||
- Recommend: win-acme на RUVDS + HTTP-01 challenge — **возможно только после full DNS cutover** (HTTP-01 bounce'нется на windows source pre-cutover, LE не сможет verify owners).
|
||||
- Soft deadline: ~2026-07-15 (week of margin до cert expiry).
|
||||
3. ~~**LE renewal pipeline НЕ построен.**~~ → **DONE 2026-06-05** (win-acme HTTP-01 после full cutover, как и рекомендовалось). Новый 25-SAN LE cert до 2026-09-03 + SYSTEM auto-renew task. Recipe: [[../.wiki/concepts/winacme-iis-owin-catchall-http01]].
|
||||
|
||||
4. **Temp SSH key cleanup не сделан.** Оставлены (могут понадобиться для будущих push'ей на RUVDS):
|
||||
- `~/.ssh/ruvds-iis-migration` + `.pub` на source workstation
|
||||
|
||||
36
.wiki/concepts/proxy-debugging-test-the-real-client.md
Normal file
36
.wiki/concepts/proxy-debugging-test-the-real-client.md
Normal file
@@ -0,0 +1,36 @@
|
||||
---
|
||||
title: Отладка прокси — проверять на реальном клиенте, не на своих curl-тестах
|
||||
type: concept
|
||||
tags: [troubleshooting, methodology, proxy, vpn, vless, reality, mtproto, anti-pattern]
|
||||
sources: [../sources/nl-vds-3xui-setup-2026-06-05.md]
|
||||
updated: 2026-06-05
|
||||
---
|
||||
|
||||
# Отладка прокси/VPN: свой короткий тест ≠ опыт пользователя
|
||||
|
||||
## Анти-паттерн (как делать НЕ надо)
|
||||
|
||||
При отладке прокси-узла [`nl-vds-3xui`](../entities/nl-vds-3xui.md) я многократно заявлял «работает» на основании **собственных изолированных тестов**:
|
||||
- `curl -x socks5h://127.0.0.1:PORT https://...` через временный `xray.exe`,
|
||||
- короткое скачивание 10 МБ,
|
||||
- `openssl s_client` к порту.
|
||||
|
||||
Эти тесты **проходили**, а боевые клиенты пользователя (v2rayN на ПК, официальный Telegram, телефон) — **не работали**. Каждое такое «у меня работает» при «у меня не работает» от пользователя разрушало доверие и уводило от причины.
|
||||
|
||||
## Почему короткие тесты врут
|
||||
|
||||
1. **Другой путь.** `curl -x http://127.0.0.1:10808` шёл через системный прокси (v2rayN), а не через тестируемый инбаунд. Или мой отдельный `xray.exe` — это **не** запущенный пользователем v2rayN (тот же core, но другой процесс/конфиг/состояние).
|
||||
2. **Короткое vs устойчивое.** Кратковременный коннект мог проходить, а реальное использование (много соединений, сессия минутами) — рушиться (актив-блокировки по состоянию, ретраи).
|
||||
3. **Камуфляж-путь vs рабочий.** `openssl` к FakeTLS-порту (mtg) проходит, потому что отвечает fallback-релей на маскировочный домен — но это НЕ значит, что реальная MTProto-сессия держится. Аналогично REALITY: неаутентифицированный `openssl` получает cert dest (fallback), а аутентифицированный клиент висит.
|
||||
4. **«Доступен/пинг ОК» в GUI** — пассивная проверка достижимости, не равна работающей сессии.
|
||||
|
||||
## Правило
|
||||
|
||||
- **Источник истины — реальный клиент пользователя на его устройстве/сети, а не мой тест.** Если пользователь говорит «не работает» — это данные; мои зелёные curl'ы их не отменяют.
|
||||
- Когда нельзя воспроизвести на боевом клиенте — **изолировать переменные на реальном пути**: закрыть конфликтующие клиенты (у ПК и телефона один внешний IP — пока Desktop держит прокси, телефон в tcpdump не отличить), смотреть `tcpdump` на сервере по конкретному соединению (дошёл ли SYN, идёт ли рукопожатие, где встаёт, есть ли ответные байты).
|
||||
- **Не заявлять «работает» / «подтверждено», пока не подтверждено на боевом клиенте.** Гипотезу называть гипотезой. (Отдельно ловить overclaim: «РКН режет 443» было выдано за факт без доказательства.)
|
||||
- Не вносить «лечебные» изменения на сервере по недоказанной гипотезе (MSS-clamp по MTU-догадке — **сломал** соединения; пользователь заранее говорил, что дело не в MTU).
|
||||
|
||||
## Где встречалось
|
||||
|
||||
- [`nl-vds-3xui-setup-2026-06-05`](../sources/nl-vds-3xui-setup-2026-06-05.md) — Reality/MTProto «проходили» в моих тестах, не работали у пользователя.
|
||||
100
.wiki/concepts/reality-pq-mldsa65-dest-incompatibility.md
Normal file
100
.wiki/concepts/reality-pq-mldsa65-dest-incompatibility.md
Normal file
@@ -0,0 +1,100 @@
|
||||
---
|
||||
title: REALITY ML-DSA-65 (PQ) × Akamai-dest несовместимость
|
||||
type: concept
|
||||
tags: [reality, xray, vless, post-quantum, mldsa65, x25519mlkem768, troubleshooting, 3x-ui]
|
||||
sources: [../sources/nl-vds-3xui-setup-2026-06-05.md]
|
||||
updated: 2026-06-05
|
||||
---
|
||||
|
||||
# REALITY + ML-DSA-65 (post-quantum) ломается с не-PQ dest (напр. www.intel.com)
|
||||
|
||||
## Симптом
|
||||
|
||||
Свежий 3x-UI / Xray-инбаунд VLESS+Reality **не коннектится** (клиент молча висит до таймаута, никакой
|
||||
ошибки в GUI), при этом **обычный VLESS на другом порту работает**. На сервере (при debug-логе):
|
||||
|
||||
```
|
||||
transport/internet/tcp: REALITY: processed invalid connection from <ip>: handshake did not complete successfully
|
||||
```
|
||||
|
||||
Клиент крутит ретраи и сдаётся: `proxy/vless/outbound: failed to find an available destination > [EOF]`.
|
||||
|
||||
## Root cause
|
||||
|
||||
Современный 3x-UI (Xray ≥ 25.x, здесь 26.6.1) для нового Reality-инбаунда **по умолчанию включает
|
||||
пост-квантовый режим ML-DSA-65** (`realitySettings.mldsa65Seed` на сервере + `mldsa65Verify` у клиента).
|
||||
В этом режиме ClientHello несёт пост-квантовый key-share **`X25519MLKEM768`** (~1.2 КБ).
|
||||
|
||||
REALITY-сервер релеит ClientHello на `dest`/`target`, чтобы «позаимствовать» его TLS-рукопожатие. Если dest
|
||||
**не поддерживает PQ-группу обмена ключами**, он отвечает **HelloRetryRequest** (просит другую группу) —
|
||||
а borrowed-TLS поток REALITY этого не переживает → хендшейк не достраивается. `www.intel.com` за **Akamai**
|
||||
именно такой: PQ-обмен не поддерживает.
|
||||
|
||||
Ключевой нюанс диагностики: **неаутентифицированный** гость (обычный `openssl s_client`) идёт по
|
||||
fallback-пути REALITY (прозрачный релей на dest) и получает настоящий сертификат intel — поэтому сервер
|
||||
кажется «живым». Ломается только **аутентифицированный** путь, и только в связке с PQ.
|
||||
|
||||
## Изоляционная матрица (replica-пара, Xray 26.6.1 ↔ 26.6.1, debug)
|
||||
|
||||
Полностью подконтрольная пара (свой сервер-инбаунд на 8443 + клиент на socks 10888, ключи выведены из seed):
|
||||
|
||||
| dest/SNI | ML-DSA-65 | Результат |
|
||||
|---|---|---|
|
||||
| `www.intel.com` | **вкл** | ❌ `handshake did not complete` |
|
||||
| `www.intel.com` | выкл | ✅ HTTP 204 |
|
||||
| `www.microsoft.com` | выкл | ✅ 204 |
|
||||
| `www.microsoft.com` | **вкл** | ✅ 204 |
|
||||
| `www.yahoo.com` | выкл | ✅ 204 |
|
||||
|
||||
→ Падает **только** `intel + PQ`. Порознь оба компонента исправны. Версии ядер, X25519-ключи, shortId, flow,
|
||||
UUID, seed↔verify, часы — всё проверено и совпадает; ни один из них не виноват.
|
||||
|
||||
## Fix
|
||||
|
||||
Два варианта (рекомендация — первый):
|
||||
|
||||
1. **Сменить dest на PQ-совместимый** (сохраняет пост-квантовую защиту). На сервере в инбаунде:
|
||||
`realitySettings.target` → `www.microsoft.com:443`, `serverNames` → `["www.microsoft.com"]`; в клиенте —
|
||||
SNI → `www.microsoft.com`. Менять **симметрично** обе стороны. PQ-совместимость dest проверяется
|
||||
тестом из матрицы выше (или: dest должен уметь TLS1.3 hybrid PQ key-exchange `X25519MLKEM768` —
|
||||
Cloudflare/Google/Microsoft умеют, Akamai-фронт обычно нет).
|
||||
2. **Выключить ML-DSA-65** на инбаунде (убрать `mldsa65Seed` / пересоздать инбаунд без PQ) — тогда `intel`
|
||||
работает. Проще, но теряется пост-квантовая стойкость. Брать только если PQ не нужен.
|
||||
|
||||
## Как воспроизвести/проверить dest на PQ (read-only)
|
||||
|
||||
Поднять временную replica-пару `xray run -c` на localhost-портах с `loglevel:debug` и `curl -x socks5h://…`
|
||||
через тоннель — НЕ трогая боевой инбаунд (см. методику в [`nl-vds-3xui`](../entities/nl-vds-3xui.md)).
|
||||
Признак PQ-несовместимого dest: сервер логирует `REALITY: ... handshake did not complete` **только** при
|
||||
включённом seed.
|
||||
|
||||
## Update 2026-06-05: GUI-клиенты вообще не умеют PQ — отключать ML-DSA-65
|
||||
|
||||
Даже после fix dest (intel→microsoft) **реальные клиенты не коннектились** через Reality (v2rayN 7.19.5,
|
||||
телефонные приложения), хотя ручной xray-конфиг с вписанным `mldsa65Verify` работал. Причина: **GUI-клиенты
|
||||
не передают `mldsa65Verify` в конфиг ядра** (v2rayN пишет его пустым — видно в `binConfigs/configTest*.json`).
|
||||
Replica-матрица на noPQ-сервере:
|
||||
|
||||
| Сервер | Клиент | Результат |
|
||||
|---|---|---|
|
||||
| PQ (mldsa65Seed) | без verify (как v2rayN) | ❌ 000 |
|
||||
| noPQ | без verify | ✅ 204 |
|
||||
| noPQ | с verify | ❌ 000 |
|
||||
|
||||
**Вывод:** ML-DSA-65 (post-quantum REALITY) на середину 2026 поддерживается только ручным xray-конфигом; ни
|
||||
v2rayN, ни мобильные клиенты его не отдают. Для рабочего Reality с GUI-клиентами **PQ надо выключать**
|
||||
(убрать `mldsa65Seed` из инбаунда) → обычный Reality X25519, который умеют все. 3x-UI включает PQ по
|
||||
умолчанию на новых инбаундах — это и ломает «из коробки».
|
||||
|
||||
## ⚠️ Caveat: отключение PQ ≠ рабочий Reality (случай nl-vds 2026-06-05)
|
||||
|
||||
Этот разбор корректно объясняет, почему PQ-Reality ломается и почему PQ надо отключать для GUI-клиентов.
|
||||
**Но отключение PQ + dest microsoft НЕ сделало Reality рабочим у реальных клиентов пользователя** (v2rayN
|
||||
на ПК, телефон) — он всё равно не поднимался, при том что plain VLESS на другом порту работал. В
|
||||
изолированных curl/standalone-xray тестах с того же ПК Reality «проходил» — но это [нерепрезентативно](proxy-debugging-test-the-real-client.md).
|
||||
Причина отказа Reality у боевых клиентов в той сети **не установлена** (перенос порта 443→2053 тоже не
|
||||
помог). Не читать этот concept как «снял PQ → Reality работает»: PQ — лишь одна из преград.
|
||||
|
||||
## Где встречалось
|
||||
|
||||
- [`nl-vds-3xui`](../entities/nl-vds-3xui.md) / [session 2026-06-05](../sources/nl-vds-3xui-setup-2026-06-05.md) — инбаунд 443→2053, обнаружено 2026-06-05.
|
||||
@@ -10,6 +10,8 @@ updated: 2026-05-24
|
||||
|
||||
Recipe для one-shot переноса Let's Encrypt certs из traefik `acme.json` (single-file ACME store) в IIS на Windows host с SNI multi-binding'ами. Использован при миграции [[../entities/ruvds-iis-host]] 2026-05-23 для 14 LE certs → 25 HTTPS hostnames bound via SNI. **Это не renewal pipeline**, а bootstrap-перенос — для long-term renewal recommend `win-acme` standalone на IIS host'е (см. footnote).
|
||||
|
||||
> **Update 2026-06-05 — SUPERSEDED для renewal'а.** Этот ручной PFX-перенос больше не на критическом пути: на RUVDS поднят постоянный self-renewing win-acme HTTP-01 pipeline — см. [[winacme-iis-owin-catchall-http01]]. RUVDS больше не зависит от домашнего traefik по сертификатам. Этот recipe оставлен как reference для bootstrap-сценария / если HTTP-01 недоступен.
|
||||
|
||||
## Когда применять
|
||||
|
||||
- Migration: traefik-on-A → IIS-on-B, certs нужны до того как ACME-validation с нового host'а станет возможной (DNS ещё указывает на старый host, HTTP-01 challenge bounce'нется).
|
||||
|
||||
94
.wiki/concepts/winacme-iis-owin-catchall-http01.md
Normal file
94
.wiki/concepts/winacme-iis-owin-catchall-http01.md
Normal file
@@ -0,0 +1,94 @@
|
||||
---
|
||||
title: win-acme HTTP-01 авто-renewal на IIS под OWIN-catch-all CMS
|
||||
status: live
|
||||
tags: [windows, iis, ruvds, letsencrypt, win-acme, acme, http-01, owin, cms, ops]
|
||||
related: [[ruvds-iis-host]], [[traefik-acme-json-to-iis-cert-import]], [[windows-server-2025-core-bootstrap]], [[iis-migration-2026-05-19-postmortem]]
|
||||
---
|
||||
|
||||
# win-acme HTTP-01 авто-renewal на IIS под OWIN-catch-all CMS
|
||||
|
||||
Постоянный self-renewing LE-pipeline на RUVDS IIS-хосте ([[ruvds-iis-host]]) для сайта `snolla`
|
||||
(25 hostname через SNI). **Заменяет** ручной метод [[traefik-acme-json-to-iis-cert-import]]
|
||||
(экспорт PFX из домашнего traefik `acme.json` + ручной `Import-PfxCertificate`) — тот делал
|
||||
RUVDS зависимым от домашней машины по сертификатам и требовал ручного продления.
|
||||
|
||||
Поднято 2026-06-05, после full DNS cutover на RUVDS (HTTP-01 challenge до cutover'а отскакивал
|
||||
на windows-source — LE не мог достучаться).
|
||||
|
||||
## Что развёрнуто
|
||||
|
||||
- **win-acme v2.2.9** в `C:\win-acme\` (скачан с GitHub releases, `x64.pluggable`).
|
||||
- Один **SAN-cert на 25 hostname** в store `WebHosting`, установлен во все 25 `*:443:<host>` SNI-биндинга.
|
||||
- **Scheduled task `win-acme-renew-snolla`** — daily 09:00 + random delay 4h, runs as **SYSTEM**,
|
||||
`wacs.exe --renew --baseuri https://acme-v02.api.letsencrypt.org/`. Renewal due 55 дней до expiry.
|
||||
- Idempotent setup-скрипт: `scripts/iis-migration-to-ruvds/03-ruvds-winacme.ps1` (фазы `download`/`app`/`probe`/`task`/`verify`).
|
||||
|
||||
## Главный gotcha: OWIN-catch-all жрёт `/.well-known/acme-challenge/`
|
||||
|
||||
Сайт = **MoreThenCms** на OWIN. В корневом `web.config`: `owin:HandleAllRequests=true` +
|
||||
handler `Owin path="*"` + `runAllManagedModulesForAllRequests="true"` → **весь** трафик уходит в
|
||||
managed OWIN-pipeline. HTTP-01 токен (статический файл) отдаётся не статикой, а CMS → `404`/`500`/redirect.
|
||||
LE-валидация падает (`Invalid response ...: 500`).
|
||||
|
||||
Снятие Owin-**handler**'а в дочернем `web.config` НЕ помогает — OWIN перехватывает на уровне
|
||||
**модуля** (HandleAllRequests). Что НЕ сработало:
|
||||
- web.config с `<rewrite><rules><clear/></rules>` — рерайта-то и нет, маршрутит managed-pipeline.
|
||||
- web.config с `<handlers><remove name="Owin"/></handlers>` в обычном (managed) пуле — модуль всё равно жив.
|
||||
|
||||
### Рабочее решение: отдельное IIS-приложение в пуле «No Managed Code»
|
||||
|
||||
`.well-known/acme-challenge` вынесен в **отдельное IIS Application** под сайтом `snolla` с
|
||||
app-pool'ом `acme-challenge`, у которого `managedRuntimeVersion=''` (**No Managed Code**). В таком
|
||||
пуле .NET/OWIN не стартует вообще — токен отдаётся нативным `StaticFileModule`.
|
||||
|
||||
Нюанс: в дочернем web.config всё равно нужно **`<handlers><remove name="Owin"/></handlers>`** —
|
||||
иначе унаследованный managed Owin-handler даёт `500` (managed handler в unmanaged пуле). Плюс
|
||||
extensionless-mime (токены без расширения). Проверенный web.config:
|
||||
|
||||
```xml
|
||||
<configuration>
|
||||
<system.webServer>
|
||||
<handlers><remove name="Owin" /></handlers>
|
||||
<staticContent>
|
||||
<remove fileExtension="." /><mimeMap fileExtension="." mimeType="text/plain" />
|
||||
</staticContent>
|
||||
<modules runAllManagedModulesForAllRequests="false" />
|
||||
</system.webServer>
|
||||
</configuration>
|
||||
```
|
||||
|
||||
Результат: токен отдаётся `200` для **любого** Host — даже для деградировавших CMS-тенантов
|
||||
(`maljarka.tandemmebel.ru`/`rimiz.ru`, которые на app-уровне отдают `502`/`404`), т.к. статика
|
||||
обходит CMS-роутинг.
|
||||
|
||||
### Патч шаблона win-acme
|
||||
|
||||
win-acme при filesystem-валидации **перезаписывает** дочерний web.config своим шаблоном
|
||||
`C:\win-acme\Web_Config.xml` (а при `CleanupFolders=true` потом удаляет токен+web.config). Дефолтный
|
||||
шаблон делает `<staticContent><clear/>` + mime, но **не снимает Owin-handler** → снова `500`.
|
||||
|
||||
Durable-фикс = **пропатчить сам шаблон** `C:\win-acme\Web_Config.xml`, добавив `<remove name="Owin"/>`
|
||||
+ `runAllManagedModulesForAllRequests="false"`. Трекаемая копия: `scripts/iis-migration-to-ruvds/winacme-Web_Config.xml`.
|
||||
Тогда на каждом renewal win-acme сам кладёт рабочий web.config в (постоянное) unmanaged-приложение,
|
||||
валидирует, чистит. Между renewal'ами папка пустая — трафика на неё нет.
|
||||
|
||||
## Процедура де-риска (повторяемо)
|
||||
|
||||
1. `--validationmode http-01 --validation filesystem` локальный probe токена через `localhost` + `Host:`-заголовок (обходит home-DPI middlebox).
|
||||
2. **Staging** через `--baseuri https://acme-staging-v02.api.letsencrypt.org/` (НЕ `--test` — он включает интерактивные промпты, которые вешают non-interactive SSH). pemfiles store + `--installation none` — без правок IIS.
|
||||
3. Прод: `--store certificatestore --installation iis --installationsiteid 1`.
|
||||
|
||||
## Грабли
|
||||
|
||||
- **`--test` ≠ staging-only.** `--test` тащит интерактив («Try in default browser?», «Quit?») → виснет под SSH. Для staging без интерактива — `--baseuri <staging>`.
|
||||
- **pemfiles path должен существовать** заранее, иначе abort до валидации.
|
||||
- **Scheduled task руками, не через win-acme.** `--notaskscheduler` при выпуске; таск создаётся отдельно как SYSTEM (win-acme-овский setup может спросить креды интерактивно). win-acme потом пишет «Scheduled task not configured yet» — косметика, ищет *свой* таск.
|
||||
- win-acme renewal'ы раздельны по `--baseuri` (разные ConfigurationPath): staging-renewal не трогается прод-таском. Staging-renewal всё равно убран для чистоты.
|
||||
|
||||
## Команда боевого выпуска (reference)
|
||||
|
||||
```
|
||||
C:\win-acme\wacs.exe --source iis --siteid 1 --validationmode http-01 --validation filesystem ^
|
||||
--webroot C:\sites\snolla --store certificatestore --installation iis --installationsiteid 1 ^
|
||||
--accepttos --emailaddress <ops-email> --force --notaskscheduler
|
||||
```
|
||||
@@ -26,11 +26,37 @@ updated: 2026-05-25 (ES migration from Windows host)
|
||||
## Disk
|
||||
|
||||
```
|
||||
/dev/vda1 122G 59G used (49%) 63G free
|
||||
/dev/vda1 122G 53G used (44%) 69G free # 2026-06-04, после disk-full remediation
|
||||
```
|
||||
|
||||
Single root partition, нет отдельной `/data`. Docker hub data под `/var/lib/docker/`.
|
||||
|
||||
**Disk-full incident 2026-06-04** (provider Rusonyx monitoring alert, 4.95% free / 96% used). Culprits:
|
||||
- **38 GB unrotated container logs** — `books-task-runner` (32.8 GB) + `bookva-task-runner`-история (5.6 GB). `books-task-runner` (тенант **slovo**) в tight error-loop с ~2026-05-31 (~9 GB/day, no log rotation). Truncated live (`:> json.log`, no restart).
|
||||
- **~26 GB orphaned BuildKit cache** — 11 running `buildx_buildkit_builder-*` daemon-контейнеров, которых нет в `docker buildx ls` (orphan builders), держали 9× `*_state` volumes. Removed (`docker rm -f` + `docker volume rm`).
|
||||
- Result: 96% → 44%.
|
||||
|
||||
**Durable guard added 2026-06-04:** `/etc/logrotate.d/docker-containers` (copytruncate, size 200M, rotate 3, compress) + hourly `/etc/cron.d/docker-logrotate`. Caps любой runaway container-log без docker restart.
|
||||
|
||||
**Root cause залипшего лога (НЕ «протухший ключ» — правка-самообман, см. ниже):**
|
||||
- На books VDS два зеркальных стека: **books-*** (тенант slovo, `books-db`) и **bookva-*** (тенант bookva, `bookva-db`), один и тот же образ. Ozon-вызовы шлёт `*-task-runner` (не scheduler — он лишь триггерит agenda-джобу, HTTP делает task-runner). Только `books-task-runner` сыпал ошибки; `bookva-task-runner` — 0.
|
||||
- В таблице `sellers` (обе БД) два Ozon-продавца: **Slovo (client_id 94191)** и **Bookva (client_id 50542)**. В `books-db` у строки Bookva в `api_key` **намеренно вписан ключ Slovo** (`9683…` вместо живого `ddc2…`) — это **сознательная ревокация** доступа books→Ozon-аккаунт Bookva (сделано в прошлой сессии). Ozon на `Client-Id:50542`+чужой ключ → `code 5 Invalid Api-Key`. **НЕ чинить этот ключ** — это и есть защита. (Живой ключ Bookva — в `bookva-db` и в конфиге, для тенанта bookva.)
|
||||
- Спам шёл оттого, что часть books-agenda-джоб **не заскоуплены** на slovo: при пустом `data.idSeller` таски итерируют ВСЕХ продавцов (`data.idSeller ? filter : allSellers`), включая Bookva с битым ключом. Раньше заскоупили только `ozon stocks syncronization` (`idSeller:2`).
|
||||
|
||||
**Фикс 2026-06-04:** проставлен `data.idSeller=2, otherSellers:[]` в `books-job-scheduler-mongo` (agendaDb.agendaJobs) пяти джобам: `ozon fbs postings syncronization`, `generate old prices`, `ozon fbs products syncronization`, `create ozon products in incorrect state report`, `put on sale products`. Залипшие overdue-прогоны оборваны: unlock (`lockedAt:null`) + `docker restart books-task-runner`. Результат: Invalid-Api-Key 6448/мин → **0**, джобы отработали по slovo и перепланировались.
|
||||
|
||||
**Durability фикса:** правка в mongo переживает деплой. Эти джобы — легаси (`data._fromConfig` отсутствует), reconciler (`lib/reconciler.js`, `RECONCILER_ENABLED=true`) трогает только `_fromConfig:true`-джобы; в `tasks.json` (запечён в образ) у них `schedule:null` → reconciler их пропускает. Эмпирика: `stocks-sync idSeller:2` (только в mongo) пережил деплой 31.05.
|
||||
|
||||
**Полнота скоупа (сверено 2026-06-04).** На books-стороне сосуществуют ДВА поколения джоб:
|
||||
- **Legacy** (без `_fromConfig`, расписание в persisted mongo): seller-перебирающие — `seller.findAll` при пустом `data.idSeller` → ВСЕ продавцы. Ровно 7 таких: `ozonFbsPostingsSyncronization`, `ozonFbsProductsSyncronization`, `ozonStocksSyncronization`, `generateOldPrices`, `createOzonProductsInIncorrectStateReport`, `putOnSaleProducts`, `syncStocksWithWarehouse`. **Все заскоуплены `idSeller:2`** (5 сегодня + stocks + warehouse ранее). Других seller-перебирающих нет.
|
||||
- **Reconciler-gen** (`_fromConfig:true`, из `tasks.json`): фильтруются по **`salesChannels:[2]`** (ozon-канал Slovo), не по idSeller — `load products to ozon`, `ozonProductSalesChannelSync`, `unarchiveAutoArchivedProducts`, `addFixedPriceProductsToAction`, `fbsPicking*` и т.д. Уже корректно указывают только на канал Slovo.
|
||||
|
||||
**Группа В — НЕ дыра (изначальная гипотеза снята).** `sales_channels` в books-db: канал 2 = Slovo **type=ozon**; канал 3 = Bookva **type=ym** (Яндекс.Маркет, не Ozon). Активного Bookva-**ozon**-канала нет → channel-driven Ozon-джобы физически не могут залезть в Bookva. Bookva-`ym` использует отдельный `ym_api_key`, к инциденту не относится.
|
||||
|
||||
Follow-ups:
|
||||
1. **Каноничный фикс — в репо books**: legacy seller-перебирающие джобы стоит либо мигрировать в `tasks.json` со скоупом, либо вывести из эксплуатации (их функции, возможно, уже покрыты reconciler-gen). Риск mongo-only правки: если будущий релиз даст legacy-джобе реальный `schedule` в `tasks.json` без скоупа — reconciler пере-сеет её (data без idSeller) → доступ к Bookva вернётся.
|
||||
2. wiki-drift — `bookva-*` stack (bookva-api/db/es/minio/mongo/scheduler/task-runner/web) + books-task-runner/scheduler не в stack-inventory ниже; нужен re-inventory.
|
||||
|
||||
## Стек (2026-05-25 inventory)
|
||||
|
||||
### Portainer-managed stacks (endpoint 1)
|
||||
|
||||
69
.wiki/entities/nl-vds-3xui.md
Normal file
69
.wiki/entities/nl-vds-3xui.md
Normal file
@@ -0,0 +1,69 @@
|
||||
---
|
||||
title: NL VDS — 3x-UI VLESS node
|
||||
type: entity
|
||||
tags: [vds, cloud, netherlands, vpn, vless, reality, mtproto, xray, 3x-ui, proxy]
|
||||
sources: [../sources/nl-vds-3xui-setup-2026-06-05.md]
|
||||
updated: 2026-06-05
|
||||
---
|
||||
|
||||
# NL VDS — 3x-UI
|
||||
|
||||
Личный прокси-VDS в Нидерландах, активирован 2026-06-05, под управлением 3x-UI (x-ui) / Xray.
|
||||
Назначение — обход блокировок для себя и раздача доступа друзьям.
|
||||
|
||||
## Hardware
|
||||
|
||||
- **Локация:** Нидерланды (провайдер Aeza, судя по `my.aeza.net` в трафике)
|
||||
- **Public IP:** `213.176.64.253` ; **IPv6:** `2a12:5940:2b1d::2`
|
||||
- **vCPU / RAM / Disk:** 1 / 2 GiB / 30 GiB NVMe
|
||||
- **OS:** Ubuntu 24.04 ; **PTR:** `square-white.ptr.network`
|
||||
|
||||
## Доступ
|
||||
|
||||
- **SSH:** `root@213.176.64.253` (password auth). Host-key (ed25519): `SHA256:XR2+0PCVUoEMrFHOoIu7IPXb4xP2JnYkqFr1uqs8YrA`.
|
||||
- С Windows non-interactive: `plink -ssh -batch -hostkey "SHA256:XR2+...YrA" -pw <pass> root@... "<cmd>"`. Пайп `y` для приёма host-key через PowerShell **не работает** (plink читает промпт с консоли) — передавать `-hostkey` явно. Для python на сервере — заливать скрипт через `pscp` (инлайн-python в plink-арге PowerShell корёжит кавычками).
|
||||
- **Панель 3x-UI:** `https://213.176.64.253:49251/aTKt95PPgt9y2dUHi8/` (port 49251, sub-port 2096).
|
||||
- **Креды:** `pass show nl-vds-3xui/full-env`. **Все логин-креды ротированы 2026-06-05** (оригиналы светились в плейнтексте): root SSH pass, panel user+pass, panel `secret` (JWT — убил install-time API-токен и сессии). Reality privateKey/UUID/seed НЕ ротировались (не светились, на них завязаны клиентские профили).
|
||||
|
||||
## Software stack
|
||||
|
||||
| Слой | Компонент | Версия |
|
||||
|---|---|---|
|
||||
| OS | Ubuntu | 24.04 |
|
||||
| Panel | 3x-UI (x-ui), нативный systemd-сервис | 3.2.7 |
|
||||
| Core | Xray (`/usr/local/x-ui/bin/xray-linux-amd64`) | 26.6.1 |
|
||||
| MTProto | mtg (`9seconds/mtg`, systemd `mtg.service`) | 2.2.8 |
|
||||
| DB | SQLite `/etc/x-ui/x-ui.db` (бэкапы `/root/x-ui.db.bak.*`) | — |
|
||||
| Firewall | ufw inactive, iptables policy ACCEPT | — |
|
||||
|
||||
Конфиг ядра генерится в `/usr/local/x-ui/bin/config.json` из БД при `x-ui restart`.
|
||||
|
||||
## Текущее состояние (итог сессии 2026-06-05) — что РЕАЛЬНО работает
|
||||
|
||||
> **Работает только plain VLESS на 32030.** Через него идёт боевой трафик из РФ (v2rayN на ПК; v2rayNG/Hiddify на телефоне/Mac). Это канал, который раздаём друзьям. Всё «маскированное» (Reality, MTProto, SOCKS5) у реальных клиентов из РФ **не поднялось** — детальный разбор почему в [source-странице](../sources/nl-vds-3xui-setup-2026-06-05.md).
|
||||
|
||||
| Порт | Протокол | Статус у реальных клиентов |
|
||||
|---|---|---|
|
||||
| **32030** | VLESS / tcp, `security=none` | 🟢 **РАБОТАЕТ.** uuid `a6fa7965-…` (sx9l9csam3). Без TLS (DPI-детектируем, но живой). |
|
||||
| 2053 | VLESS + **Reality** X25519, flow vision, dest `www.microsoft.com` (PQ снят) | 🔴 **НЕ работает** у v2rayN/телефона. В изолированных curl/xray-тестах с того же ПК проходил (exit NL, 5 МБ/с), но **боевые клиенты — нет**. Причина не установлена (вероятно — обработка TLS-хендшейка к этому IP в сети пользователя). Был на 443 → перенесён на 2053. Клиенты: `5da48418-…` (pqmkayaxo2), `7941887a-…` (0h5rzrsex3); pbk `zWTp-3dPfB78…`, sid `795fc9`. |
|
||||
| 47020 | SOCKS5 (auth=password) | 🔴 у пользователя режется DPI (на сервере сам по себе ОК, auth работает). user `tg_s5wm7I`. |
|
||||
| 8443 | **MTProto** (mtg, FakeTLS `www.cloudflare.com`) | 🔴 **НЕ работает как Telegram-прокси:** и Telegram Desktop, и телефон висят на «соединение…». Пассивный пинг в Telegram показывает «доступен» — **вводит в заблуждение**. В tcpdump: телефон шлёт 1288-б ClientHello → mtg отвечает **0 байт**. Локальный FakeTLS (`openssl` на сервере) проходит, но реальную MTProto-сессию mtg здесь не держит. |
|
||||
|
||||
## Клиент для друзей (рабочий путь)
|
||||
|
||||
Hiddify (Win/Mac/Android) либо v2rayN/v2rayNG — импорт `vless://…@213.176.64.253:32030?type=tcp&security=none` (ссылка/QR). Полная инструкция для друзей — в [source](../sources/nl-vds-3xui-setup-2026-06-05.md).
|
||||
**При включённом VPN в Telegram прокси не нужен:** на телефоне «Отключить прокси», на десктопе «Использовать системные настройки прокси», кастомные прокси удалить.
|
||||
|
||||
## Что трогали на сервере 2026-06-05
|
||||
|
||||
- Reality: dest `intel`→`microsoft`; снят ML-DSA-65 (`mldsa65Seed`); порт 443→2053.
|
||||
- Креды ротированы (см. Доступ).
|
||||
- Поднят mtg (MTProto) на 8443; SOCKS5-инбаунд на 47020.
|
||||
- **MSS-clamp 1360** ставился (ошибочная MTU-гипотеза) и **снят** — он ломал соединения (после снятия комп-телега через системный прокси ожила).
|
||||
|
||||
## Подводные камни / уроки
|
||||
|
||||
- **ML-DSA-65 (PQ-Reality) несовместим с GUI-клиентами** — v2rayN/мобильные не шлют `mldsa65Verify` → PQ надо отключать. Полный разбор: [`reality-pq-mldsa65-dest-incompatibility`](../concepts/reality-pq-mldsa65-dest-incompatibility.md).
|
||||
- **Свои короткие curl/standalone-xray тесты «работали», а боевые клиенты — нет.** Не доверять собственным изолированным тестам как доказательству — проверять на реальном клиенте/устройстве: [`proxy-debugging-test-the-real-client`](../concepts/proxy-debugging-test-the-real-client.md).
|
||||
- **MSS-clamp на прокси-сервере может рвать соединения** — не лепить «на всякий случай».
|
||||
- Reality/MTProto в РФ — нетривиальны; единственное, что тут гарантированно поднялось у реальных клиентов — plain VLESS.
|
||||
@@ -11,6 +11,7 @@ Catalog of all wiki pages. One line per page, organized by type. Updated on ever
|
||||
- [books-vds](entities/books-vds.md) — Books VDS (89.253.255.133 — host4g.ru, client server hosting books app + shared mongo/minio/elasticsearch)
|
||||
- [dead-synology-diskstation](entities/dead-synology-diskstation.md) — мёртвая Synology DiskStation (source NAS)
|
||||
- [kreknin-synology](entities/kreknin-synology.md) — Kreknin Synology (backup target + DDNS)
|
||||
- [nl-vds-3xui](entities/nl-vds-3xui.md) — NL VDS 3x-UI VLESS/Reality node (213.176.64.253) — Reality 443 сломан (PQ×intel), plain VLESS 32030 работает
|
||||
- [openwrt-router](entities/openwrt-router.md) — OpenWRT Router (192.168.1.1)
|
||||
- [ruvds-iis-host](entities/ruvds-iis-host.md) — RUVDS IIS Host (Win Server 2025 Core, 80.64.31.36) — CMS catch-all destination
|
||||
- [snolla-recovery-vm](entities/snolla-recovery-vm.md) — Snolla Recovery VM (VirtualBox, savestate'нута 2026-05-21 после 36h soak)
|
||||
@@ -35,6 +36,8 @@ Catalog of all wiki pages. One line per page, organized by type. Updated on ever
|
||||
- [portainer-2.21-admin-password-regression](concepts/portainer-2.21-admin-password-regression.md) — Portainer 2.21 `--admin-password` regression + min 12-char policy
|
||||
- [portainer-stack-management-books-vds](concepts/portainer-stack-management-books-vds.md) — Portainer-managed stacks на books VDS — pattern application + migration log 2026-05-25
|
||||
- [portainer-stack-management-vds](concepts/portainer-stack-management-vds.md) — Portainer-managed stacks на VDS — canonical pattern + migration script + gotchas
|
||||
- [proxy-debugging-test-the-real-client](concepts/proxy-debugging-test-the-real-client.md) — анти-паттерн: свои curl/standalone-тесты «работают», а боевой клиент пользователя нет; источник истины — реальный клиент
|
||||
- [reality-pq-mldsa65-dest-incompatibility](concepts/reality-pq-mldsa65-dest-incompatibility.md) — REALITY+ML-DSA-65 (PQ) не работает с не-PQ dest (Akamai/intel шлёт HRR); fix = PQ-совместимый dest или выключить PQ; **caveat: снятие PQ ≠ рабочий Reality у GUI-клиентов**
|
||||
- [recovery-architecture-snapshot](concepts/recovery-architecture-snapshot.md) — текущая recovery architecture (2026-05-19/21, attempt 2)
|
||||
- [registry-gc-mount-and-modify-flag](concepts/registry-gc-mount-and-modify-flag.md) — Docker Registry GC mount layout + `-m` flag
|
||||
- [rusonyx-vps-onboarding-quirks](concepts/rusonyx-vps-onboarding-quirks.md) — Rusonyx VPS onboarding quirks (Astra Облако / myvm.rusonyx.ru)
|
||||
@@ -45,6 +48,7 @@ Catalog of all wiki pages. One line per page, organized by type. Updated on ever
|
||||
- [vbox-windows-stability-tuning](concepts/vbox-windows-stability-tuning.md) — VirtualBox + Windows-гость — нюансы стабильности cross-hypervisor миграции
|
||||
- [vds-kzntsv-dhcp-outage-2026-05-28](concepts/vds-kzntsv-dhcp-outage-2026-05-28.md) — DHCP outage 2026-05-28 на vds-kzntsv — диагностика + recovery runbook (link UP но без IPv4 → статика + тикет хостеру)
|
||||
- [verdaccio-prune-semantics](concepts/verdaccio-prune-semantics.md) — Verdaccio prune semantics — proxied vs locally-published
|
||||
- [winacme-iis-owin-catchall-http01](concepts/winacme-iis-owin-catchall-http01.md) — win-acme HTTP-01 авто-renewal LE на IIS под OWIN-catch-all CMS — challenge в отдельном No-Managed-Code приложении + патч шаблона; заменяет ручной PFX-импорт
|
||||
- [wd40efax-smr-cascade](concepts/wd40efax-smr-cascade.md) — WD40EFAX SMR Cascade — root cause NAS failure 2026-05-18
|
||||
- [windows-server-2025-core-bootstrap](concepts/windows-server-2025-core-bootstrap.md) — Win Server 2025 Core (RUVDS) — bootstrap для IIS-хоста: default-blockers + transfer-методов матрица
|
||||
|
||||
@@ -59,5 +63,6 @@ Catalog of all wiki pages. One line per page, organized by type. Updated on ever
|
||||
- [nas-recovery-session-2026-05-18](sources/nas-recovery-session-2026-05-18.md) — NAS Recovery Session 2026-05-18/19 chronology
|
||||
- [books-vds-backup-daily-kreknin-2026-05-25](sources/books-vds-backup-daily-kreknin-2026-05-25.md) — books VDS daily backup → kreknin pipeline standup 2026-05-25 (ES file-snapshot repo + DB dumps + curl SMTP)
|
||||
- [ruvds-backup-daily-kreknin-2026-05-24](sources/ruvds-backup-daily-kreknin-2026-05-24.md) — RUVDS daily backup → kreknin pipeline standup 2026-05-24 (rclone+SFTP, SYSTEM task)
|
||||
- [nl-vds-3xui-setup-2026-06-05](sources/nl-vds-3xui-setup-2026-06-05.md) — NL VDS 3x-UI setup+troubleshooting session; итог: у реальных клиентов из РФ работает только plain VLESS 32030 (Reality/MTProto/SOCKS не поднялись)
|
||||
- [vds-kzntsv-bootstrap-2026-05-20](sources/vds-kzntsv-bootstrap-2026-05-20.md) — VDS bootstrap session 2026-05-20 chronology
|
||||
- [vds-kzntsv-incident-2026-05-28](sources/vds-kzntsv-incident-2026-05-28.md) — DHCP outage incident session 2026-05-28 — chronology + ticket text
|
||||
|
||||
14
.wiki/log.md
14
.wiki/log.md
@@ -2,6 +2,8 @@
|
||||
|
||||
Append-only log of wiki operations (ingests, promotions, lints, migrations).
|
||||
|
||||
## [2026-06-05] ingest | concepts/winacme-iis-owin-catchall-http01 — постоянный self-renewing LE pipeline на RUVDS IIS (win-acme v2.2.9, 25-SAN cert, SYSTEM scheduled task). Главное: OWIN-catch-all CMS жрёт `/.well-known/acme-challenge/` → решено отдельным IIS-приложением в пуле «No Managed Code» + патч шаблона `Web_Config.xml` (snять Owin-handler). Заменяет ручной [[traefik-acme-json-to-iis-cert-import]] для renewal'а; снимает зависимость RUVDS от домашнего traefik. Закрывает дедлайн cert-expiry 2026-07-22 (новый cert до 2026-09-03). Источник: `.tasks/iis-migration-to-ruvds.md` Decisions log 2026-06-05.
|
||||
|
||||
## [2026-05-28] ingest | concepts/es-destructive-delete-incident-2026-05-26 — RCA для удаления 3 user-индексов на canonical ES `elasticsearch.kzntsv.site` (books VDS stack 33) во время cutover-prep. Caller identity unrecoverable (audit log = X-Pack платный, traefik accessLog был выключен). 2 preventive controls applied + verified: ES env `action.destructive_requires_name=true` + traefik JSON accessLog. Источник: `.tasks/restore-elasticsearch-indices-books-vds.md` § Closure note.
|
||||
|
||||
## 2026-05-21
|
||||
@@ -31,3 +33,15 @@ Append-only log of wiki operations (ingests, promotions, lints, migrations).
|
||||
## [2026-05-28] update | vds-kzntsv DHCP outage post-resolution — после reset хостером в 13:52 MSK выяснилось что root cause — конфликт двух сетевых стеков (netplan+networkd поверх ожидаемого provider's ifupdown). Их `start/ipadd` ожидает чистый ifupdown, не мог auto-recover при разрыве DHCP binding. Resolution: mask netplan+systemd-networkd, reboot, provider положил `/etc/network/interfaces.d/ifcfg-eth0` с /18 netmask. UPDATE concepts/vds-kzntsv-dhcp-outage-2026-05-28 (revised RCA + permanent-fix § + anti-pattern + revised lessons-learned) + UPDATE sources/vds-kzntsv-incident-2026-05-28 (timeline до 14:00 + final config) + UPDATE entities/vds-kzntsv (mask /18, ifupdown stack, kernel cmdline net.ifnames=0) + UPDATE concepts/rusonyx-vps-onboarding-quirks (quirk #9 переписан про /18, quirk #10 NEW про ifupdown vs netplan stack). Memory `vds-kzntsv-rusonyx-network-recovery` переписан с новыми фактами.
|
||||
|
||||
## [2026-05-29] update | ES destructive-delete RECURRENCE — true root cause найден, диагноз сменился. UPDATE concepts/es-destructive-delete-incident-2026-05-26 (correction-блок + Hypothesis помечена ОПРОВЕРГНУТА + новая секция «Рецидив 2026-05-29 — true root cause»: ransom-бот через открытый `0.0.0.0:9200` мимо traefik+basicAuth, ES 7.10 free без auth; `read_me`=BTC-выкуп; снос by-name мимо Control #1; accessLog пуст т.к. бот шёл прямо в :9200; firewalld bypass docker-publish; Control #3 = убрать публикацию host-порта via Portainer PUT stack 33; restore из daily-2026-05-25; exposure-audit таблица — mongo/books-db/bookva-db/minio/bookva-minio тоже exposed но credentialed). bookva не пострадал (bookva-es порт не публикует). Live incident response session.
|
||||
|
||||
## [2026-06-05] ingest | NL VDS 3x-UI node + Reality PQ×dest root-cause
|
||||
- new entities/nl-vds-3xui.md (213.176.64.253, Ubuntu 24.04, 3x-UI 3.2.7 / Xray 26.6.1); creds -> pass nl-vds-3xui/full-env
|
||||
- new concepts/reality-pq-mldsa65-dest-incompatibility.md (root cause: ML-DSA-65 PQ ClientHello X25519MLKEM768 + Akamai dest www.intel.com -> HRR -> handshake fail; fix = PQ-capable dest e.g. www.microsoft.com, verified via isolation matrix)
|
||||
- index.md updated (entity + concept). Fix NOT applied — awaiting user command.
|
||||
|
||||
## [2026-06-05] ingest | NL VDS 3x-UI session — honest final state + lessons
|
||||
- NEW sources/nl-vds-3xui-setup-2026-06-05.md (chronicle: Reality PQ fix, port 443→2053, mtg MTProto, SOCKS5, friend-client instr; HONEST outcome — у реальных клиентов из РФ работает только plain VLESS 32030)
|
||||
- NEW concepts/proxy-debugging-test-the-real-client.md (anti-pattern: свои curl/standalone-тесты ≠ боевой клиент; overclaim «РКН режет 443» / MSS-clamp по MTU-догадке сломал коннект)
|
||||
- REWROTE entities/nl-vds-3xui.md — убраны ложные «Reality verified/fixed», «mtg неотличим»; честная таблица статусов (32030 🟢, Reality 2053 / MTProto 8443 / SOCKS 47020 🔴 у клиентов); MSS-clamp снят
|
||||
- UPDATE concepts/reality-pq-mldsa65-dest-incompatibility.md — caveat «снятие PQ ≠ рабочий Reality у GUI-клиентов» + source link
|
||||
- index.md updated (2 new pages). Креды/ссылки — pass nl-vds-3xui/full-env.
|
||||
|
||||
46
.wiki/sources/nl-vds-3xui-setup-2026-06-05.md
Normal file
46
.wiki/sources/nl-vds-3xui-setup-2026-06-05.md
Normal file
@@ -0,0 +1,46 @@
|
||||
---
|
||||
title: NL VDS 3x-UI — setup & troubleshooting session 2026-06-05
|
||||
type: source
|
||||
tags: [vless, reality, mtproto, hiddify, v2rayn, rkn, troubleshooting, session]
|
||||
ingested: 2026-06-05
|
||||
raw_path: (live session, no raw file)
|
||||
sources: []
|
||||
updated: 2026-06-05
|
||||
---
|
||||
|
||||
# NL VDS 3x-UI — сессия настройки/диагностики 2026-06-05
|
||||
|
||||
Хроника заведения и отладки прокси-VDS [`nl-vds-3xui`](../entities/nl-vds-3xui.md).
|
||||
|
||||
## Что сделано
|
||||
|
||||
1. **Заведение в вики + ротация кредов.** Узел задокументирован, креды (SSH root, panel, JWT secret) ротированы и положены в `pass nl-vds-3xui/full-env` (оригиналы светились в плейнтексте).
|
||||
2. **Reality 443 диагностика.** Не коннектился. Root cause: 3x-UI включил ML-DSA-65 (PQ) + dest `www.intel.com` (Akamai, не умеет PQ key-exchange) → handshake не достраивался. Изоляционная матрица на replica-парах. Разбор: [`reality-pq-mldsa65-dest-incompatibility`](../concepts/reality-pq-mldsa65-dest-incompatibility.md).
|
||||
3. **Fix Reality (server-side):** dest→`www.microsoft.com`, затем снят `mldsa65Seed` (GUI-клиенты не шлют `mldsa65Verify`), затем порт 443→2053.
|
||||
4. **MTProto:** поднят mtg 2.2.8 (FakeTLS cloudflare) на 8443.
|
||||
5. **SOCKS5:** инбаунд на 47020 (auth).
|
||||
6. **Инструкции для друзей** (Hiddify, Win/Mac/Android).
|
||||
|
||||
## Чем закончилось (честный итог)
|
||||
|
||||
**У реальных клиентов из РФ работает ТОЛЬКО plain VLESS 32030.** Reality (2053), MTProto (8443), SOCKS5 (47020) — **не поднялись** на боевых клиентах:
|
||||
|
||||
- **Reality 2053:** в изолированных тестах (отдельный `xray.exe` + `curl -x socks5h` с того же ПК) — проходил, exit NL, 5 МБ/с. Боевой v2rayN на том же ПК и телефон — **нет**. Причина не установлена. Версионная/PQ-несовместимость исключена (PQ снят, flow на месте, конфиг сверен — идентичен рабочему тесту). Вероятная гипотеза (НЕ доказана) — обработка TLS-хендшейка к этому IP в сети пользователя.
|
||||
- **MTProto 8443:** Telegram (Desktop и телефон) висит «соединение…». tcpdump (телефон изолирован, Desktop закрыт): телефон шлёт 1288-б ClientHello → mtg отвечает 0 байт, телефон долбится десятками повторов. Локальный FakeTLS (`openssl` на сервере) проходит — но это лишь камуфляж-путь, реальную MTProto-сессию mtg здесь не держит. «Доступен (пинг N мс)» в Telegram — пассивная проверка, не равна рабочей сессии.
|
||||
- **SOCKS5 47020:** на сервере исправен (внешний curl с auth проходил), но у пользователя режется DPI.
|
||||
|
||||
**Грубые ошибки в процессе (см. урок ниже):**
|
||||
- Несколько раз заявлял «работает» по своим коротким curl/standalone-тестам, тогда как боевые клиенты не работали. Тесты были нерепрезентативны (часто шли не через тот путь, что у пользователя; либо через системный прокси v2rayN; либо это был мой отдельный процесс, не v2rayN).
|
||||
- Влепил **MSS-clamp 1360** на сервер по неверной MTU-гипотезе (пользователь сразу сказал, что дело не в MTU) — clamp **ломал** соединения; после снятия комп-телега через системный прокси заработала.
|
||||
|
||||
## Рабочее решение для друзей (раздаётся)
|
||||
|
||||
Клиент **Hiddify** (Win/Mac/Android, один на все платформы) либо v2rayN/v2rayNG. Импорт по `vless://`-ссылке или QR, профиль 32030. При включённом VPN — в Telegram прокси не настраивать (моб. «отключить прокси», desktop «системный прокси», кастомные удалить).
|
||||
|
||||
Каждому другу — **свой** клиентский UUID (на момент сессии на 32030 один общий `a6fa7965-…`; рекомендовано завести отдельных клиентов под каждого для возможности отзыва — не сделано, ждёт решения user).
|
||||
|
||||
## Открытые хвосты
|
||||
|
||||
- **Reality/MTProto у реальных клиентов из РФ не работают** — причина не доведена до конца. Если нужен DPI-стойкий канал (не plain VLESS) — отдельная задача (возможно: другой IP/провайдер, CDN-fronting, или клиент с TUN вместо встроенного Telegram-прокси).
|
||||
- Per-friend UUID на 32030 — завести отдельных клиентов.
|
||||
- Опционально: убрать неработающие инбаунды (2053 Reality / 47020 SOCKS / 8443 mtg), чтобы не торчали лишние порты.
|
||||
159
scripts/iis-migration-to-ruvds/03-ruvds-winacme.ps1
Normal file
159
scripts/iis-migration-to-ruvds/03-ruvds-winacme.ps1
Normal file
@@ -0,0 +1,159 @@
|
||||
# 03-ruvds-winacme.ps1 — win-acme setup + HTTP-01 challenge-path probe on RUVDS IIS host.
|
||||
# Idempotent. Run elevated on RUVDS (80.64.31.36) over SSH.
|
||||
# Phase switch: -Phase download|probe|cleanprobe
|
||||
param([string]$Phase = 'probe')
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
||||
$dest = 'C:\win-acme'
|
||||
$root = 'C:\sites\snolla'
|
||||
$chDir = Join-Path $root '.well-known\acme-challenge'
|
||||
|
||||
function Download-WinAcme {
|
||||
if (Test-Path (Join-Path $dest 'wacs.exe')) { Write-Output "wacs already present: $dest\wacs.exe"; return }
|
||||
$api = 'https://api.github.com/repos/win-acme/win-acme/releases/latest'
|
||||
$rel = Invoke-RestMethod -Uri $api -Headers @{ 'User-Agent' = 'ruvds-setup' }
|
||||
$asset = $rel.assets | Where-Object { $_.name -match 'x64\.pluggable\.zip$' } | Select-Object -First 1
|
||||
if (-not $asset) { throw "no x64.pluggable.zip asset in $($rel.tag_name)" }
|
||||
$zip = Join-Path $env:TEMP $asset.name
|
||||
Write-Output "downloading $($rel.tag_name): $($asset.name)"
|
||||
Invoke-WebRequest -Uri $asset.browser_download_url -OutFile $zip -Headers @{ 'User-Agent' = 'ruvds-setup' }
|
||||
New-Item -ItemType Directory -Force -Path $dest | Out-Null
|
||||
Expand-Archive -Path $zip -DestinationPath $dest -Force
|
||||
Remove-Item $zip -Force
|
||||
Write-Output ("installed: " + (Get-Item (Join-Path $dest 'wacs.exe')).VersionInfo.ProductVersion)
|
||||
}
|
||||
|
||||
function Test-ChallengePath {
|
||||
New-Item -ItemType Directory -Force -Path $chDir | Out-Null
|
||||
$token = 'acme-probe-' + (Get-Random)
|
||||
$tokenFile = Join-Path $chDir $token
|
||||
Set-Content -Path $tokenFile -Value $token -NoNewline -Encoding ascii
|
||||
Write-Output "token file: $tokenFile (content='$token')"
|
||||
|
||||
$hosts = 'snolla.com','tandemmebel.ru','maljarka.tandemmebel.ru','rimiz.ru'
|
||||
Write-Output "--- WITHOUT challenge web.config (baseline CMS behaviour) ---"
|
||||
Probe-Hosts $hosts $token
|
||||
|
||||
# Mirror the proven /admin escape: remove the catch-all Owin handler so OWIN stops
|
||||
# intercepting this path, add extensionless-token mime, drop managed-module overhead.
|
||||
$webcfg = @'
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<system.webServer>
|
||||
<handlers>
|
||||
<remove name="Owin" />
|
||||
</handlers>
|
||||
<staticContent>
|
||||
<remove fileExtension="." />
|
||||
<mimeMap fileExtension="." mimeType="text/plain" />
|
||||
</staticContent>
|
||||
<modules runAllManagedModulesForAllRequests="false" />
|
||||
</system.webServer>
|
||||
</configuration>
|
||||
'@
|
||||
Set-Content -Path (Join-Path $chDir 'web.config') -Value $webcfg -Encoding utf8
|
||||
Write-Output "--- WITH challenge web.config (win-acme style) ---"
|
||||
Probe-Hosts $hosts $token
|
||||
}
|
||||
|
||||
function Probe-Hosts($hosts, $token) {
|
||||
foreach ($h in $hosts) {
|
||||
try {
|
||||
$r = Invoke-WebRequest "http://localhost/.well-known/acme-challenge/$token" -Headers @{ Host = $h } -UseBasicParsing -TimeoutSec 15 -MaximumRedirection 0
|
||||
$ok = ($r.Content.Trim() -eq $token)
|
||||
Write-Output (" [{0}] HTTP {1} match={2} body='{3}'" -f $h, $r.StatusCode, $ok, ($r.Content -replace '\s+',' ').Substring(0,[Math]::Min(40,$r.Content.Length)))
|
||||
} catch {
|
||||
$resp = $_.Exception.Response
|
||||
if ($resp) { Write-Output (" [{0}] HTTP {1} loc={2}" -f $h, [int]$resp.StatusCode, $resp.Headers['Location']) }
|
||||
else { Write-Output (" [{0}] ERR: {1}" -f $h, $_.Exception.Message) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function Setup-ChallengeApp {
|
||||
Import-Module WebAdministration
|
||||
$pool = 'acme-challenge'
|
||||
if (-not (Test-Path "IIS:\AppPools\$pool")) { New-WebAppPool -Name $pool | Out-Null; Write-Output "created app pool $pool" }
|
||||
Set-ItemProperty "IIS:\AppPools\$pool" -Name managedRuntimeVersion -Value '' # No Managed Code
|
||||
Set-ItemProperty "IIS:\AppPools\$pool" -Name autoStart -Value $true
|
||||
New-Item -ItemType Directory -Force -Path $chDir | Out-Null
|
||||
# No-Managed-Code pool + drop the inherited catch-all Owin handler (else it 500s in an
|
||||
# unmanaged pool), serve extensionless ACME tokens as text/plain. Verified combo.
|
||||
$appcfg = @'
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<system.webServer>
|
||||
<handlers>
|
||||
<remove name="Owin" />
|
||||
</handlers>
|
||||
<staticContent>
|
||||
<remove fileExtension="." />
|
||||
<mimeMap fileExtension="." mimeType="text/plain" />
|
||||
</staticContent>
|
||||
<modules runAllManagedModulesForAllRequests="false" />
|
||||
<directoryBrowse enabled="false" />
|
||||
</system.webServer>
|
||||
</configuration>
|
||||
'@
|
||||
Set-Content -Path (Join-Path $chDir 'web.config') -Value $appcfg -Encoding utf8
|
||||
$vpath = '/.well-known/acme-challenge'
|
||||
$app = Get-WebApplication -Site 'snolla' | Where-Object { $_.path -eq $vpath }
|
||||
if (-not $app) {
|
||||
New-WebApplication -Site 'snolla' -Name '.well-known/acme-challenge' -PhysicalPath $chDir -ApplicationPool $pool -Force | Out-Null
|
||||
Write-Output "created IIS application $vpath (pool=$pool, No Managed Code)"
|
||||
} else {
|
||||
Set-ItemProperty "IIS:\Sites\snolla$vpath" -Name applicationPool -Value $pool
|
||||
Write-Output "IIS application $vpath exists (pool ensured=$pool)"
|
||||
}
|
||||
}
|
||||
|
||||
function Probe-Once {
|
||||
New-Item -ItemType Directory -Force -Path $chDir | Out-Null
|
||||
$token = 'acme-probe-' + (Get-Random)
|
||||
Set-Content -Path (Join-Path $chDir $token) -Value $token -NoNewline -Encoding ascii
|
||||
Write-Output "probe token: $token"
|
||||
Probe-Hosts ('snolla.com','tandemmebel.ru','www.tandemmebel.ru','maljarka.tandemmebel.ru','rimiz.ru','kupimknigi.spb.ru') $token
|
||||
}
|
||||
|
||||
function Clean-Probe {
|
||||
if (Test-Path $chDir) { Get-ChildItem $chDir -Filter 'acme-probe-*' | Remove-Item -Force -EA SilentlyContinue; Write-Output "removed probe tokens" }
|
||||
}
|
||||
|
||||
function Setup-RenewTask {
|
||||
$wacs = 'C:\win-acme\wacs.exe'
|
||||
$taskName = 'win-acme-renew-snolla'
|
||||
$action = New-ScheduledTaskAction -Execute $wacs -Argument '--renew --baseuri https://acme-v02.api.letsencrypt.org/'
|
||||
$trigger = New-ScheduledTaskTrigger -Daily -At 9am
|
||||
try { $trigger.RandomDelay = 'PT4H' } catch {}
|
||||
$principal = New-ScheduledTaskPrincipal -UserId 'SYSTEM' -LogonType ServiceAccount -RunLevel Highest
|
||||
$settings = New-ScheduledTaskSettingsSet -StartWhenAvailable -ExecutionTimeLimit (New-TimeSpan -Hours 2)
|
||||
Register-ScheduledTask -TaskName $taskName -Action $action -Trigger $trigger -Principal $principal -Settings $settings -Description 'Auto-renew Let''s Encrypt cert for IIS site snolla (25 SNI bindings) via HTTP-01.' -Force | Out-Null
|
||||
$t = Get-ScheduledTask -TaskName $taskName
|
||||
$info = $t | Get-ScheduledTaskInfo
|
||||
Write-Output ("task '{0}' state={1} nextRun={2}" -f $taskName, $t.State, $info.NextRunTime)
|
||||
|
||||
# remove the staging renewal so a stray --renew against staging does nothing
|
||||
$stagingRenewals = 'C:\ProgramData\win-acme\acme-staging-v02.api.letsencrypt.org\Renewals'
|
||||
if (Test-Path $stagingRenewals) { Remove-Item "$stagingRenewals\*" -Recurse -Force -EA SilentlyContinue; Write-Output "cleared staging renewals" }
|
||||
if (Test-Path 'C:\win-acme\stagingtest') { Remove-Item 'C:\win-acme\stagingtest' -Recurse -Force -EA SilentlyContinue; Write-Output "removed stagingtest pemfiles" }
|
||||
}
|
||||
|
||||
function Verify-Certs {
|
||||
Import-Module WebAdministration
|
||||
# show the cert now bound (thumbprint -> subject/expiry)
|
||||
$b = Get-WebBinding -Port 443 | Select-Object -First 1
|
||||
$hash = (Get-Item "IIS:\SslBindings\*!443!*" -EA SilentlyContinue | Select-Object -First 1).Thumbprint
|
||||
Get-ChildItem Cert:\LocalMachine\WebHosting | Sort-Object NotAfter -Descending | Select-Object -First 3 |
|
||||
ForEach-Object { Write-Output ("WebHosting cert: {0} | NotAfter={1} | Issuer={2} | SAN-count via DnsNameList={3}" -f $_.Thumbprint, $_.NotAfter, $_.Issuer, $_.DnsNameList.Count) }
|
||||
}
|
||||
|
||||
switch ($Phase) {
|
||||
'download' { Download-WinAcme }
|
||||
'probe' { Download-WinAcme; Test-ChallengePath }
|
||||
'app' { Download-WinAcme; Setup-ChallengeApp; Probe-Once }
|
||||
'task' { Setup-RenewTask; Verify-Certs }
|
||||
'verify' { Verify-Certs }
|
||||
'cleanprobe' { Clean-Probe }
|
||||
default { throw "unknown phase $Phase" }
|
||||
}
|
||||
23
scripts/iis-migration-to-ruvds/winacme-Web_Config.xml
Normal file
23
scripts/iis-migration-to-ruvds/winacme-Web_Config.xml
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
win-acme HTTP-01 challenge web.config template (overwrites C:\win-acme\Web_Config.xml on RUVDS).
|
||||
Patched for the MoreThenCms / OWIN catch-all: the .well-known/acme-challenge folder is a
|
||||
separate IIS application in a "No Managed Code" app pool (acme-challenge). The inherited
|
||||
catch-all Owin *managed* handler 500s in an unmanaged pool, so we <remove> it; tokens are
|
||||
served by the native StaticFileModule with an extensionless mimeMap. See task decisions log.
|
||||
-->
|
||||
<configuration>
|
||||
<system.webServer>
|
||||
<httpRedirect enabled="false" />
|
||||
<validation validateIntegratedModeConfiguration="false" />
|
||||
<handlers>
|
||||
<remove name="Owin" />
|
||||
</handlers>
|
||||
<modules runAllManagedModulesForAllRequests="false" />
|
||||
<staticContent>
|
||||
<clear />
|
||||
<mimeMap fileExtension="." mimeType="text/json" />
|
||||
<mimeMap fileExtension=".*" mimeType="text/json" />
|
||||
</staticContent>
|
||||
</system.webServer>
|
||||
</configuration>
|
||||
Reference in New Issue
Block a user