From 6a5b075039204020d77c3ff953d78693493598c0 Mon Sep 17 00:00:00 2001 From: oqyude Date: Sat, 10 Oct 2026 21:38:49 +0300 Subject: [PATCH] =?UTF-8?q?docs(agent):=20R1.11-R1.13=20=E2=80=94=20podman?= =?UTF-8?q?=20ports,=20x-ui.db=20rollback,=20panel=20TLS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also fixes R1 numbering: two items were both labelled '8', so reality443Forwarding counted as ninth while AGENTS.md, traps and f2e70bb already referenced it as R1.10. Verification commands were executed against the live host: '{{json .Ports}}' and 'exec xray version' both fail, corrected to .NetworkSettings.Ports and /app/bin/xray-linux-amd64. --- .agent/decisions/0003-3x-ui-reality-chain.md | 14 ++-- .agent/rules/project-rules.md | 84 ++++++++++++++++---- AGENTS.md | 5 ++ 3 files changed, 82 insertions(+), 21 deletions(-) diff --git a/.agent/decisions/0003-3x-ui-reality-chain.md b/.agent/decisions/0003-3x-ui-reality-chain.md index 59160b5..5126b3e 100644 --- a/.agent/decisions/0003-3x-ui-reality-chain.md +++ b/.agent/decisions/0003-3x-ui-reality-chain.md @@ -17,13 +17,13 @@ |---|---| | 16:25:52 | `0df9688` (задача T10) — удалён `reality443Forwarding` | | 17:05:27 | первый `Connection refused` к `127.0.0.1:15380` в журнале nginx | -| 17:07:33 | первое `worker_connections are not enough` (с 37.128.246.126) | +| 17:07:33 | первое `worker_connections are not enough` (адрес обезличен) | | ~17:15 | клиенты уходят в ретрай-петлю: ~1668 ошибок за ~40 мин | | 17:30:58 | `37b4956` — revert nftables (T3) | | 17:54:18 | `07a0437` — `reality443Forwarding` восстановлен | | 17:55:38 | контейнер `3xui_app` пересоздан с `127.0.0.1:15380:443/tcp` | | ~18:05+ | флуд прекращается, ошибок 0 за 36 мин | -| 19:16–19:19 | живые REALITY-сессии, `oqyude` и `snity` online | +| 19:16–19:19 | живые REALITY-сессии, клиенты online | Два вывода, которые неочевидны и потому требуют фиксации: @@ -35,11 +35,11 @@ 2. **`worker_connections are not enough` — вторичный симптом, а не причина.** nginx имеет пустой `events {}` → `worker_connections` = 512 (дефолт). Пока - маршрут на 443 был мёртв, реальные клиенты (37.128.246.126 — lanta-me, - Тамбов; 213.135.154.225 — Ростелеком, Тамбов) слали 517-байтные - ClientHello в цикле и выедали 512 соединений. Из-за этого «не работало - всё» даже там, где конкретная причина уже была устранена, и создавался - флуд в логах, уводящий от настоящей причины. + маршрут на 443 был мёртв, реальные клиенты слали 517-байтные ClientHello + в цикле и выедали 512 соединений. Из-за этого «не работало всё» даже там, + где конкретная причина уже была устранена, и создавался флуд в логах, + уводящий от настоящей причины. Источники флуда — два адреса /24 из + разных сетей; адреса и провайдеры обезличены (репозиторий публичный). Отдельно: `x-ui.db.bak.1787862834` (2026-08-27) при поверхностном взгляде выглядит как «бэкап, который можно откатить». Это **другая конфигурационная diff --git a/.agent/rules/project-rules.md b/.agent/rules/project-rules.md index 07d1e4e..57af7f8 100644 --- a/.agent/rules/project-rules.md +++ b/.agent/rules/project-rules.md @@ -35,26 +35,57 @@ 7. **sops-пути — через `config.sops.secrets..path`.** Любой `path =` override на sops-блоке делает хардкод-потребителя молча сломанным: rebuild зелёный, сервис стартует, контент пустой. См. ADR-0001. -8. **Backups: external/unknown — accepted risk.** На 2026-10-10 open question +8. **Версия ядра Xray — состояние UI-панели 3x-ui, не Nix.** Ядро + ставится через UI панели (UI → xray version) и хранится в её + sqlite-БД. Перед любым деплоем/ребутом 3x-ui — проверить версию + ядра в панели. Nix декларирует панель (`:latest`), но не ядро. +9. **Backups: external/unknown — accepted risk.** На 2026-10-10 open question 5.6 («где бэкапы, как проверяются?») не отвечен владельцем. В этом репозитории **не декларируется** ни одна бэкап-стратегия. Failure modes (потеря `/dev/sdc1` = потеря всех 9 сервисов на sapphira) перечислены в `.agent/decisions/0002-backups-external.md`. Если в будущем бэкап-система появится — отменить этот R1.9 и зафиксировать R1.x про регулярную верификацию. -8. **Версия ядра Xray — состояние UI-панели 3x-ui, не Nix.** Ядро - ставится через UI панели (UI → xray version) и хранится в её - sqlite-БД. Перед любым деплоем/ребутом 3x-ui на sapphira — - проверить версию ядра в панели. Nix декларирует панель (`:latest`), - но не ядро. -9. **`reality443Forwarding = true` на VDS обязателен, НЕ удалять.** - `modules/vds/nginx.nix` маршрутизирует реальный `443` через stream: - `pubray1.zeroq.su → 127.0.0.1:2049` (панель), всё остальное - (в т.ч. SNI `media.mediavitrina.ru` для REALITY-клиентов) → - `127.0.0.1:15380 → container:443`. Маппинг `127.0.0.1:15380:443/tcp` - публикует опция `reality443Forwarding` (T10/C5 «погасил» её 2026-10-10 — - Xray REALITY стал недоступен при живых SSH и pubray1.zeroq.su; - восстановлено `07a0437`, manifest T10 → status `pending`). +10. **`reality443Forwarding = true` на VDS обязателен, НЕ удалять.** + `modules/vds/nginx.nix` маршрутизирует реальный `443` через stream: + `pubray1.zeroq.su → 127.0.0.1:2049` (панель), всё остальное + (в т.ч. SNI `media.mediavitrina.ru` для REALITY-клиентов) → + `127.0.0.1:15380 → container:443`. Маппинг `127.0.0.1:15380:443/tcp` + публикует опция `reality443Forwarding` (T10/C5 «погасил» её 2026-10-10 — + Xray REALITY стал недоступен при живых SSH и pubray1.zeroq.su; + восстановлено `07a0437`, manifest T10 → status `pending`). + **Сигнатура отказа НЕ выглядит как «Xray упал»** (2026-10-10, T10): + контейнер здоров, `restarts=0`, ядро 26.7.28 на месте, SSH жив, панель по + SNI `pubray1.zeroq.su` отвечает валидным сертификатом — но в журнале nginx + `connect() to 127.0.0.1:15380 failed (111: Connection refused)` и масса + `worker_connections are not enough`. Диагностировать «панель/Xray» надо + **пробой порта 15380 и `podman inspect .NetworkSettings.Ports`**, а не по симптому. +11. **Декларация портов ≠ runtime.** `ports` в + `virtualisation.oci-containers.containers."3xui_app"` + (`modules/containers/3x-ui.nix:26-35,68`) применяются **только при + пересоздании контейнера**. Правка Nix без `nixos-rebuild switch` не меняет + ничего; проверка после деплоя — обязательна: + ```bash + sudo podman inspect 3xui_app --format '{{json .NetworkSettings.Ports}}' # ждём 15380 + ``` + Любой ребилд, пересоздающий `3xui_app`, = окно недоступности REALITY + (2026-10-10: `07a0437` 17:54:18 → контейнер пересоздан 17:55:38). + Клиенты в это окно уходят в ретрай-флуд (см. R1.12 и ADR-0003). +12. **`x-ui.db` не откатывать на `x-ui.db.bak.1787862834`.** Живая БД — + `/mnt/services/nodes/otreca/3x-ui/db/x-ui.db` (в контейнере + `/etc/x-ui/x-ui.db`), схема **v3**, колонка `stream_settings`. + Бэкап от 2026-08-27 (311296 B) — **другая конфигурационная эпоха**: + инбаунды `id` 3/39/15/33 на портах **14380/14480/14910/14920** + (tcp/xhttp/xhttp/grpc), 7 клиентов, без `dest media.mediavitrina.ru`. + Текущая БД: `id` 42/45/46 на **443/8443/18443** (xhttp+reality), 11 клиентов. + Откат заменит рабочие инбаунды и обесценит все 11 клиентских конфигов. +13. **TLS терминирует панель 3x-ui, не nginx.** На otreca nginx в `stream` + делает только `ssl_preread` и проксирует сырой TCP; TLS живёт **внутри** + контейнера. Сертификат: хост `/var/lib/acme/pubray1.zeroq.su/{fullchain,key}.pem` + → bind-mount `ro` в `/root/cert/*`; в настройках панели + `webCertFile=/root/cert/fullchain.pem`, `webKeyFile=/root/cert/key.pem`. + **Не добавлять** TLS-терминирующий `server {}` для `pubray1.zeroq.su` — + перекроет stream-SNI карту и убьёт и панель, и REALITY. ### R2. home-manager `Service` ≠ `serviceConfig` @@ -111,6 +142,8 @@ nix build .#nixosConfigurations.<хост>.config.system.build.toplevel --dry-ru | `users.nix:66` | `uid = if hostname == "sapphira" then 1001 else …` | Костыль под 1000 = удалённый `yuyus`; удалять только после миграции ФС | | `3x-ui.nix:54` | `image = …:latest` | Панель намеренно latest; ядро Xray — состояние панели, см. R1.8 | | `3x-ui.nix:33-35` | `reality443Forwarding = true` на VDS | **Обязательно, НЕ удалять** (R1.10). nginx stream (`vds/nginx.nix`) маршрутизирует `443 → 127.0.0.1:15380 → container:443`; без маппинга Xray REALITY мёртв. Удаление T10/C5 сломало — восстановлено `07a0437` | +| `vds/nginx.nix`, `events {}` | Пустой блок → `worker_connections` = **512** (дефолт) | Не баг, но и не запас: при окне недоступности REALITY клиенты дают ретрай-флуд и исчерпывают 512 → «не работает всё» даже после починки первопричины (2026-10-10: 1668 ошибок за ~40 мин). Известный пробел, задача не заведена | +| Настройки панели, `webBasePath = /pubray/` | `GET https://pubray1.zeroq.su/` → **404, 0 байт** | Панель жива, корень не корень. Реальный URL — `https://pubray1.zeroq.su/pubray/` (HTTP 200). `/subs/` без токена тоже 404 — это норма. Не «чинить» nginx под `/` | | `server/default.nix:37-50` | 14 закомментированных модулей (13 архивировано, 1 stirling-pdf удалён в 5dd7a58) | Отключены осознанно, см. задачу T16 | | `opencode.nix:339` | `systemd.user.services.opencode-web.Service` | `serviceConfig` рендерится в секцию `[serviceConfig]`, systemd молча игнорирует (`c73a698`); см. R2 | | `vds.nix:73-91` | nftables без финального правила | Известный пробел, см. задачу A3 | @@ -159,8 +192,31 @@ systemctl show postgresql -p Requires -p After | tr ' ' '\n' | grep -E 'mnt-|hom # sops sops --version + +# цепочка 3x-ui REALITY на otreca (после любого деплоя, трогающего 3x-ui/nginx) +sudo podman inspect 3xui_app --format '{{json .NetworkSettings.Ports}}' # есть 15380->443 +sudo podman exec 3xui_app /app/bin/xray-linux-amd64 version # ожидаем 26.7.x +curl -ks --resolve pubray1.zeroq.su:443:127.0.0.1 -o /dev/null \ + -w '%{http_code}\n' https://pubray1.zeroq.su/pubray/ # ожидаем 200 +sudo journalctl -u nginx --since '-10 min' | grep -cE 'worker_connections|Connection refused' # ожидаем 0 ``` +## Диагностика «REALITY на otreca не работает» (порядок, 2026-10-10) + +1. `sudo podman inspect 3xui_app --format '{{json .NetworkSettings.Ports}}'` — есть ли `15380->443`. + Нет → R1.10/R1.11 (декларация разошлась с runtime), контейнер не пересоздан. +2. `sudo podman exec 3xui_app /app/bin/xray-linux-amd64 version` — должно быть + 26.7.x (R1.8). Не 26.9.x. **В `$PATH` контейнера бинаря нет** — только + полный путь. +3. `sudo podman exec 3xui_app python3 -c "import sqlite3;…"` — `inbounds` в + `x-ui.db` (колонка `stream_settings`): порты 443/8443, `network=xhttp`, + `security=reality`, `enable=1`. Сверить с `/app/bin/config.json` внутри контейнера. +4. Проба 443 снаружи: TLS с SNI `media.mediavitrina.ru` должен вернуть + steal-сертификат `*.mediavitrina.ru`; SNI `pubray1.zeroq.su` — валидный + сертификат панели. +5. Только если 1–4 зелёные, а пользователь всё ещё видит отказ — проблема + клиентская (старый конфиг, клиент без поддержки `xhttp`). + ## Конвенции проекта - `xlib` (в `lib/xlib/`) — чистые данные: identity (`device`), capability flags, diff --git a/AGENTS.md b/AGENTS.md index 1a0a8b8..96d1c7b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -75,6 +75,9 @@ flake.nix 5. **3x-ui заморожен.** Панель на `:latest`, ядро Xray на 26.7.x. Миграция на 26.9.x провалена. → задачи T6–T10. 6. **nftables на VDS требует явной финальной политики.** Текущий ruleset — без финального правила → неявный accept. → задача T3. 7. **sops-пути — через `config.sops.secrets..path`.** Любой `path =` override на sops-блоке делает хардкод-потребителя молча сломанным. → ADR-0001. +8. **Декларация портов ≠ runtime.** `ports` контейнера `3xui_app` применяются только при пересоздании; правка Nix без `nixos-rebuild` не меняет ничего. Проверка: `podman inspect 3xui_app --format '{{json .NetworkSettings.Ports}}'`. → R1.11, ADR-0003. +9. **`x-ui.db` не откатывать на `x-ui.db.bak.1787862834`.** Бэкап от 2026-08-27 — другая эпоха (порты 14380/14480/14910/14920, 7 клиентов). Откат убьёт рабочие 443/8443 и все 11 конфигов. → R1.12, ADR-0003. +10. **TLS терминирует панель 3x-ui, не nginx.** nginx делает только `ssl_preread` и проксирует сырой TCP; сертификат смонтирован в контейнер `ro`. TLS-терминирующий `server {}` для `pubray1.zeroq.su` перекроет stream-SNI и убьёт и панель, и REALITY. → R1.13, ADR-0003. ## Ловушки (выглядит сломанным, намеренно) @@ -85,6 +88,8 @@ flake.nix | `users.nix:66` | `uid = if hostname == "sapphira" then 1001 else …` | Костыль под 1000 = удалённый `yuyus`; удалять только после миграции ФС | | `3x-ui.nix:54` | `image = …:latest` | Панель намеренно latest; ядро Xray — на 26.7.x | | `3x-ui.nix:33-35` | `reality443Forwarding = true` на VDS | **Обязательно, НЕ удалять.** nginx stream (`vds/nginx.nix`) маршрутизирует `443 → 127.0.0.1:15380 → container:443`; без маппинга Xray REALITY мёртв. Удаление T10/C5 сломало — восстановлено `07a0437` | +| `vds/nginx.nix`, `events {}` | Пустой блок → `worker_connections` = **512** (дефолт) | Не баг, но и не запас: при окне недоступности REALITY клиенты дают ретрай-флуд и исчерпывают 512 → «не работает всё» даже после починки первопричины (1668 ошибок за ~40 мин). Известный пробел | +| Настройки панели | `GET https://pubray1.zeroq.su/` → **404** | Панель жива: `webBasePath=/pubray/`, реальный URL `https://pubray1.zeroq.su/pubray/`. Не «чинить» nginx под `/` | | `server/default.nix:37-50` | 14 закомментированных модулей (13 архивировано, 1 stirling-pdf удалён в 5dd7a58) | Отключены осознанно, см. задачу T16 | | `opencode.nix:339` | `systemd.user.services.opencode-web.Service` | `serviceConfig` рендерится в секцию `[serviceConfig]`, systemd молча игнорирует; см. R2 | | `vds.nix:73-91` | nftables без финального правила | Известный пробел, см. задачу T3 |