Skip to content

Latest commit

 

History

History
171 lines (133 loc) · 11.5 KB

File metadata and controls

171 lines (133 loc) · 11.5 KB

05 · Диагностика и грабли

Тестов в стеке нет. Диагностика — это чтение живого состояния системы: логи, ss, nft list, docker exec ... version. Почти каждая ошибка ниже выглядела не тем, чем была — экономит время правило менять по одному и смотреть на факт, а не на конфиг.

Быстрая проверка

sudo ./scripts/check-stack.sh                       # все слои разом, read-only
sudo ./scripts/check-reality-target.sh 127.0.0.1:10444   # годится ли таргет
sudo ./scripts/diagnose-reality.sh 200 plug2.example.com # разбор лога nginx

Пример вывода check-stack.sh на здоровой системе:

── Контейнеры
  ✓ 3x-ui — running
  ✓ telemt — running
  ✓ mtproto_gate — running
  ✓ stub-site1 — running
  ✓ stub-site2 — running

── JA4T-сплит (nftables)
  ✓ таблица inet mtpr_ja4t_split присутствует
  ✓ правило редиректа на месте
  ✓ лимит для iOS выключен — режим по умолчанию

── Сертификаты
  ✓ example-rsa — RSA, сертификатов в цепочке: 3, осталось 89 дн.
  ✓ example.com — ECDSA, сертификатов в цепочке: 4, осталось 87 дн.
  ✓ deploy-хук перезагрузки nginx на месте

── Xray
  ✓ версия 26.6.1 — совпадает с ожидаемой

Строка «лимит для iOS выключен — режим по умолчанию» — норма, не поломка: лимит для iOS отключён намеренно (см. 04-services.md).

Сигнатуры в stream_access.log

Главный диагностический инструмент: по ответу nginx видно, на каком слое сломалось, даже без логов Xray.

bytes_sent session_time Диагноз
≈ 3–4 КБ ≈ 0.1 с Reality-fallback: клиент не аутентифицирован, получил TLS заглушки и оборвался
0 ~0.01 с Таргет недоступен либо Xray упал раньше ответа
> 10 КБ секунды Рабочий туннель
sni="-", нули ~0.01 с Сканирование без SNI, обрыв по default ""норма

Точный размер fallback свой у каждой заглушки; diagnose-reality.sh определяет его сам по самому частому значению.

Различение слоёв по логу Xray

docker exec 3x-ui grep -viE "dokodemo|detour \[api\]" /var/log/x-ui/error.log | tail -30
Сообщение Слой Куда смотреть
transport/internet/tcp: REALITY: ... authentication failed or validation criteria not met TLS/Reality ключи, shortId, SNI, версия Xray, ML-DSA65
transport/internet/tcp: REALITY: ... handshake did not complete successfully TLS/Reality таргет недоступен или не подходит
proxy/vless/inbound: ML-KEM-768 handshake failed VLESS Reality прошёл, клиент не умеет VLESS Encryption
proxy/vless/inbound: invalid request user id VLESS Reality прошёл, неверный UUID

Самое ценное различение здесь: первые два — проблема до туннеля, вторые два — туннель установился, дело в VLESS.

Дерево решений

flowchart TD
    S["VPN не работает"] --> L{"Что в<br/>stream_access.log?"}

    L -->|"записей нет"| N1["Не доходит до nginx:<br/>DNS, UFW, JA4T"]
    L -->|"bytes_sent = 0"| N2["Таргет недоступен<br/>или Xray упал"]
    L -->|"bytes_sent ≈ 3-4 КБ<br/>session ≈ 0.1 с"| N3["Reality не аутентифицировал<br/>клиента → fallback"]
    L -->|"трафик идёт"| N4["Транспорт жив,<br/>ищите выше: DNS, роутинг"]

    N3 --> E{"Что в логе Xray?"}
    E -->|"transport/internet/tcp:<br/>REALITY:"| R1["Слой TLS:<br/>ключи · shortId · SNI ·<br/>версия Xray · mldsa65"]
    E -->|"proxy/vless/inbound:<br/>ML-KEM-768"| R2["Reality прошёл.<br/>Слой VLESS Encryption:<br/>клиент не поддерживает"]

    style N3 fill:#2d1418,stroke:#f85149,color:#c9d1d9
    style R1 fill:#0d2136,stroke:#2f81f7,color:#c9d1d9
    style R2 fill:#1a1030,stroke:#a371f7,color:#c9d1d9
Loading

Reality не подключается: порядок проверки

От дешёвого к дорогому.

  1. Ссылка перевыпущена? Удалить профиль целиком и добавить заново.
  2. Ключи парные? docker exec 3x-ui /app/bin/xray-linux-amd64 x25519 -i "<privateKey>"Password (PublicKey) = pbk в ссылке.
  3. Версия Xray? docker exec 3x-ui /app/bin/xray-linux-amd64 version — 26.7.x ломает Reality (грабля №1).
  4. Таргет жив и подходит? ./scripts/check-reality-target.sh 127.0.0.1:10444
  5. Время синхронно? date; docker exec 3x-ui date — сравнивать в UTC.
  6. Контейнер ходит наружу? docker exec 3x-ui /app/bin/xray-linux-amd64 tls ping www.google.com:443

Грабли

# Симптом Причина Лечение
1 Shadowrocket/mihomo не пускает, Happ работает Регрессия Xray 26.7.11 (#6477) Пин 3x-ui:v3.3.1 (Xray 26.6.1)
2 Версия в compose верная, а работает другая «Обновить ядро» в панели пишет в writable-слой, не видно в теге образа ... version + --force-recreate
3 С mldsa65Seed Reality не работает Нужен объёмный сертификат таргета — разбор ниже RSA-линия для таргета либо без ML-DSA65
4 Убрали seed на сервере — не помогло На клиенте остался mldsa65Verify Чистить обе стороны сразу
5 Через 60–90 дней VPN тихо умирает Нет deploy-хука, nginx держит старый сертификат в памяти Хук — 03-certificates.md
6 certbot renew --dry-run падает Две линии на одни домены пишут одну TXT-запись, 10 сек мало dns_cloudflare_propagation_seconds = 60
7 Connection refused при живом контейнере Bridge-сеть прячет инбаунды; mask_host=127.0.0.1 указал бы в никуда network_mode: host обязателен
8 Заглушка открывается, маскировка нет mask_port указывал на HTTP-бэкенд вместо TLS-фронта Указать порт TLS-терминации
9 Ссылки telemt выглядят верно и не работают public_host разошёлся с tls_domain Свести оба значения
10 nftables-правила не применяются reject недопустим в цепочке nat reject — в отдельной filter/input
11 После proxy_protocol on падает один бэкенд Настройка на весь блок, не per-backend — 04-services.md Все апстримы принимают PROXY-преамбулу
12 www.microsoft.com непригоден как таргет Сертификат 8273 байта против лимита 8192 (#6356) — разбор ниже Для теста брать заведомо рабочий домен
13 Скрипт говорит «правила нет», хотя оно есть pipefail + grep -q = SIGPIPE, конвейер считается упавшим Сохранять вывод в переменную

Reality-таргет не подходит по объёму

Разбор граблей №3 и №12. С mldsa65Seed в поддельный сертификат Reality встраивается пост-квантовая подпись ~3.3 КБ — чтобы она не выглядела аномалией, TLS-запись таргета должна быть достаточно крупной. Порог не про алгоритм, а про объём. Измерения на Xray 26.6.1, единственная переменная — таргет или сертификат.

Внешние таргеты: nvidia.com, apple.com, bing.com, samsung.com — ✅. cloudflare.com, vk.com, microsoft.com — ❌.

Своя заглушка, разные сертификаты (таргет один — 127.0.0.1:10444):

Сертификат Длина цепочки ML-DSA65
ECDSA Let's Encrypt 3390 байт
RSA самоподписанный 2569 байт
RSA самоподписанный 4196 байт
RSA Let's Encrypt 4096 4308 байт ✅ (5/5)

Дело не в алгоритме, а в объёме: короткий RSA (2569) падает так же, как ECDSA. Мерить надо подключением — vk.com (2759 байт) не работает, nvidia.com работает при похожей длине. tls ping показывает не ту метрику: длину цепочки сертификатов, а не размер всей TLS-записи (плюс OCSP-степлинг, SCT, расширения) — величины близкие, но не равные, а на границе это решает.

Отдельно — microsoft.com: запись сертификата 8273 байта против захардкоженного лимита 8192 в парсере Reality (XTLS/Xray-core#6356). Непригоден как таргет вообще, даже без ML-DSA65 — важно, раз он часто встречается в примерах конфигов.

Проверка конкретного таргета: ./scripts/check-reality-target.sh <host:port>.

Регулярный контроль

sudo ./scripts/check-stack.sh                       # раз в неделю
sudo certbot renew --dry-run                        # раз в месяц
sudo ./scripts/diagnose-reality.sh 500               # при жалобах
docker exec 3x-ui /app/bin/xray-linux-amd64 version  # раз в месяц

Последнее — на случай, если кто-то нажал «обновить ядро» в панели (грабля №2); check-stack.sh это тоже ловит, но привычка проверять напрямую не повредит.