lightweight-server/agents/codex/done/2026-10-23-vps-ru-de-setup.md
ochenstarik-ui 7329c1164f
All checks were successful
Bash syntax / syntax (push) Successful in 17s
Bash syntax / syntax (pull_request) Successful in 17s
docs: record DE443 home inbound and scoped acceptance
2026-10-23 17:22:39 +07:00

28 KiB
Raw Blame History

RU/DE VPS — настройка 23.10.2026

База и прямой VPN-вход из текущей сети: PASS. Первоначальный HOLD устранён точечным исключением RU-IP из локального прозрачного прокси. Обычный REALITY-клиент без SSH выходит в зарубежный Интернет через DE, к российскому сервису через RU. Другая сеть и устройство семьи проверяются при переносе. Финляндия и Дания не затронуты.

Основание и исходники

Прямое задание владельца: kagent/agents/claude/done/2026-10-23-fixes/CODEX-vps-setup-ru-de.md; повтор kagent/kagent в переданном пути исправлен. Только два адреса из разрешённых RU/DE файлов; иных SSH-хостов не проверял. Порядок: RU полностью, затем DE, затем связка.

Развёрнуты скрипты main после PR19, точный merge SHA 47d5e030dfa392a995649c0519088aae74f73935 (PR19 head eb00e38a7515c6772535322d7b353c9c01718fcc). Merge и main CI5/task7370 SUCCESS проверены до работы. Использован отдельный worktree существующего репозитория; скрипты переданы SCP, все SHA-256 сверены на серверах. С GitHub репозиторий на VPS не клонировался. Продуктовых прогонов KAgent/Telegram не запускал.

Первый парольный вход — один на каждый VPS через SSH_ASKPASS, без паролей в argv/history/логах/временных копиях. Далее — новый ключ оператора. Исходные .env и .ppk не копировались и не менялись, каталог700/файлы600 сохранены. У .ppk читались только заголовки и ровно Public-Lines, остановка до приватной части.

Host keys (Ed25519), зафиксированы при первом контакте, TOFU, не независимая внеполосная аттестация:

  • RU: SHA256:rYHjuLL2NjiHlImXA3ShWCeZBrdoGbGw0phQfxafJlE
  • DE: SHA256:UeebWqUQoNx4FePQGV4P14iSpzZHClFDjndLm/9k3DI

Постоянный known_hosts: ~/.ssh/kagent_vps_known_hosts; новый порт привязан к тому же ранее проверенному host key. Создан ~/.ssh/kagent_vps_ed25519 (0600). Приватный ключ не передавался на VPS. В новом admin authorized_keys обоих — публичные ключи владельца и оператора. Полный вход оператора и sudo с паролем проверены. Сервер отдельно подтвердил приём публичного ключа владельца (SSH public-key probe); end-to-end подпись его приватным ключом не выполнялась, поскольку приватную часть PPK читать запрещено.

Выполненные этапы

Проверка RU DE
ОС Ubuntu24.04 LTS: проверка24.04.4, после обновления24.04.5 то же
Часовой пояс Europe/Moscow Europe/Berlin
Этап1 swap2GiB, текущая локаль сохранена, необязательные программы пропущены существующий swap512MiB сохранён, локаль сохранена, программы пропущены
Этап2 IPv4, выбранный SSH +443, временный22 затем удалён то же
Этап3 новый admin, два ключа, SSH root/password/kbdinteractive no, sudo с паролем то же
Вторая независимая key-session PASS до подтверждения удаления22 PASS до подтверждения удаления22
Этап6 3x-ui v3.10.2; панель и подписки loopback; WARP off то же
Получение 3x-ui GitHub, закреплённые SHA-256 main-helper то же
Страница входа через SSH-L HTTP200 HTTP200
Этап7 initial snapshot +checksum PASS initial snapshot +checksum PASS
Состояние после связки и финальной смены секретов consistent SQLite checkpoint +ручные daily snapshots/checksum PASS то же

Автоматические расписания не включались; первичные снимки не перезаписывались. После API-ротации логина/пароля/секретного пути выполнен финальный согласованный checkpoint БД и новый ручной снимок, чтобы восстановление соответствовало актуальным env-файлам. Настройка выполнялась без изменения глобальной сети/брандмауэра этой машины. Этапы4,5,8 не выполнялись. Telegram-узел DE не ставился. WARP не установлен.

На Ubuntu с socket activation после обновления пакетов отсутствовал /run/sshd; standalone sshd -t завершился ошибкой до рестарта. Обратимо создан стандартный служебный каталог root:root755, затем неизменённый main-скрипт прошёл проверку и перенос SSH. Текущая административная сессия сохранялась до новой key-session и password-sudo проверки.

Перед контрольной перезагрузкой обнаружено: RU ufw.service была masked, хотя действующие kernel rules были активны. До перезагрузки сохранена исходная mask-ссылка в закрытом root-каталоге codex-ufw-boot-before-*, выполнены systemctl unmask ufw.service и systemctl enable ufw.service. DE служба уже была enabled. Это локализованное операционное исправление, не автоматическое снятие произвольных масок установщиком.

Оба VPS последовательно перезагружены. Boot ID изменился; новая независимая key-session admin, UFW, x-ui и fail2ban после загрузки PASS. Итоговые ядра: RU6.8.0-100-generic, DE6.8.0-147-generic; ниже приведены реальные post-boot снимки. Обе страницы панелей и оба egress-направления повторно проверены после загрузки.

Оба дефекта оформлены отдельным code PR20: head e5b06793ec69dcbdf402b72b2e661453a7732569; 14тестов PASS, pushCI9/task7381 и PRCI10/task7382 SUCCESS именно на этом SHA. Этап3 подготавливает runtime directory, этап2 требует автозапуск UFW до изменения правил и отказывает при маске без её автоматического снятия. Существующие тесты не изменены. Полный pushlog23954B без усечения проверен, оба новых теста и Job succeeded присутствуют; SHA256 f74aee3ac1f4d4902145a6a42554073156ccf8bd40958c43d1c7f47fd8a25483. На VPS выполнялись описанные операционные исправления; несмерженный код PR20 не разворачивался.

Связка и сетевые проверки

Через аутентифицированный API 3x-ui по SSH-туннелям, с штатным CSRF-token/session cookie:

  • DE: VLESS+Reality TCP на24443, inbound codex-ru-de-link, клиент ru-link; UFW разрешает этот порт только с RU_IP. В общий список глобально публикуемых managed ports он не добавлен, чтобы последующий рендер не расширил CIDR-правило до Anywhere.
  • RU: VLESS+Reality443, один тестовый клиент owner-test, inbound family-owner-test; outbound vpn-de — в DE. Private IP и geoip:ru → direct; geosite:category-ru и домены ru/su/рф → direct; остальное по умолчанию → DE. Служебные API/stats и прежние правила сохранены.
  • Native Xray из закреплённого 3x-ui:26.10.10 на обоих; временный клиент26.10.21 (SHA-256 проверен по pinned архиву). Также проверялся клиент26.10.10: наблюдение не является только различием версий.
  • Начальный camouflage target RU Microsoft сменён на доступный Cloudflare; ключи/UUID не ротировались. DE target Microsoft. После изменения выполнен штатный reload Xray. Настройки в реальном config.json сверены с API-моделью. Подмены TLS/отключения проверок сертификата нет.
Путь клиента Зарубежный запрос api.ipify.org Российский запрос к сервису Яндекса Статус
Эта машина → публичный RU443, до исправления TLS error35 TLS error35 исторический HOLD, устранён
Эта машина → публичный RU443, после исправления фактический IP=DE_IP фактический IP=RU_IP PASS, без SSH
Эта машина → SSH-L к тому же RU443 → REALITY фактический IP=DE_IP фактический IP=RU_IP PASS, это SSH-путь
Временный клиент на DE → публичный RU443 → DE фактический IP=DE_IP фактический IP=RU_IP PASS, внешний контроль публичного входа

Российская проверка: https://ipv4-internet.yandex.net/api/v0/ip; ответ сопоставлен с RU_IP в памяти, сам IP не журналировался. 2ip.ru вернул HTTP-ошибку и не использовался как положительное доказательство.

Первоначально REALITY получал маскирующий сертификат, хотя UUID, SNI, short ID, private/public pair и загруженные настройки совпадали. Через SSH и с DE ошибки не было. Перебор fingerprint/SNI/версии не устранил исходный отказ; это историческое наблюдение.

Прямой HOLD устранён — дополнительное поручение владельца

На этой машине активен xray-transparent.service: /usr/local/sbin/xray-transparent-up перенаправляет TCP вне bypass4 на локальный Xray12345. RU-IP отсутствовал в исключениях. ip route get показывал физический интерфейс, но не последующий NAT redirect. До исправления пять отправленных ClientHello не дали ни одного пакета в ограниченном по времени захвате входящего RU443; публичный RU-IP действительно назначен интерфейсу. Часы совпадают, min/maxClientVer/maxTimeDiff не заданы. Причина HOLD — локальный прозрачный перехват; внешний DPI/MITM не заявляется.

После аутентификации владельца штатным pkexec добавлен только RU-IP в действующий nft set inet xray_transparent bypass4 и тот же список startup script. Перед изменением исходный root-owned script и JSON активного set сохранены в локальном /root/codex-ru-direct-before-* (0700). Проверены IPv4, права, сохранение прежних CIDR/redirect, идемпотентность формирования патча; bash -n и nft -c PASS. Запись атомарная, при её неудаче предусмотрен rollback добавленного элемента. Общий прокси не останавливался и не перезапускался; RU/DE конфигурации, ключи и тестовый клиент не менялись. FI/DK не затронуты.

Временный клиент Xray26.10.10 подключался к публичному RU443 обычным VLESS+Reality. Proxy env удалены у клиента и curl; SSH/dialerProxy в клиентском data path отсутствуют. SSH использован только для административного захвата на RU, без forwarding443. Оба запроса сначала PASS, затем отдельный свежий клиент повторил оба PASS: api.ipify.org видит DE_IP, API Яндекса RU_IP, curl exit0. На RU совпали 2 из2 префиксов ClientHello — SHA-256 первых76байт отправленного/принятого handshake; fallback «received real certificate» отсутствует. Прямой вход из текущей сети принят. Персистентный script после записи прошёл bash -n; перезагрузка этой машины/перезапуск общего прокси ради проверки не выполнялись.

Тестовая ссылка только /home/ochenstarik/srgfd/vpn_test_link.txt (0600), не ротировалась. При переносе проверить фактическое устройство/сеть семьи; до переноса FI не переустанавливать.

Доступ к панелям

Актуальные значения панели сохранены в защищённых panel_ru.env и panel_de.env; в report/Git/вывод команд их нет. Одноразовые параметры upstream-установщика, который внутри использует CLI-setting, аннулированы: логин/пароль и секретный path сменены штатным API без секретов в argv. Новый вход проверен. Проверка journal показала отсутствие актуального пароля и секретного path. Сам идентификатор пользователя 3x-ui записывает в штатный authentication audit; утверждать, что username нигде на VPS не встречается, нельзя. Аудит не отключался и не удалялся. Полный набор реквизитов сохраняется только в указанных env-файлах. Подробные готовые команды с приватными адресами/именем/SSH-портом и PuTTY-параметрами — /home/ochenstarik/srgfd/PANEL_HOWTO.txt (0600). SSH alias config — /home/ochenstarik/srgfd/ssh_config (0600).

Готовые команды из этой машины без публикации приватных адресов и значений из env:

# RU — оставить открытым в отдельном терминале:
PANEL_PORT="$(python3 -c 'from pathlib import Path; import shlex; print(dict((k,shlex.split(v)[0]) for k,v in (s.split("=",1) for s in Path("/home/ochenstarik/srgfd/panel_ru.env").read_text().splitlines()))["port"])')"
ssh -F /home/ochenstarik/srgfd/ssh_config -i ~/.ssh/kagent_vps_ed25519 -N -L "127.0.0.1:18053:127.0.0.1:$PANEL_PORT" ru-vpn
# DE — в другом терминале:
PANEL_PORT="$(python3 -c 'from pathlib import Path; import shlex; print(dict((k,shlex.split(v)[0]) for k,v in (s.split("=",1) for s in Path("/home/ochenstarik/srgfd/panel_de.env").read_text().splitlines()))["port"])')"
ssh -F /home/ochenstarik/srgfd/ssh_config -i ~/.ssh/kagent_vps_ed25519 -N -L "127.0.0.1:18054:127.0.0.1:$PANEL_PORT" de-vpn

PuTTY: SSH Auth → указать существующий .ppk владельца; Connection → SSH → Tunnels: source18053(RU)/18054(DE), destination 127.0.0.1:<PANEL_PORT из panel_*.env>, Local, Add. Адрес браузера: http://127.0.0.1:18053<path из panel_ru.env> либо http://127.0.0.1:18054<path из panel_de.env>. В HOWTO есть команда открытия URL через чтение env без печати секретного пути. Обе страницы входа реально проверены, не только описаны.

Снимки приёмки (значения доступов и panel port отредактированы)

RU

os_kernel, exit=0

Operating System: Ubuntu 24.04.5 LTS
          Kernel: Linux 6.8.0-100-generic

timezone, exit=0

Europe/Moscow

swap, exit=0

NAME      TYPE SIZE USED PRIO
/swapfile file   2G   0B   -2

sshd, exit=0

port <SSH_PORT>
permitrootlogin no
passwordauthentication no
kbdinteractiveauthentication no

ufw, exit=0

Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip

To                         Action      From
--                         ------      ----
<SSH_PORT>/tcp                  ALLOW IN    Anywhere                  
443/tcp                    ALLOW IN    Anywhere

ss, exit=0

127.0.0.53%lo:53 users:(("systemd-resolve",pid=500,fd=15))
127.0.0.1:2096 users:(("x-ui",pid=746,fd=19))
127.0.0.54:53 users:(("systemd-resolve",pid=500,fd=17))
127.0.0.1:<PANEL_PORT> users:(("x-ui",pid=746,fd=10))
0.0.0.0:<SSH_PORT> users:(("sshd",pid=754,fd=3),("systemd",pid=1,fd=90))
127.0.0.1:11111 users:(("xray-linux-amd6",pid=906,fd=7))
127.0.0.1:62789 users:(("xray-linux-amd6",pid=906,fd=3))
[::]:<SSH_PORT> users:(("sshd",pid=754,fd=4),("systemd",pid=1,fd=91))
*:443 users:(("xray-linux-amd6",pid=906,fd=6))

nft_tables, exit=0

table ip filter
table ip6 filter

services, exit=0

active
active

Panel DB (без path/credentials):

{
  "webListen": "127.0.0.1",
  "webPort": "<PANEL_PORT>",
  "subListen": "127.0.0.1",
  "subPort": "2096",
  "subEnable": "true"
}

DE

os_kernel, exit=0

Operating System: Ubuntu 24.04.5 LTS
          Kernel: Linux 6.8.0-147-generic

timezone, exit=0

Europe/Berlin

swap, exit=0

NAME      TYPE SIZE USED PRIO
/swapfile file 512M   0B   -2

sshd, exit=0

port <SSH_PORT>
permitrootlogin no
passwordauthentication no
kbdinteractiveauthentication no

ufw, exit=0

Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip

To                         Action      From
--                         ------      ----
<SSH_PORT>/tcp                  ALLOW IN    Anywhere                  
443/tcp                    ALLOW IN    Anywhere                  
24443/tcp                  ALLOW IN    <RU_IP>              # RU-DE Reality upstream

ss, exit=0

127.0.0.1:62789 users:(("xray-linux-amd6",pid=1023,fd=3))
0.0.0.0:<SSH_PORT> users:(("sshd",pid=792,fd=3),("systemd",pid=1,fd=87))
127.0.0.1:<PANEL_PORT> users:(("x-ui",pid=788,fd=10))
127.0.0.1:2096 users:(("x-ui",pid=788,fd=18))
127.0.0.54:53 users:(("systemd-resolve",pid=746,fd=17))
127.0.0.1:11111 users:(("xray-linux-amd6",pid=1023,fd=7))
127.0.0.53%lo:53 users:(("systemd-resolve",pid=746,fd=15))
[::]:<SSH_PORT> users:(("sshd",pid=792,fd=4),("systemd",pid=1,fd=88))
*:24443 users:(("xray-linux-amd6",pid=1023,fd=6))

nft_tables, exit=0

table ip filter
table ip6 filter

services, exit=0

active
active

Panel DB (без path/credentials):

{
  "webListen": "127.0.0.1",
  "webPort": "<PANEL_PORT>",
  "subListen": "127.0.0.1",
  "subPort": "2096",
  "subEnable": "true"
}

Границы результата и следующая приёмка

  • Прямой публичный вход из текущей сети и оба egress-направления PASS после локального исключения RU-IP. Проверка другой сети/устройства семьи и полный вход владельца своим приватным PuTTY-ключом остаются отдельными действиями.
  • Публичная панель, публичные подписки, Telegram-ноды, AI-агенты и WARP не включались. Новых дополнительных мониторов/автоматизаций нет; прежний тик30 не возобновлялся.
  • Для послеустановочного восстановления оставлены согласованные SQLite checkpoints и локальные initial/daily snapshots с проверенными checksum. Локальная копия не заменяет отдельное внешнее хранилище; offsite не включался.
  • Этот PR содержит только данный обезличенный отчёт. Code PR20 отдельный, автор не вливает. Прежний release gate для новых PR/документов без CI не обходится.

Дополнение 23.10.2026 — DE443 для домашней машины

Основание: актуальная заменяющая версия kagent/agents/claude/done/2026-10-23-fixes/CODEX-vps-de-close-443.md. Закрытие443 отменено. Эта работа — отдельный report-only PR поверх main 6f699607b079a57ea19765b19f781ef012d7de18, где PR20 и PR21 уже merged внешним участником. Итоговый main CI18/task7390 SUCCESS; промежуточный CI17/task7389 cancelled, зелёным не объявляется.

SSH использован только к de-vpn с ранее разрешённым операторским ключом и pinned known_hosts. RU/FI/DK по SSH не посещались, их конфигурации не менялись. Системный прокси/bypass этой машины не менялся; ключ владельца/исходные доступы не копировались и не читались дополнительно.

Через API приватной панели DE добавлен отдельный inbound home-server-de: VLESS+Reality TCP443, клиент home-server, Vision, самостоятельные private/public key и shortId, отличные от связки24443. Camouflage www.microsoft.com:443: TLS1.3 и проверка цепочки с DE PASS до создания. Ссылка записана только в /home/ochenstarik/srgfd/home_server_de_link.txt (0600), без вывода URI/UUID/ключей.

UFW443/tcp уже открыт для всех; правило и запись443 в managed ports оставлены. UFW user.rules и managed-ports файл побайтно не изменились. Профиль codex-ru-de-link24443, его разрешение только с RU_IP, outbounds и routing DE не менялись: сравнены API-настройки и native existing-inbound до/после. Новый вход добавлен горячим API без смены PID Xray и без ручного рестарта.

Перед изменением сохранены согласованная SQLite backup, native-config и UFW/managed файлы в закрытом root checkpoint codex-before-de-home-*. После — новая согласованная SQLite backup с integrity_check=ok, обе записи443/24443 на месте, и snapshot собранного панелью конфига (codex-after-de-home-*). API server/getConfigJson содержит оба inbound. Последний записанный native config.json на диске при hot-add ещё не содержит443; он не переписывался вручную. Рабочий443 подтверждён слушателем и реальными запросами, сохранение — БД и собранным конфигом; перезапуск DE ради этого теста не выполнялся.

Проверка Результат и предел
Новый home-server, временный Xray на DE → публичный DE443 PASS: api.ipify.org и icanhazip.com, curl0, фактический egress DE_IP
Новый home-server, прямой клиент с домашней машины Не выполнялся: DE_IP отсутствует в локальном bypass4. Самостоятельное добавление прямо запрещено этим заданием; проверка передана в отдельный CODEX-home-xray-via-ru.md
Прежняя связка RU→DE, обычный временный клиент на этой машине PASS: api.ipify.org egress DE_IP, российский API Яндекса egress RU_IP, оба curl0. Только клиентский трафик по прежней ссылке, без SSH/изменений RU
Сохранность24443 API/native profile, routing/outbounds и firewall неизменны; слушатель24443 активен

Временные клиенты работали на свободных loopback SOCKS-портах, proxy env удалены; SSH data forwarding не использовался. Self-test DE не подменяет приёмку внешнего домашнего пути. На домашнем системном прокси новая ссылка не установлена — это задача другого поручения при владельце.

DE: фактический вывод после добавления (доступы отредактированы)

ufw status verbose:

Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip

To                         Action      From
--                         ------      ----
<SSH_PORT>/tcp                  ALLOW IN    Anywhere
443/tcp                    ALLOW IN    Anywhere
24443/tcp                  ALLOW IN    <RU_IP>              # RU-DE Reality upstream

ss -ltnpH (расширенный ss -ltn, для проверки процесса):

LISTEN 0      4096       127.0.0.1:62789 0.0.0.0:* users:(("xray-linux-amd6",pid=1023,fd=3))
LISTEN 0      4096         0.0.0.0:<SSH_PORT> 0.0.0.0:* users:(("sshd",pid=792,fd=3),("systemd",pid=1,fd=153))
LISTEN 0      4096       127.0.0.1:<PANEL_PORT>  0.0.0.0:* users:(("x-ui",pid=788,fd=10))
LISTEN 0      4096       127.0.0.1:2096  0.0.0.0:* users:(("x-ui",pid=788,fd=18))
LISTEN 0      4096      127.0.0.54:53    0.0.0.0:* users:(("systemd-resolve",pid=746,fd=17))
LISTEN 0      4096       127.0.0.1:11111 0.0.0.0:* users:(("xray-linux-amd6",pid=1023,fd=7))
LISTEN 0      4096   127.0.0.53%lo:53    0.0.0.0:* users:(("systemd-resolve",pid=746,fd=15))
LISTEN 0      4096            [::]:<SSH_PORT>    [::]:* users:(("sshd",pid=792,fd=4),("systemd",pid=1,fd=154))
LISTEN 0      4096               *:443         *:* users:(("xray-linux-amd6",pid=1023,fd=9))
LISTEN 0      4096               *:24443       *:* users:(("xray-linux-amd6",pid=1023,fd=6))

Панель/подписки по-прежнему loopback. Новый report-only PR не содержит кода, конфигураций с ключами или самой ссылки; автоматический CI и действующий release-review gate сохраняются. Самослияние не выполняется.