Верхняя граница пароля была объявлена в 64 СИМВОЛА и обоснована пределом bcrypt в 72 БАЙТА. Обоснование верно только для ASCII: у 64 символов длина от 64 до 256 байт. golang.org/x/crypto@v0.55.0 (bcrypt.go:96) отвечает на пароль длиннее 72 байт ErrPasswordTooLong, а не «молча отбрасывает остаток», как утверждал комментарий, — так вела себя редакция пакета до v0.28. Следствие: пароль из 64 кириллических букв (128 байт) проходил панель, оркестратор и DTO, а отказ приходил из хеширования — системной ошибкой на штатной смене пароля, а при установке падением старта админки, то есть сервером без администратора после INSTALL EXIT CODE: 0. Хуже самого дефекта было то, что тест закреплял это значение как ожидаемое. Вместе с ним закрыты три соседних расхождения того же контракта. Пароль триммился вопреки собственному контракту. util.HashPassword вёл проверку len(strings.TrimSpace(password)) < 6, а bootstrap читал strings.TrimSpace(os.Getenv("HY2XS_ADMIN_INITIAL_PASSWORD")). Значение "abcde " принимали все двери продукта и не мог захешировать никто, а первая учётная запись создавалась не с тем паролем, который оператор записал в hy2xs.env. Панель считала длину в единицах UTF-16. Element Plus делегирует правила формы async-validator, а он сравнивает min/max с String.prototype.length: пароль из трёх эмодзи имел length 6, проходил минимум формы и получал отказ сервера, который панель не могла объяснить. hy2xs.env не был форматом. Значения писались интерполяцией, а читались split("=") с trim(); при этом файл читает не только оркестратор — он объявлен EnvironmentFile= в юните hy2xs-admin, и у незакавыченного значения systemd срезает краевые пробелы и трактует обратный слеш как escape. Что сделано: - контракт переехал в leaf-пакет apps/credential: его зовут util.HashPassword и dao, а service импортирует util — обратный импорт был бы циклическим, и именно поэтому HashPassword завёл собственную копию правила; - AdminPasswordMaxBytes = 72 объявлен отдельной константой и зеркально в оркестраторе и панели; сверяется тестами, читающими Go-исходник; - одно правило adminPassword вместо min=6,max=64 в тегах DTO (границу в байтах тегом валидатора не выразить) и код причины admin_password_format, называющий обе границы; - TrimSpace убран из хеширования и из bootstrap-пути; bootstrap проверяет контракт сам и падает с текстом, называющим переменную и файл; - панель считает code points и UTF-8 байты общим adminPasswordFormRule на обеих формах вместо встроенных min/max; - orchestrator/src/lib/envFile.ts — порт конечного автомата parse_env_file_internal из systemd и обратный ему кодировщик; экранируются только обратный слеш и двойная кавычка, оба из SHELL_NEED_ESCAPE. Обычные значения остаются без кавычек, поэтому релизные гейты не меняются. Тем же кодировщиком пишется bootstrap-admin.secret; - управляющие символы запрещены контрактом: формат KEY=VALUE их не несёт, а ввести такой пароль в форму входа всё равно нельзя; - отрицательная проба smoke сверяет конверт отказа (code 50000, invalid_credentials, отсутствие accessToken) вместо HTTP 200, а пароль генерирует, а не берёт из литерала; - положительная проба читает bootstrap-секрет парсером формата вместо grep | cut -d= -f2- с trim() — третьего по счёту слоя, срезавшего пробелы. Тесты: граничная таблица (36 x «я», 37 x «я», 18 и 19 эмодзи, 64 x «я», «abcde ») прогоняется в четырёх слоях; тест с 64 кириллическими буквами инвертирован; round-trip env-формата на значениях с кавычками, слешами и краевыми пробелами; bootstrap-путь на настоящей SQLite. 14 новых гейтов приёмки. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
34 KiB
Operations and troubleshooting
Цель документа
Зафиксировать минимальный operational контур после установки.
Что должен помнить оператор
0. Target prerequisites обязательны
На target-хосте install-flow сам обеспечивает системные зависимости (deps stage):
apt-get update
apt-get install -y sudo ca-certificates curl iproute2 tar openssl nftables systemd
sudo обязателен для smoke-проверок прав от имени runtime-пользователей (hysteria, hy2xs-admin), но его не нужно ставить вручную заранее: на clean-host он устанавливается на deps-стадии до smoke.
Важно: packaged baseline использует HY2XS_SSH_PORT=2323 по умолчанию. На target-хосте это значение обязательно нужно привести к фактическому рабочему SSH-порту оператора в /etc/hy2xs/hy2xs.env и применить через reconfigure --apply.
1. Builder и target — разные миры
Если нужно изменить состав install package, это делается в локальном builder layer, а не на target server.
2. UI приезжает из нашего пакета
Если проблема в UI, сначала смотреть:
- какой
HY2XS_ADMIN_SOURCE - какой
HY2XS_ADMIN_BUILD_ID - тот ли пакет вообще стоит на сервере
3. Hysteria приходит из upstream
Если проблема в ядре Hysteria, сначала смотреть:
- какую фактическую версию оркестратор установил
- что записано в
HY2_VERSION - не связано ли поведение со свежим upstream release
- какая версия Hysteria зафиксирована в metadata установленного пакета
Для обновления бинарника Hysteria2 используйте новый release install package. Изменение runtime env не обновляет бинарник Hysteria2.
4. Оркестратор — Bun/TypeScript, но target не билдит его
Если проблема в install flow, сначала смотреть:
- какой
ORCH_BUILD_ID - какой
ORCH_ENTRYPOINT - не подменён ли install package вручную
Базовые команды проверки
Проверка сервисов:
systemctl status hysteria-server
systemctl status hy2xs-admin
Проверка порта:
ss -uln
Проверка firewall:
nft list ruleset
Проверка post-install.env:
cat /etc/hysteria/post-install.env
Проверка логов через journald:
journalctl -u hysteria-server.service -n 100 --no-pager
journalctl -u hy2xs-admin.service -n 100 --no-pager
Источник логов в UI:
- Страница «Логи Hysteria» читает записи из journald unit
hysteria-server.service. - Экспорт «Логи Hysteria» также формируется из journald (
journalctl), а не из отдельного файлаhysteria2.log.
Проверка install-state marker:
cat /var/lib/hy2xs/install-state.json
Если reconfigure сообщает об отсутствии marker, нужно повторно выполнить чистый install и только потом применять runtime-изменения.
Auth endpoint fail checklist
systemctl status hysteria-server
systemctl status hy2xs-admin
sudo -u hy2xs-admin test -r /etc/hysteria/config.yaml
curl -sS -X POST \
-H 'Content-Type: application/json' \
--data '{"addr":"127.0.0.1:12345","auth":"invalid","tx":0}' \
http://127.0.0.1:8080/internal/hysteria/auth
curl -sS \
-H "Authorization: <trafficStatsSecret>" \
http://127.0.0.1:36712/online
Типовые проблемы
Установка отказывается: обнаружена предыдущая установка
Отказ происходит в PHASE 0, до любой мутации. Сервер остался в том
состоянии, в котором был: ни /usr/local/lib/hy2xs, ни
/var/lib/hy2xs/install-state.json, ни работающие службы не тронуты.
В тексте отказа перечислены конкретные найденные маркеры. Порядок действий —
14-legacy-cleanup.md: сохранить данные, посмотреть план
tools/legacy/purge-v0.sh, выполнить очистку, установить заново.
Проверить хост, ничего не устанавливая:
./orchestrator/hy2xs-orchestrator preflight-install --package-dir "$(pwd)"
reconfigure/repair отказываются: маркер чужого поколения
Маркер установки /var/lib/hy2xs/install-state.json не относится к текущему
поколению HY2XS.
installed: true сам по себе ничего не доказывает: такой же маркер мог
остаться от 0.x. Обе команды проверяют product, release_line и
config_schema_version.
Посмотреть, что видит оркестратор:
hy2xs-orchestrator status --package-dir /usr/local/lib/hy2xs/package \
| grep -o '"install_state_generation":"[^"]*"'
"current" — маркер текущего поколения; "foreign" — требуется чистая
переустановка; "absent" — установки нет.
Незавершённая установка текущего поколения
Если установка упала после начала применения изменений, полная очистка не нужна:
hy2xs-orchestrator repair \
--package-dir /usr/local/lib/hy2xs/package \
--config /etc/hy2xs/hy2xs.env \
--allow-partial-state
Флаг обязателен и осознан: без него repair работает только поверх полностью
успешной установки.
Операция отказывает: уже выполняется другая
another HY2XS operation is already in progress: reconfigure (pid 4242, started at …)
install, reconfigure, repair и doctor сериализованы замком
/run/lock/hy2xs-orchestrator.lock. Это не перестраховка: production paths —
/etc/hysteria/config.yaml, unit-файлы, /etc/nftables.conf,
/var/lib/hy2xs/install-state.json — общие, и две одновременные операции
записывают их поверх друг друга, после чего откат одной «восстанавливает»
состояние поверх изменений другой.
Отказ происходит до первой мутации, поэтому сервер не тронут. Что делать:
# кто держит замок
cat /run/lock/hy2xs-orchestrator.lock
# что делает держатель
ps -o pid,etime,cmd -p "$(sed -n 's/.*"pid": *\([0-9]*\).*/\1/p' /run/lock/hy2xs-orchestrator.lock)"
Дождитесь завершения. Замок снимается сам при любом завершении держателя,
включая Ctrl+C, SIGTERM и обрыв SSH, а мёртвого держателя следующая операция
обнаруживает и переиспользует замок самостоятельно.
Удалять файл руками нужно ровно в одном случае — если оркестратор сообщил, что содержимое замка не является корректной записью:
operation lock … exists but is not a valid HY2XS lock record
Такой замок сознательно не снимается автоматически: непонятый файл не доказывает, что операции нет.
status и diagnostics collect замок не берут и работают во время операции.
В отчёте status при этом появляется поле operation_in_progress — читайте
состояние как снимок незавершённой транзакции, а не как итог.
Операция отказывает: guard предыдущей операции ещё вооружён
previous HY2XS operation is no longer running, but its firewall rollback guard
is still armed: hy2xs-fw-rollback-<op-id>.timer (active/waiting)
Предыдущая операция умерла аварийно после применения firewall. Её процесса уже нет — замка может не быть тоже, — но rollback guard это отдельный объект systemd, и он переживает свой процесс. Если начать новую операцию сейчас, guard сработает посреди неё и вернёт firewall, существовавший до предыдущей операции.
Ничего делать не нужно, кроме как подождать: окно guard — 45 секунд с момента
применения firewall плюс точность таймера (AccuracySec=1s), то есть не больше
46 секунд.
# сколько ещё ждать и что именно висит
systemctl list-units --all --plain 'hy2xs-fw-rollback-*'
hy2xs-orchestrator status --package-dir /usr/local/lib/hy2xs/package
--plain здесь не для красоты: у юнита в состоянии failed systemctl печатает
первой колонкой маркер ●, и без флага его легко не заметить в списке.
Когда guard сработает, отработавший таймер выгрузится (RemainAfterElapse=no),
и операция пройдёт. Состояние failed у сервиса покою не мешает: оно означает,
что откат отработал не полностью, и это как раз повод запустить repair, а не
ждать дальше — подробности в journalctl -u 'hy2xs-fw-rollback-*'. Такой
failed-юнит остаётся загруженным до systemctl reset-failed, но операцию не
блокирует.
Операция отказывает: состояние guard'а не удалось выяснить
unable to verify firewall rollback guard state; systemd query failed,
refusing to start a lifecycle operation: systemctl list-units failed: …
Это не «guard вооружён», и ждать здесь нечего. Барьер обязан доказать, что у
предыдущей операции не осталось исполнителей, способных изменить firewall;
systemctl не ответил, доказательства нет, и операция отказывает до первой
мутации.
Отсутствие ответа не равно отсутствию guard'а: systemd мог быть жив, а взведённый таймер — существовать. Разрешить операцию в этой ситуации означало бы допустить срабатывание старого таймера поверх новой операции.
systemctl status
systemctl list-units --all --plain 'hy2xs-fw-rollback-*'
journalctl -u 'hy2xs-fw-rollback-*' --no-pager
Разбирайтесь с systemd/D-Bus и повторяйте операцию. Отдельно ускорять ничего не
нужно: systemd-run требуется в preflight, поэтому без работающего systemd
операция всё равно не прошла бы — барьер лишь сообщает об этом раньше и точнее.
Установка отказала с firewall_guard_fired
automatic firewall rollback has already fired
phase: firewall_guard_fired
Это означает: автоматический откат firewall сработал раньше, чем операция успела снять guard. Сервер жив и доступен, но работает на прежнем firewall, а не на том, который сгенерировала операция. Именно поэтому фиксация успеха запрещена, даже если smoke успел сойтись, — иначе сервер считался бы настроенным с чужими правилами, что особенно дорого при смене порта Hysteria, SSH или ACME.
Окно guard — 45 секунд (плюс точность таймера, AccuracySec=1s), и оно не
обязано покрывать smoke. Причину ищите в том, почему проход в него не уложился:
journalctl -u 'hy2xs-fw-rollback-*' --no-pager
journalctl -u hysteria-server -u hy2xs-admin --since '-10 min' --no-pager
Обычная причина — медленный старт одного из сервисов. После устранения root-cause операция запускается заново; откат уже вернул сервер в исходное состояние.
Сервер установился, но UI не работает
Проверить:
- разложился ли bundled UI
- корректен ли unit
hy2xs-admin - совпадает ли
HY2XS_ADMIN_INSTALL_DIRс реальностью - не сломан ли bind host / port
Admin UI access via SSH tunnel
Production-модель для UI: HY2XS_UI_BIND_HOST=127.0.0.1, внешний доступ к 8080/tcp не открывается.
Доступ оператора выполняется через SSH local forwarding.
Windows-команда туннеля:
ssh -p 2323 \
-i C:\Users\kirap\.ssh\id_ed25519_uk1 \
-N \
-L 127.0.0.1:8080:127.0.0.1:8080 \
root@185.156.108.141
После запуска открыть http://127.0.0.1:8080/#/login.
Если SSH-туннель не поднимается (administratively prohibited), проверить effective SSH policy:
sshd -T | grep -E '^(port|allowtcpforwarding|permitopen|gatewayports|passwordauthentication|permitrootlogin) '
Рекомендуемый фрагмент hardening sshd_config:
Port 2323
PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin prohibit-password
AllowTcpForwarding local
PermitOpen 127.0.0.1:8080 localhost:8080
GatewayPorts no
X11Forwarding no
AllowAgentForwarding no
MaxAuthTries 3
LoginGraceTime 20
ClientAliveInterval 300
ClientAliveCountMax 2
Hysteria скачалась, но не стартует
Проверить:
- валиден ли config
- совпадают ли listen port и firewall rule
- домен / SNI / TLS policy
- реальную установленную версию Hysteria
Тестовый клиент не подключается
Проверить:
server_name- порт
obfs.password- auth material
- что используется совместимый клиентский конфиг
Ни один пир не проходит авторизацию
Симптом резкий: подключения перестают устанавливаться у всех сразу, в журнале
админки — device limit unavailable.
Лимит устройств проверяется fail-closed: без ответа /online админка не
знает, сколько устройств уже на связи, и пускать подключения не имеет права.
Значит вопрос ровно один — почему недоступен Traffic Stats API.
# 1. что записано в конфиге
grep -A2 '^trafficStats:' /etc/hysteria/config.yaml
# 2. отвечает ли API по этому адресу
curl -sS -H "Authorization: <trafficStatsSecret>" http://127.0.0.1:36712/online
# 3. что говорит сама админка
journalctl -u hy2xs-admin -n 100 --no-pager | grep -i 'traffic stats'
Частая причина — правка trafficStats.listen руками. Админка обращается к
Traffic Stats API только по loopback, поэтому адрес вроде 192.168.1.10
разводит Hysteria и панель по разным адресам: сама Hysteria работает, туннели
существующих клиентов живут, но лимит устройств, учёт трафика и принудительное
отключение выключаются разом. С таким конфигом админка отказывает явно:
trafficStats.listen слушает 192.168.1.10, а админка обращается к Traffic Stats
API только по loopback. ...Верните 127.0.0.1 через `hy2xs-orchestrator reconfigure`
Страница конфигурации показывает тот же адрес и называет его состояние. Ответов три, и они означают разное:
| адрес | что показано | что это значит |
|---|---|---|
127.0.0.1:36712 |
без пометки | канон production-профиля |
0.0.0.0:36712, :36712 |
предупреждение | API достижим, но опубликован на всех интерфейсах; при HY2XS_FIREWALL_MODE=external|off его не прикрывает ничто |
127.0.0.5:36712 |
ошибка | недостижим, см. ниже |
192.168.1.10:36712 |
ошибка | панель до него не достучится, доступ пиров уже не работает |
Две детали, на которых легко ошибиться:
-
пустой хост в
listen— это не loopback: в Go:36712означает все интерфейсы, ровно как0.0.0.0; -
другой адрес loopback — это не «почти правильно». Слушатель на конкретном адресе принимает соединения только на него:
bind 127.0.0.5:36712 → dial 127.0.0.1:36712 → connection refusedАдминка обращается к Traffic Stats API строго через
127.0.0.1, поэтому127.0.0.5ломает контур доступа так же, как LAN-адрес.
Дашборд показывает «состояние службы неизвестно»
Это не «Hysteria остановлена». Значение означает, что не удалось получить
ответ systemctl is-active hysteria-server: сломанный или недоступный systemctl
при живой Hysteria выглядит именно так.
Проверяется отдельно от туннеля:
systemctl is-active hysteria-server # active | inactive | failed | ...
Доступность Traffic Stats API на дашборде — независимый факт, полученный фактическим обращением к API. Сочетание «состояние неизвестно» + «API доступен» означает исправно работающий туннель и сломанную диагностику службы; сочетание «служба активна» + «API недоступен» — предыдущий раздел.
Install/reconfigure падает на DNS AAAA
Проверить значение HY2XS_DNS_AAAA_POLICY в /etc/hy2xs/hy2xs.env:
strict(default): AAAA приводит к fail в IPv4-only профиле;warn: warning + продолжение;off: AAAA-check отключён.
Для production baseline рекомендуется strict.
DNS IPv4 mismatch: DNS ведёт не на этот сервер
Сообщение выглядит так:
DNS IPv4 mismatch for HY2XS_PUBLIC_HOST fi.api.withen.pro:
DNS A records: 185.xxx.xxx.10
server public IPv4: 185.xxx.xxx.27
Update the DNS A record before using this server.
Это не ложное срабатывание, а именно то, ради чего проверка сделана: сервисы на машине живы, но публичный endpoint ведёт куда-то ещё. Чаще всего — после принудительной смены IPv4 провайдером.
Что делать:
- сверить фактический адрес сервера:
ip -4 addr show scope global; - обновить A-запись у DNS-провайдера;
- дождаться истечения TTL;
- повторить
hy2xs-orchestrator doctor.
doctor безопасно запускать на работающем сервере: он не перезапускает
сервисы и живые соединения не рвёт. Раньше это было не так — команда звала
общий smoke, который начинается с systemctl restart hysteria-server hy2xs-admin, и диагностика подозрения на проблему сама создавала обрыв у всех
подключённых клиентов.
Безопасность здесь — инвариант рантайма, а не свойство текущего кода. doctor
целиком выполняется под тем же read-only guard, что и PHASE 0 установки: любая
запись в файл и любой мутирующий вызов под ним отказывают. Раньше от рестарта
защищал один принудительный флаг, а остальные проверки smoke — чтение прав,
владельцев и синтаксиса nftables — выполнялись мутирующими раннерами, поэтому
настоящая мутация, случайно добавленная в smoke, была бы разрешена молча.
При этом диагностика не сужается: слушатели, healthz, права на файлы, machine
auth, trafficStats, версия бинаря, семантика /etc/hysteria/config.yaml и
синтаксис nft проверяются полностью.
Где проходит граница read-only
Guard действует внутри процесса оркестратора. Он не способен запретить побочный эффект, который вызвал бы HTTP-запрос в другом процессе, поэтому эта половина границы держится не им, а составом проб.
Существенный случай — machine-auth. Успешная авторизация пира заставляет админку
выполнить UPDATE peer.last_connection_at, то есть диагностика изменила бы
отображаемое «последнее подключение» у bootstrap-admin-peer. Поэтому проба с
действующим паролем выполняется только в режиме install; doctor работает
в режиме reconfigure и до неё не доходит. Полный happy-path авторизации
проверяют установка и E2E, а не диагностика.
doctor отправляет только пробы, которые заведомо не проходят авторизацию
(отсутствующий machine token, неверные учётные данные, некорректный тип поля) и
читающие запросы (/healthz, trafficStats /online). Ни одна из них не
изменяет данные.
Честная формулировка гарантии:
doctorне изменяет конфигурацию, состояние сервисов, firewall и данные.
Единственный след, который он оставляет, — записи в журнале админки: пробы проходят через обычный обработчик логирования, как любой запрос. Это не состояние системы, но и не «совсем ничего», поэтому сказано прямо.
Вариант server public IPv4: пустой означает, что на интерфейсах нет ни одного
публичного маршрутизируемого IPv4 — сервер за NAT. Это топология вне baseline;
осознанное решение оформляется через HY2XS_PUBLIC_ENDPOINT_POLICY=warn.
Если в A-записях присутствует правильный адрес и посторонний, проверка тоже отказывает. HY2XS — single-host профиль: второй backend за тем же именем означает, что часть клиентов попадёт не на этот сервер.
Скорость не соответствует ожиданиям
Проверить:
bandwidth.*на сервере- клиентские
up_mbps/down_mbps - нет ли ложного ожидания, что один только host BBR решает speed policy
Изменили post-install.env, но runtime не изменился
Это ожидаемо.
post-install.env — reference file, а не autoreconcile engine.
Редактировать нужно /etc/hy2xs/hy2xs.env и затем запускать reconfigure --dry-run/--apply.
Изменили bootstrap-поля, но пароль admin не сменился
Это ожидаемо.
HY2XS_ADMIN_INITIAL_PASSWORD и HY2XS_ADMIN_CON_PASS используются только как bootstrap-данные при первичной установке.
Для ротации существующих credentials нужен отдельный flow на уровне account-management.
hy2xs-admin не стартует: «HY2XS_ADMIN_INITIAL_PASSWORD не задан»
Означает, что учётной записи администратора в базе нет, а переменной, из которой её положено создать, — тоже.
Придумывать пароль самостоятельно админка не будет: такой пароль не знал бы никто, кроме журнала, а раньше именно он туда и попадал открытым текстом. Сообщение говорит о повреждённом контракте запуска.
Что проверять:
systemctl cat hy2xs-admin | grep EnvironmentFile
grep -c '^HY2XS_ADMIN_INITIAL_PASSWORD=' /etc/hy2xs/hy2xs.env
grep -c '^ADMIN_INITIAL_PASSWORD=' /etc/hy2xs/bootstrap-admin.secret
Починка — hy2xs-orchestrator repair --allow-partial-state: значения принадлежат
оркестратору, он же приводит hy2xs.env и bootstrap-admin.secret в
согласованное состояние.
hy2xs-admin не стартует: «HY2XS_ADMIN_INITIAL_PASSWORD не удовлетворяет контракту панели»
Значение задано, но панель его не приняла бы на форме входа, поэтому учётная запись администратора с ним не создаётся: установка иначе завершилась бы успешно, а войти было бы нельзя.
Контракт пароля — две границы в разных единицах и один запрет:
| Требование | Кто его ставит |
|---|---|
| 6-64 символа Unicode | форма входа и форма смены пароля |
| не более 72 байт в UTF-8 | bcrypt (ErrPasswordTooLong) |
| без управляющих символов | формат KEY=VALUE, который читает systemd |
Границы независимы: у 64 символов длина от 64 до 256 байт. Пароль из 64 кириллических букв — это 128 байт, и он отвергается, хотя в границу символов укладывается. Практический предел: 36 кириллических букв или 18 эмодзи.
Набор символов не ограничен ничем сверх этого, а пробелы по краям являются
частью пароля. Именно поэтому такое значение записывается в hy2xs.env в
двойных кавычках:
HY2XS_ADMIN_INITIAL_PASSWORD="пароль с пробелом на конце "
Без кавычек пробелы по краям срежет systemd — файл объявлен
EnvironmentFile= в юните, — и админка получит не то значение, которое вы
записали.
Починка: исправьте значение в /etc/hy2xs/hy2xs.env и выполните
hy2xs-orchestrator repair --allow-partial-state.
Как посмотреть bootstrap-пароль
/etc/hy2xs/bootstrap-admin.secret — файл того же формата KEY=VALUE, и
значения в нём могут быть закавычены. Читать их cut -d= -f2- нельзя: кавычки
уедут в пароль. source и eval тоже не годятся — shell выполнит подстановку
команд внутри двойных кавычек, чего сам systemd не делает.
read_bootstrap_field() {
sudo sed -n "s/^$1=//p" /etc/hy2xs/bootstrap-admin.secret | head -n1 \
| sed -e 's/^"//' -e 's/"$//' -e 's/\\\(["\\]\)/\1/g'
}
read_bootstrap_field ADMIN_USER
read_bootstrap_field ADMIN_INITIAL_PASSWORD
Аналогичное сообщение про HY2XS_ADMIN_CON_PASS относится к пиру установщика.
Его секрет продублирован в bootstrap-admin.secret, откуда его читает проверка
machine-auth, поэтому придуманный секрет разошёлся бы с файлом и первая же
проверка подключения провалилась бы.
Забыт пароль администратора
systemctl stop hy2xs-admin
set -a; . /etc/hy2xs/hy2xs.env; set +a
"$HY2XS_INSTALL_DIR/hy2xs-admin" reset-admin
systemctl start hy2xs-admin
Runtime env подключается намеренно: из него берутся пути к базе и журналу
(HY2XS_DATA_DIR, HY2XS_LOG_DIR) — те же, с которыми работает юнит.
Команда печатает новые логин и пароль в консоль и требует смены пароля при первом входе. Работает поверх существующей установки; на машине без базы она осмысленно откажет — это инструмент восстановления, а не установки.
Автоматический сброс трафика не срабатывает
Проверьте сохранённое расписание:
journalctl -u hy2xs-admin | grep RESET_TRAFFIC_CRON
Невалидное выражение теперь отклоняется API до записи в базу, поэтому попасть в
это состояние можно только правкой базы в обход продукта. Планировщик в таком
случае поднимается без джобы сброса и пишет ERROR — старт сервиса при этом не
прерывается намеренно: на панели висит /internal/hysteria/auth, и её отказ
положил бы подключения пользователей.
Починка — сохранить корректное значение в разделе настроек панели; оно применяется сразу, без перезапуска сервиса. Пустое значение — легальное и означает «автоматический сброс выключен».
Правила эксплуатации
- Не править сервер как будто на нём есть builder.
- Не считать bundled UI источником install-policy.
- Не считать
post-install.envавтоматическим механизмом применения изменений. - Не расширять install-only baseline до lifecycle-manager без отдельного проектного решения.
- Не смешивать install baseline и access/bot platform в одной документации.
- Не включать IPv6 в runtime-политике HY2XS (проект IPv4-only).