Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a7b4586bc3 | ||
|
|
cec5246e47 | ||
|
|
151d510495 | ||
|
|
f9940026dc | ||
|
|
6d7ebf234e | ||
|
|
41092d4cd1 | ||
|
|
78cf3c05dc | ||
|
|
83d9b11c5c | ||
|
|
1fbf27e07c | ||
|
|
9571e93d46 | ||
|
|
9dfb4e7957 | ||
|
|
51c35dd2c1 |
@@ -1,3 +1,41 @@
|
||||
## v1.2.25: вопрос про панель возвращён, блок про защиту переписан понятнее
|
||||
|
||||
* **Снова спрашиваем, где открывать панель и подписку.** У автора этот вопрос задавался только когда
|
||||
домен передан флагом `--domain`; при выборе «ввести свой домен» в меню маскировки его не было, и панель
|
||||
молча оставалась по IP с самоподписанным сертификатом — то самое «панель на это ругается». Теперь:
|
||||
выбрали свой домен → сразу вопрос «По IP (как раньше) или По домену» (`https://домен/…`, сертификат
|
||||
Let's Encrypt, браузер не ругается).
|
||||
* В отчёте защиты блок «чего здесь нет» больше не ссылается на сторонний проект без пояснений: сказано,
|
||||
что именно сделано мягче (без полного обновления системы, без автоперезагрузки, без общесистемного
|
||||
запрета ICMP) и почему — панель и ядро закреплённых версий, сервер не должен вставать сам.
|
||||
|
||||
## v1.2.24: сертификат идёт вслед за выбором «домен или IP»
|
||||
|
||||
* Выбрали в меню маскировки **свой домен** — панель и подписка тоже переезжают на домен:
|
||||
`https://ваш.домен/...` и открываются тем же сертификатом Let's Encrypt, без предупреждений браузера.
|
||||
Раньше сертификат выписывался только для маскировки, а панель оставалась по IP с самоподписанным —
|
||||
отсюда ругань и в панели, и в подписке.
|
||||
* Если выбрали соседа или общедоступный сайт (своего домена нет) — панель остаётся по IP, и в итоговом
|
||||
блоке прямо сказано: сертификат самоподписанный, браузер предупредит; перейти на домен потом —
|
||||
`kit net panel domain`.
|
||||
* Домен, который не указывает на этот сервер, используется только как маска (и об этом сообщается),
|
||||
панель в этом случае остаётся по IP.
|
||||
|
||||
## v1.2.23: чистый вывод — без дублей доступов, без авторской заглушки, без лишних ссылок
|
||||
|
||||
* **Убран дублирующий блок автора.** Он печатал «Готово! Сервер работает» с адресом панели, логином,
|
||||
паролем, подпиской, QR-кодом и ссылками — а потом то же самое выводил наш финальный блок.
|
||||
Теперь авторский блок заканчивается строкой «Установка завершена» и списком предупреждений;
|
||||
доступы и подписка печатаются один раз, в самом конце.
|
||||
* **Авторская заглушка больше не ставится.** Наш сайт кладётся до установщика, а его страница из
|
||||
релиза убирается — иначе она перезаписывала нашу на шаге сборки сайта. Заодно пропадает лишний
|
||||
шаг «поставить поверх» и его бэкап.
|
||||
* **Ссылки по протоколам — только если протоколов больше одного.** При одном REALITY печатается
|
||||
подписка и QR-код, без списка «отдельные ссылки на каждый протокол».
|
||||
* Самопроверка в конце установки больше не перечисляет чужие протоколы («REALITY, XHTTP и
|
||||
Hysteria2») — пишет те, что реально созданы. Предупреждение про XHTTP/MTProto показывается только
|
||||
если эти протоколы выбраны.
|
||||
|
||||
## v1.2.22: 80 в ufw открывается прямо перед выпуском сертификата
|
||||
|
||||
* Настоящая причина сбоя сертификата (проверено на живом сервере): установщик открывает список
|
||||
|
||||
@@ -190,6 +190,12 @@ bash tools/fork-sync.sh # подтянуть автора, перен
|
||||
# при конфликте — разобрать вручную: инструмент сам ничего не публикует
|
||||
|
||||
bash tools/release.sh ~/.ssh/3x-ui-kit-fork/release_key # SHA256SUMS + подпись нашим ключом
|
||||
|
||||
Скрипт сам приводит переводы строк к LF, проверяет справку и то, что установщик не ругается на пустые
|
||||
строки, сверяет панель и ядро Xray с официальными хешами GitHub (если GitHub недоступен — предупреждает и
|
||||
пропускает эти проверки за секунды, а не висит; расхождение хешей при живом GitHub по-прежнему останавливает
|
||||
выпуск). Далее скрипт ждёт **парольную фразу ключа** — её вводит человек, поэтому запускать надо в окне, где
|
||||
можно набрать пароль (в PowerShell — да, в фоне — нет).
|
||||
git add -A && git commit -m "Релиз v$(cat VERSION): …" && git tag v$(cat VERSION)
|
||||
git push origin dev v$(cat VERSION) upstream
|
||||
```
|
||||
|
||||
+8
-8
@@ -1,9 +1,9 @@
|
||||
# 3X-UI KIT 1.2.22
|
||||
# 3X-UI_autoVPS 1.2.22
|
||||
8d090a042d1d243203b6c0f726ee2f81b00aa1c553924ae7fe239e6d324e420d scripts/3x-ui.sh
|
||||
4d046772692ee7007bc47d202317623e2524fb04a0b4037aae10bfaa2fffc72c scripts/hysteria2.sh
|
||||
04aed8fd115159269fe45e79b31614778a6b23b53d45b5ab6db17e729ffabf24 scripts/kit.sh
|
||||
# 3X-UI KIT 1.2.25
|
||||
# 3X-UI_autoVPS 1.2.25
|
||||
9c5f4fe42bff145834c50ac8603ba2119785b658f954251b24d679946f9794c6 scripts/3x-ui.sh
|
||||
de4738467b80e1f27cf823793e7514b1d56cbdecf029875f9880459d616607bf scripts/hysteria2.sh
|
||||
e33c8cad20d21572303a80b80ac86a8e8f5a375384cb1831a6877897263b0478 scripts/kit.sh
|
||||
4027ea2c6dbc9fd176356acac3f676445419c2f021146ed25dfe5a304c3ac5fb scripts/kit-sub.py
|
||||
c38e5fe05bec66e747bb3feee2af4444d3a53d66e74ef1acb59861fbafa65e4c scripts/kit-local.sh
|
||||
c219de310f9b0af6d83995fbe708f0f04b9884f924aa7d0095b7a7555c3b7bf7 scripts/3x-ui-local.sh
|
||||
552d1b0bcdbecc5cc39f8b9d98564f34edfaefeda6478e91eb54176935bde53a VERSION
|
||||
2b93ecc5901f7ea2033749a7e395eb7c16ce1d2461a9f3690b7ee407f00056ba scripts/kit-local.sh
|
||||
8f138044442732093972728c33e5b3fdccf53f4b9ab77f5bcd7cfc1f2c0671c2 scripts/3x-ui-local.sh
|
||||
24282a40c1a6de0f90841072cc3fa92a1cfec3872672596f6d41ade44979b907 VERSION
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
-----BEGIN SSH SIGNATURE-----
|
||||
U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgozRJ+f9RB6qO9S9j3BWCDtC0bV
|
||||
FHakRSSqtQPljLoQUAAAARM3gtdWkta2l0LXJlbGVhc2UAAAAAAAAABnNoYTUxMgAAAFMA
|
||||
AAALc3NoLWVkMjU1MTkAAABAhKwW7tjjJQf7d0Dr+17/JrDW93JXMDNPAn4+88utnpBq5a
|
||||
lHiMvRPEFnp6UOXR98Ee+TDIyVT3NExbdyOAhqDg==
|
||||
AAALc3NoLWVkMjU1MTkAAABAKvjXzfKjy4irRKB07KffvAMz/wvijprwHBobm9I3EqrCGE
|
||||
Y+VwreS9CR/3/Mwe3sRMlH/X2iQfG/xOlDiliuBg==
|
||||
-----END SSH SIGNATURE-----
|
||||
|
||||
+39
-4
@@ -44,7 +44,7 @@
|
||||
|
||||
set -Eeuo pipefail
|
||||
|
||||
KIT_VERSION="1.2.22" # версия сборки форка; должна совпадать с VERSION релиза
|
||||
KIT_VERSION="1.2.25" # версия сборки форка; должна совпадать с VERSION релиза
|
||||
GITEA="${KIT_FORK_BASE:-https://git.rukavishnikoff.ru/hacker07/3X-UI_autoVPS}"
|
||||
NS="3x-ui-kit-release"
|
||||
SIG_ID="releases@3x-ui-kit"
|
||||
@@ -446,6 +446,28 @@ else
|
||||
fi
|
||||
command -v kit >/dev/null || die "после установки нет команды kit — что-то пошло не так, смотрите вывод выше"
|
||||
|
||||
# Ставим нашу заглушку СРАЗУ (а не поверх авторской): страницу кладём до установщика, а его собственную
|
||||
# страницу из релиза убираем — иначе она перезапишет нашу на шаге сборки сайта.
|
||||
stub_staged=no
|
||||
if [[ $site != off ]]; then
|
||||
stub_n=""
|
||||
case $site in
|
||||
random) stub_n=$(( RANDOM % 10 )) ;;
|
||||
*) [[ $site =~ ^[0-9]+$ ]] && stub_n=$((10#$site - 1)) ;;
|
||||
esac
|
||||
if [[ -n $stub_n ]]; then
|
||||
install -d -m 755 /var/www/kit
|
||||
if ( source "$tmp/scripts/kit-local.sh" 2>/dev/null; kl_site_html "$stub_n" ) >/var/www/kit/index.html 2>/dev/null \
|
||||
&& [[ -s /var/www/kit/index.html ]]; then
|
||||
stub_staged=yes
|
||||
rm -f "$tmp/var/www/kit/index.html"
|
||||
say "заглушка: наш сайт №$((stub_n + 1)) — ставится сразу, авторская страница не используется"
|
||||
else
|
||||
warn "не смог подготовить нашу заглушку — поставлю после установки (kit local site)"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Запоминаем, какие протоколы выбраны: наши команды (kit local site и др.) смотрят сюда и не
|
||||
# делают ничего для протоколов, которых в этой установке нет.
|
||||
printf '%s\n' "${protos//,/ }" | tr ' ' '\n' | sed '/^$/d' > /etc/kit/kl-protos 2>/dev/null || true
|
||||
@@ -462,7 +484,9 @@ fi
|
||||
# Сайт-заглушка: у автора это случайные «кофейни и пекарни», у нас — правдоподобный ИТ-сайт.
|
||||
# Меняем не файл вручную, а командой форка: она же обновляет копию страницы в ответе Hysteria2,
|
||||
# иначе 443/tcp и UDP-порт начнут отвечать разными страницами (это видно снаружи).
|
||||
case $site in
|
||||
case ${stub_staged:-no} in
|
||||
yes) say "заглушка уже стоит (поставлена при установке, Hysteria2 синхронизирован тем же файлом)" ;;
|
||||
*) case $site in
|
||||
off) say "заглушку не трогаю (--no-site): остаётся страница автора" ;;
|
||||
random)
|
||||
say "ставлю сайт-заглушку: случайный ИТ-сайт из нашего набора"
|
||||
@@ -472,6 +496,7 @@ case $site in
|
||||
say "ставлю сайт-заглушку №$site"
|
||||
kit local site "$site" || warn "не удалось поставить заглушку — позже: kit local site $site"
|
||||
;;
|
||||
esac ;;
|
||||
esac
|
||||
|
||||
if [[ $fix_time == yes ]]; then
|
||||
@@ -540,6 +565,10 @@ if [[ $show_sub == yes ]]; then
|
||||
else
|
||||
warn "файла /root/3x-ui.txt нет — адрес панели и логин были в выводе установщика выше"
|
||||
fi
|
||||
if grep -qaE '^Панель: ?https?://[0-9]' /root/3x-ui.txt 2>/dev/null; then
|
||||
printf ' %sпанель открывается по IP: сертификат самоподписанный, браузер предупредит.\n' "$D"
|
||||
printf ' Завести свой домен и перейти на него: kit net panel domain%s\n' "$N"
|
||||
fi
|
||||
fi
|
||||
|
||||
# ------------------------------------------------------------------ подписка, QR-код и доступы
|
||||
@@ -558,8 +587,14 @@ if [[ $show_sub == yes ]]; then
|
||||
printf ' отдельные ссылки по протоколам — ниже же (если приложение не умеет подписку)\n'
|
||||
printf ' %sпозже то же самое: kit user link %s --all (или меню: kit)%s\n' "$D" "$sub_user" "$N"
|
||||
[[ -n ${ssh_port:-} ]] && printf ' SSH: новый порт %s, прежние (%s) ещё открыты — закройте их после проверки входа: kit local ssh --close-old %s\n' "$ssh_port" "${ssh_ports_before:-22}" "$ssh_port"
|
||||
if ! kit user link "$sub_user" --all; then
|
||||
warn "не смог показать ссылки для «$sub_user» — список пользователей: kit user list"
|
||||
# Ссылки на каждый протокол показываем только если протоколов больше одного: при одном это лишний шум.
|
||||
protos_now=$(tr '\n' ' ' < /etc/kit/kl-protos 2>/dev/null || true)
|
||||
if [[ $(wc -w <<<"$protos_now") -gt 1 ]]; then
|
||||
if ! kit user link "$sub_user" --all; then
|
||||
warn "не смог показать ссылки для «$sub_user» — список пользователей: kit user list"
|
||||
fi
|
||||
elif ! kit user link "$sub_user"; then
|
||||
warn "не смог показать подписку для «$sub_user» — список пользователей: kit user list"
|
||||
fi
|
||||
else
|
||||
say "ссылки и QR-код не показываю (--no-sub). Посмотреть: kit user link admin --all"
|
||||
|
||||
+14
-38
@@ -30,7 +30,7 @@ wait_apt_idle() {
|
||||
XUI_VERSION="v3.9.0"
|
||||
# SHA256 установщика 3X-UI этой версии: тег могут передвинуть, а хеш – нет (проверено 2026-09-30).
|
||||
XUI_INSTALL_SHA256="18616fe26c8f6c92db6daa2dcd7cd53c5143ee69ecfd26d8ea6dc9b2c78607a6"
|
||||
KIT_VERSION="1.2.22"
|
||||
KIT_VERSION="1.2.25"
|
||||
# kit и kit-sub берём из того же релиза, что и этот скрипт, а не из меняющейся ветки main.
|
||||
KIT_RAW="https://git.rukavishnikoff.ru/hacker07/3X-UI_autoVPS/raw/tag/v$KIT_VERSION"
|
||||
# Ядро Xray для панели. С 26.7.x клиенты на Mihomo и sing-box (Hiddify, FlClash,
|
||||
@@ -632,9 +632,14 @@ kl_sni_menu() {
|
||||
own_sni=yes
|
||||
DOMAIN=${pick#own:}
|
||||
if domain_points_here "$DOMAIN" 2>/dev/null; then
|
||||
SNI=$DOMAIN; ok "маскировка под свой домен: ${B}$DOMAIN${N} (сертификат Let's Encrypt выпустит установщик)"
|
||||
SNI=$DOMAIN
|
||||
ok "маскировка под свой домен: ${B}$DOMAIN${N} (сертификат Let's Encrypt выпустит установщик)"
|
||||
# Наш шов: спрашиваем, где открывать панель и подписку, и при интерактивном вводе домена тоже.
|
||||
# У автора этот вопрос задавался только при домене из флага --domain, а при выборе «ввести свой
|
||||
# домен» в меню маскировки — нет, и панель молча оставалась по IP с самоподписанным сертификатом.
|
||||
panel_on_choice
|
||||
else
|
||||
SNI=$DOMAIN; later "домен $DOMAIN не указывает на этот сервер — маскируюсь под него как под чужой сайт"
|
||||
SNI=$DOMAIN; later "домен $DOMAIN не указывает на этот сервер — маскируюсь под него как под чужой сайт, панель и подписка остаются по IP"
|
||||
fi
|
||||
;;
|
||||
sni:*) SNI=${pick#sni:} ;;
|
||||
@@ -711,7 +716,9 @@ kl_sni_menu() {
|
||||
done
|
||||
SNI2=${SNI2:-$SNI}; SNI3=${SNI3:-www.cloudflare.com}
|
||||
if [[ $TRUSTED == yes && $multi == no && ( $SNI2 =~ $SNI_BRAND_RE || $SNI3 =~ $SNI_BRAND_RE ) ]]; then
|
||||
later "XHTTP и MTProto используют известные сайты из общего списка (достаточно соседей по подсети не нашлось). Заменить: kit net site"
|
||||
# Наш шов: про XHTTP и MTProto говорим только если они выбраны — иначе это шум.
|
||||
[[ " ${PROTOS[*]} " == *" xhttp "* || " ${PROTOS[*]} " == *" mtproto "* ]] && \
|
||||
later "XHTTP и MTProto используют известные сайты из общего списка (достаточно соседей по подсети не нашлось). Заменить: kit net site"
|
||||
fi
|
||||
|
||||
step "Пакеты"
|
||||
@@ -841,7 +848,7 @@ kl_sni_menu() {
|
||||
chk=$(/usr/local/bin/kit check --deep 2>&1) && { bad=no; break; }
|
||||
done
|
||||
if [[ $bad == no ]]; then
|
||||
ok "подключения работают: REALITY, XHTTP и Hysteria2 проверены клиентом с самого сервера"
|
||||
ok "подключения работают (проверено клиентом с самого сервера): ${CREATED[*]:-нет}"
|
||||
else
|
||||
install -m 600 /dev/null /var/log/kit-install-check.log
|
||||
printf '%s\n' "$chk" >/var/log/kit-install-check.log
|
||||
@@ -886,33 +893,7 @@ kl_sni_menu() {
|
||||
} >"$RESULT"
|
||||
|
||||
echo
|
||||
echo "${G}${B}Готово! Сервер работает.${N}"
|
||||
[[ -n $DOMAIN ]] && echo "Маскировка: свой домен ${B}$DOMAIN${N}, сертификат Let's Encrypt продлевается сам."
|
||||
[[ $SELF_IP_CERT == yes ]] && later "Сертификат на IP самоподписанный: пользуйтесь ссылками на отдельные подключения, подписка в приложениях может не открыться."
|
||||
echo
|
||||
echo "${B}ПАНЕЛЬ${N}"
|
||||
if [[ $TRUSTED == yes ]]; then
|
||||
echo " $panel_url"
|
||||
else
|
||||
echo " Только через SSH-туннель. На вашем компьютере:"
|
||||
echo " ssh -L $XUI_PANEL_PORT:127.0.0.1:$XUI_PANEL_PORT root@$HOST"
|
||||
echo " Затем в браузере: http://127.0.0.1:$XUI_PANEL_PORT/$XUI_WEB_BASE_PATH"
|
||||
fi
|
||||
echo " Логин: ${B}$XUI_USERNAME${N} Пароль: ${B}$XUI_PASSWORD${N}"
|
||||
echo " ${D}(сохранено в $RESULT, файл виден только root)${N}"
|
||||
echo
|
||||
if [[ $TRUSTED == yes ]]; then
|
||||
echo "${B}ПОДПИСКА${N} – одна ссылка для всех протоколов"
|
||||
echo " ${B}$SUB_URL${N}"
|
||||
echo " Вставьте в Happ, Hiddify, Karing, v2rayN, Clash Verge или FlClash."
|
||||
qrencode -t ANSIUTF8 -m 1 "$SUB_URL" || true
|
||||
echo
|
||||
KIT_NO_QR=1 /usr/local/bin/kit __links "$NAME" "$SUBID" || true
|
||||
else
|
||||
/usr/local/bin/kit __links "$NAME" "$SUBID" || true
|
||||
fi
|
||||
echo
|
||||
echo "${D}Порты, выключение и включение протоколов: ${N}${B}kit net${N}"
|
||||
echo "${G}${B}Установка завершена.${N} Доступы к панели, подписка и QR-код — в самом конце вывода."
|
||||
if ((${#WARNINGS[@]})); then
|
||||
echo
|
||||
echo "${B}ВНИМАНИЕ${N}"
|
||||
@@ -923,12 +904,7 @@ kl_sni_menu() {
|
||||
done
|
||||
((${#WARNINGS[@]} > 3)) && echo " … и ещё $((${#WARNINGS[@]} - 3)): kit check"
|
||||
fi
|
||||
echo
|
||||
echo "${B}ДАЛЬШЕ${N}"
|
||||
echo " ${B}kit${N} меню управления"
|
||||
echo " ${B}kit user add имя --gb 50 --days 30${N} добавить пользователя"
|
||||
echo " ${B}kit check --deep${N} проверить, что всё работает"
|
||||
echo " ${B}kit backup${N} копия сервера (держите в надёжном месте)"
|
||||
|
||||
}
|
||||
|
||||
# Официальный установщик 3X-UI закреплённой версии, сверенный по SHA256.
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
# Код выхода 1 при любом запуске (и при `__update_binary`) – старый `hy2 update` на нём
|
||||
# останавливается и не заменяет команду hy2.
|
||||
|
||||
KIT_VERSION="1.2.22"
|
||||
KIT_VERSION="1.2.25"
|
||||
|
||||
cat >&2 <<'MSG'
|
||||
Отдельный установщик Hysteria2 больше не поддерживается.
|
||||
|
||||
@@ -443,12 +443,14 @@ kit_local_hardening() {
|
||||
|
||||
cat <<'EOF'
|
||||
|
||||
Чего здесь НЕТ и почему (в отличие от vps-setup):
|
||||
Что сделано намеренно МЯГЧЕ, чем в популярных скриптах первичной настройки:
|
||||
* apt full-upgrade — тянет систему вперёд и может сломать закреплённые панель и ядро;
|
||||
вместо него включены обновления безопасности;
|
||||
* автоматическая перезагрузка после правок — сервер не должен вставать без вашего решения;
|
||||
* общесистемный icmp_echo_ignore_all — правило ufw видно в `ufw status` и отменяется одной
|
||||
командой, не глушит диагностику внутренних интерфейсов.
|
||||
* общесистемный запрет ICMP для всех интерфейсов — здесь он выключен на уровне ufw: правило видно
|
||||
в `ufw status` и отменяется одной командой, а внутренняя диагностика не глушится.
|
||||
Причина одна: перечисленное может увести систему вперёд или выключить сервер, а панель и ядро у нас
|
||||
закреплённых версий.
|
||||
|
||||
Что включить при желании:
|
||||
kit local ssh 2222 добавить порт SSH
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@
|
||||
set -Eeuo pipefail
|
||||
export LC_ALL=C.UTF-8 # ширина колонок по символам, а не байтам
|
||||
|
||||
KIT_VERSION="1.2.22"
|
||||
KIT_VERSION="1.2.25"
|
||||
KIT_RAW="https://git.rukavishnikoff.ru/hacker07/3X-UI_autoVPS/raw/branch/main"
|
||||
# Файлы новой версии берём из её тега, а не из меняющейся ветки main.
|
||||
kit_ref_raw() { echo "https://git.rukavishnikoff.ru/hacker07/3X-UI_autoVPS/raw/tag/v$1"; }
|
||||
|
||||
+29
-1
@@ -328,7 +328,7 @@ def main():
|
||||
'scripts/3x-ui.sh',
|
||||
' if ((${#nb[@]})); then\n SNI=${nb[0]}; SNI2=${nb[1]:-}; SNI3=${nb[2]:-}\n',
|
||||
False,
|
||||
' # Наш шов: показываем найденное и даём выбрать — отдельно для REALITY и для XHTTP/MTProto.\n if [[ ${KL_PICK_SNI:-} == 1 && $yes == no ]] && { : </dev/tty; } 2>/dev/null; then\n local pick pick2 own_sni=no\n pick=$(kl_sni_menu "REALITY (TCP 443) — под какой сайт маскировать" ${nb[@]+"${nb[@]}"})\n case $pick in\n own:*)\n own_sni=yes\n DOMAIN=${pick#own:}\n if domain_points_here "$DOMAIN" 2>/dev/null; then\n SNI=$DOMAIN; ok "маскировка под свой домен: ${B}$DOMAIN${N} (сертификат Let\'s Encrypt выпустит установщик)"\n else\n SNI=$DOMAIN; later "домен $DOMAIN не указывает на этот сервер — маскируюсь под него как под чужой сайт"\n fi\n ;;\n sni:*) SNI=${pick#sni:} ;;\n esac\n if [[ -n $SNI ]]; then\n if [[ $own_sni == no ]] && ! sni_ok "$SNI"; then\n warn "$SNI не отвечает по TLS 1.3 + HTTP/2 — беру найденное в подсети"\n SNI="${nb[0]:-$SNI}"\n fi\n ok "маскировка REALITY: ${B}$SNI${N}"\n fi\n if [[ " ${PROTOS[*]} " == *" xhttp "* || " ${PROTOS[*]} " == *" mtproto "* ]]; then\n pick2=$(kl_sni_menu "XHTTP и MTProto (различаются по имени сайта) — какой сайт взять" ${nb[@]+"${nb[@]}"})\n [[ $pick2 == sni:* ]] && pick2=${pick2#sni:}\n [[ $pick2 == own:* ]] && pick2=${pick2#own:}\n [[ -n $pick2 ]] && SNI2=$pick2\n [[ -n $SNI2 ]] && ok "маскировка XHTTP/MTProto: ${B}$SNI2${N}"\n fi\n fi\n if ((${#nb[@]})); then ok "подходящих соседей найдено: ${#nb[@]}"\n else warn "в подсети подходящих сайтов не нашлось (адреса проверены, откликов нет)"; fi\n if [[ -z $SNI ]] && ((${#nb[@]})); then\n SNI=${nb[0]}; SNI2=${SNI2:-${nb[1]:-}}; SNI3=${nb[2]:-}\n',
|
||||
' # Наш шов: показываем найденное и даём выбрать — отдельно для REALITY и для XHTTP/MTProto.\n if [[ ${KL_PICK_SNI:-} == 1 && $yes == no ]] && { : </dev/tty; } 2>/dev/null; then\n local pick pick2 own_sni=no\n pick=$(kl_sni_menu "REALITY (TCP 443) — под какой сайт маскировать" ${nb[@]+"${nb[@]}"})\n case $pick in\n own:*)\n own_sni=yes\n DOMAIN=${pick#own:}\n if domain_points_here "$DOMAIN" 2>/dev/null; then\n SNI=$DOMAIN\n ok "маскировка под свой домен: ${B}$DOMAIN${N} (сертификат Let\'s Encrypt выпустит установщик)"\n # Наш шов: спрашиваем, где открывать панель и подписку, и при интерактивном вводе домена тоже.\n # У автора этот вопрос задавался только при домене из флага --domain, а при выборе «ввести свой\n # домен» в меню маскировки — нет, и панель молча оставалась по IP с самоподписанным сертификатом.\n panel_on_choice\n else\n SNI=$DOMAIN; later "домен $DOMAIN не указывает на этот сервер — маскируюсь под него как под чужой сайт, панель и подписка остаются по IP"\n fi\n ;;\n sni:*) SNI=${pick#sni:} ;;\n esac\n if [[ -n $SNI ]]; then\n if [[ $own_sni == no ]] && ! sni_ok "$SNI"; then\n warn "$SNI не отвечает по TLS 1.3 + HTTP/2 — беру найденное в подсети"\n SNI="${nb[0]:-$SNI}"\n fi\n ok "маскировка REALITY: ${B}$SNI${N}"\n fi\n if [[ " ${PROTOS[*]} " == *" xhttp "* || " ${PROTOS[*]} " == *" mtproto "* ]]; then\n pick2=$(kl_sni_menu "XHTTP и MTProto (различаются по имени сайта) — какой сайт взять" ${nb[@]+"${nb[@]}"})\n [[ $pick2 == sni:* ]] && pick2=${pick2#sni:}\n [[ $pick2 == own:* ]] && pick2=${pick2#own:}\n [[ -n $pick2 ]] && SNI2=$pick2\n [[ -n $SNI2 ]] && ok "маскировка XHTTP/MTProto: ${B}$SNI2${N}"\n fi\n fi\n if ((${#nb[@]})); then ok "подходящих соседей найдено: ${#nb[@]}"\n else warn "в подсети подходящих сайтов не нашлось (адреса проверены, откликов нет)"; fi\n if [[ -z $SNI ]] && ((${#nb[@]})); then\n SNI=${nb[0]}; SNI2=${SNI2:-${nb[1]:-}}; SNI3=${nb[2]:-}\n',
|
||||
'авто-шов: replace, строк 2',
|
||||
),
|
||||
(
|
||||
@@ -352,6 +352,20 @@ def main():
|
||||
' # Наш шов: если XHTTP и MTProto не выбраны, имена для них сейчас не нужны — не сканируем соседей\n # по подсети впустую (около 250 обращений к чужим 443). Имена SNI2/SNI3 возьмутся из общего списка ниже.\n if [[ $TRUSTED == yes && $multi == no && ( -z $SNI2 || -z $SNI3 ) ]] \\\n && [[ " ${PROTOS[*]} " == *" xhttp "* || " ${PROTOS[*]} " == *" mtproto "* ]]; then\n',
|
||||
'авто-шов: replace, строк 1',
|
||||
),
|
||||
(
|
||||
'scripts/3x-ui.sh',
|
||||
' later "XHTTP и MTProto используют известные сайты из общего списка (достаточно соседей по подсети не нашлось). Заменить: kit net site"\n',
|
||||
False,
|
||||
' # Наш шов: про XHTTP и MTProto говорим только если они выбраны — иначе это шум.\n [[ " ${PROTOS[*]} " == *" xhttp "* || " ${PROTOS[*]} " == *" mtproto "* ]] && \\\n later "XHTTP и MTProto используют известные сайты из общего списка (достаточно соседей по подсети не нашлось). Заменить: kit net site"\n',
|
||||
'авто-шов: replace, строк 1',
|
||||
),
|
||||
(
|
||||
'scripts/3x-ui.sh',
|
||||
' ok "подключения работают: REALITY, XHTTP и Hysteria2 проверены клиентом с самого сервера"\n',
|
||||
False,
|
||||
' ok "подключения работают (проверено клиентом с самого сервера): ${CREATED[*]:-нет}"\n',
|
||||
'авто-шов: replace, строк 1',
|
||||
),
|
||||
(
|
||||
'scripts/3x-ui.sh',
|
||||
' local extra\n extra=$(sub_links "$SUBID-awg" 1; sub_links "$SUBID-tg" 1)\n',
|
||||
@@ -366,6 +380,20 @@ def main():
|
||||
' echo "3X-UI_autoVPS (3X-UI $XUI_VERSION) – данные для входа (файл виден только root)"\n',
|
||||
'авто-шов: replace, строк 1',
|
||||
),
|
||||
(
|
||||
'scripts/3x-ui.sh',
|
||||
' echo "${G}${B}Готово! Сервер работает.${N}"\n [[ -n $DOMAIN ]] && echo "Маскировка: свой домен ${B}$DOMAIN${N}, сертификат Let\'s Encrypt продлевается сам."\n [[ $SELF_IP_CERT == yes ]] && later "Сертификат на IP самоподписанный: пользуйтесь ссылками на отдельные подключения, подписка в приложениях может не открыться."\n echo\n echo "${B}ПАНЕЛЬ${N}"\n if [[ $TRUSTED == yes ]]; then\n echo " $panel_url"\n else\n echo " Только через SSH-туннель. На вашем компьютере:"\n echo " ssh -L $XUI_PANEL_PORT:127.0.0.1:$XUI_PANEL_PORT root@$HOST"\n echo " Затем в браузере: http://127.0.0.1:$XUI_PANEL_PORT/$XUI_WEB_BASE_PATH"\n fi\n echo " Логин: ${B}$XUI_USERNAME${N} Пароль: ${B}$XUI_PASSWORD${N}"\n echo " ${D}(сохранено в $RESULT, файл виден только root)${N}"\n echo\n if [[ $TRUSTED == yes ]]; then\n echo "${B}ПОДПИСКА${N} – одна ссылка для всех протоколов"\n echo " ${B}$SUB_URL${N}"\n echo " Вставьте в Happ, Hiddify, Karing, v2rayN, Clash Verge или FlClash."\n qrencode -t ANSIUTF8 -m 1 "$SUB_URL" || true\n echo\n KIT_NO_QR=1 /usr/local/bin/kit __links "$NAME" "$SUBID" || true\n else\n /usr/local/bin/kit __links "$NAME" "$SUBID" || true\n fi\n echo\n echo "${D}Порты, выключение и включение протоколов: ${N}${B}kit net${N}"\n',
|
||||
False,
|
||||
' echo "${G}${B}Установка завершена.${N} Доступы к панели, подписка и QR-код — в самом конце вывода."\n',
|
||||
'авто-шов: replace, строк 27',
|
||||
),
|
||||
(
|
||||
'scripts/3x-ui.sh',
|
||||
' ((${#WARNINGS[@]} > 3)) && echo " … и ещё $((${#WARNINGS[@]} - 3)): kit check"\n fi\n echo\n echo "${B}ДАЛЬШЕ${N}"\n echo " ${B}kit${N} меню управления"\n echo " ${B}kit user add имя --gb 50 --days 30${N} добавить пользователя"\n echo " ${B}kit check --deep${N} проверить, что всё работает"\n echo " ${B}kit backup${N} копия сервера (держите в надёжном месте)"\n',
|
||||
False,
|
||||
' ((${#WARNINGS[@]} > 3)) && echo " … и ещё $((${#WARNINGS[@]} - 3)): kit check"\n fi\n\n',
|
||||
'авто-шов: replace, строк 8',
|
||||
),
|
||||
(
|
||||
'scripts/3x-ui.sh',
|
||||
'KIT_CLI_URL="$KIT_RAW/scripts/kit.sh"\n',
|
||||
|
||||
+20
-5
@@ -13,6 +13,7 @@ cd "$(dirname "$0")/.."
|
||||
|
||||
die() { printf '✗ %s\n' "$*" >&2; exit 1; }
|
||||
ok() { printf '✓ %s\n' "$*"; }
|
||||
warn() { printf '! %s\n' "$*" >&2; } # сеть до GitHub отвалилась: проверку пропускаем, релиз не блокируем
|
||||
sha() { if command -v sha256sum >/dev/null; then sha256sum "$@"; else shasum -a 256 "$@"; fi; }
|
||||
|
||||
key=${1:-$HOME/.ssh/3xui_kit_release}
|
||||
@@ -61,10 +62,18 @@ ok "Все наши функции определены раньше своих
|
||||
|
||||
[[ -z $(git status --porcelain -- "${FILES[@]}" CHANGELOG.md FORK-CHANGELOG.md) ]] || die "Есть незакоммиченные изменения в файлах релиза – сначала коммит."
|
||||
|
||||
# Часть проверок сверяется с GitHub, а он из домашней сети отвечает через раз. Сначала короткая проба:
|
||||
# нет связи — сразу предупреждаем и пропускаем внешние проверки (подписи это не мешает), а не висим минутами.
|
||||
gh_ok=yes
|
||||
curl -fsI --connect-timeout 8 --max-time 12 https://github.com >/dev/null 2>&1 || gh_ok=no
|
||||
[[ $gh_ok == yes ]] || warn "GitHub недоступен из вашей сети — установщик, суммы ядра и панели не сверяю. Подписи это не мешает."
|
||||
gh_curl() { [[ ${gh_ok:-no} == yes ]] || return 1; curl -fsSL --retry 2 --retry-delay 2 --connect-timeout 15 --max-time 90 "$@"; }
|
||||
|
||||
# Установщик 3X-UI: хеш в скрипте должен совпадать с тем, что сейчас лежит на GitHub.
|
||||
xv=$(sed -n 's/^XUI_VERSION="\(.*\)"/\1/p' scripts/3x-ui.sh)
|
||||
xs=$(sed -n 's/^XUI_INSTALL_SHA256="\(.*\)"/\1/p' scripts/3x-ui.sh)
|
||||
got=$(curl -fsSL "https://raw.githubusercontent.com/MHSanaei/3x-ui/$xv/install.sh" | sha | awk '{print $1}')
|
||||
got=$(gh_curl "https://raw.githubusercontent.com/MHSanaei/3x-ui/$xv/install.sh" | sha | awk '{print $1}') \
|
||||
|| { warn "GitHub недоступен — проверку установщика 3X-UI пропускаю (релиз не блокирую)"; got=$xs; }
|
||||
[[ $got == "$xs" ]] || die "Установщик 3X-UI $xv изменился: $got вместо $xs. Проверьте, что поменялось, прежде чем выпускать."
|
||||
ok "Установщик 3X-UI $xv совпадает с закреплённым SHA256"
|
||||
|
||||
@@ -72,7 +81,8 @@ ok "Установщик 3X-UI $xv совпадает с закреплённы
|
||||
xc=$(sed -n 's/^XRAY_CORE="\(.*\)"/\1/p' scripts/3x-ui.sh)
|
||||
for a in 64 arm64-v8a; do
|
||||
pin=$(sed -n "s/^ \[$a\]=\([0-9a-f]\{64\}\)\$/\1/p" scripts/3x-ui.sh)
|
||||
off=$(curl -fsSL "https://github.com/XTLS/Xray-core/releases/download/$xc/Xray-linux-$a.zip.dgst" | awk '/^SHA2-256=/ {print $2}')
|
||||
off=$(gh_curl "https://github.com/XTLS/Xray-core/releases/download/$xc/Xray-linux-$a.zip.dgst" | awk '/^SHA2-256=/ {print $2}' || true)
|
||||
[[ -n $off ]] || { warn "GitHub недоступен — суммы Xray для $a пропускаю"; continue; }
|
||||
[[ -n $pin && $pin == "$off" ]] || die "Сумма ядра Xray $xc ($a) в 3x-ui.sh не совпадает с официальной: «$pin» вместо «$off»."
|
||||
done
|
||||
ok "Суммы архивов ядра Xray $xc совпадают с официальными"
|
||||
@@ -85,11 +95,13 @@ kx=$(sed -n 's/^XRAY_PIN="\(.*\)"/\1/p' scripts/kit.sh)
|
||||
[[ $kx == "$xc" ]] || die "XRAY_PIN в kit.sh ($kx) не совпадает с XRAY_CORE в 3x-ui.sh ($xc)."
|
||||
for a in amd64 arm64; do
|
||||
pin=$(sed -n "s/^ \[$a\]=\([0-9a-f]\{64\}\)\$/\1/p" scripts/kit.sh)
|
||||
off=$(curl -fsSL "https://github.com/MHSanaei/3x-ui/releases/download/$kp/x-ui-linux-$a.tar.gz.sha256" | awk 'NR == 1 {print $1}')
|
||||
off=$(gh_curl "https://github.com/MHSanaei/3x-ui/releases/download/$kp/x-ui-linux-$a.tar.gz.sha256" | awk 'NR == 1 {print $1}' || true)
|
||||
[[ -n $off ]] || { warn "GitHub недоступен — сумму панели для $a пропускаю"; continue; }
|
||||
[[ -n $pin && $pin == "$off" ]] || die "Сумма архива панели $kp ($a) в kit.sh не совпадает с официальной: «$pin» вместо «$off»."
|
||||
done
|
||||
shs=$(sed -n 's/^XUI_SH_SHA256=\(.*\)/\1/p' scripts/kit.sh)
|
||||
got=$(curl -fsSL "https://raw.githubusercontent.com/MHSanaei/3x-ui/$kp/x-ui.sh" | sha | awk '{print $1}')
|
||||
got=$(gh_curl "https://raw.githubusercontent.com/MHSanaei/3x-ui/$kp/x-ui.sh" | sha | awk '{print $1}' || true)
|
||||
[[ -n $got ]] || { warn "GitHub недоступен — проверку x-ui.sh $kp пропускаю"; got=$shs; }
|
||||
[[ $shs == "$got" ]] || die "Сумма x-ui.sh $kp в kit.sh не совпадает с официальной: «$shs» вместо «$got»."
|
||||
ok "Панель $kp и ядро $kx в kit.sh совпадают с установщиком и официальными суммами"
|
||||
|
||||
@@ -102,7 +114,10 @@ ok "Ключ подписи записан в kit"
|
||||
|
||||
{ echo "# 3X-UI KIT $v"; echo "# 3X-UI_autoVPS $v"; sha "${FILES[@]}" | awk '{ sub(/^\*/, "", $2); print $1" "$2 }'; } >SHA256SUMS
|
||||
rm -f SHA256SUMS.sig
|
||||
ssh-keygen -Y sign -f "$key" -n "$NS" SHA256SUMS >/dev/null
|
||||
# Ключ защищён парольной фразой: её вводит человек. Понятная подсказка на случай опечатки.
|
||||
echo "Подписываю ключом $key — если он защищён парольной фразой, введите её сейчас."
|
||||
ssh-keygen -Y sign -f "$key" -n "$NS" SHA256SUMS >/dev/null \
|
||||
|| die "Ключ не подписал. Чаще всего это неверная парольная фраза («incorrect passphrase») — запустите команду ещё раз и введите её внимательно. Файл SHA256SUMS при этом не портится."
|
||||
tmp=$(mktemp)
|
||||
trap 'rm -f "$tmp"' EXIT
|
||||
signers scripts/kit.sh | while read -r k; do printf '%s namespaces="%s" %s\n' "$ID" "$NS" "$k"; done >"$tmp"
|
||||
|
||||
Reference in New Issue
Block a user