Compare commits

...
7 Commits
11 changed files with 281 additions and 17 deletions
+33
View File
@@ -3,6 +3,39 @@
Здесь записи о наших версиях. Файл автора (`CHANGELOG.md`) мы не трогаем — так обновления
автора не конфликтуют с нашими записями.
## v1.2.5: суммы релиза в формате, который понимает kit
* Исправлена ошибка нашего релизного конвейера: на Windows `sha256sum` пишет суммы как
`hash *файл`, а `kit` на сервере сверяет имя строго (`$2 == "файл"`) — то есть `kit update`
отклонил бы релизы v1.2.1–v1.2.4 как «в подписанном списке нет такого файла». Теперь
`tools/release.sh` приводит список к POSIX-виду (`hash файл`) **до** подписи.
* `scripts/3x-ui-local.sh` принимает оба формата, чтобы не спотыкаться о суммы, собранные на
другой машине.
* Проверка теперь повторяет логику самого `kit`: подпись `SHA256SUMS` + строгая сверка имени
каждого файла из подписанного списка (а не только `sha256sum -c`, который звёздочку прощает).
## v1.2.4: проверка релиза отдельной командой
* Флаг `--verify-only`: скачать релиз, проверить подпись `SHA256SUMS` и SHA256 установщика и выйти —
можно проверить канал на сервере, ничего не устанавливая.
* Порядок шагов изменён: проверка подписи теперь идёт до предполётных проверок и до любых
изменений на сервере, чтобы чужой код не запускался раньше проверки.
## v1.2.3: установка одной командой (`scripts/3x-ui-local.sh`)
* Один скрипт на чистом VPS: проверка сервера → скачивание нашего релиза → проверка подписи
`SHA256SUMS` и SHA256 самого установщика → установщик автора (панель 3X-UI, протоколы,
сайт-заглушка, маскировка, сертификат, подписка, ufw) → наши дополнения → проверка.
* По умолчанию досыпает: закрыть ответ на ping (правилом ufw), включить обновления безопасности,
`kit fix` (время и безопасные починки), в конце `kit check` и сводку `kit local hardening`.
Отключается флагами `--no-harden`, `--no-time`, `--no-check`.
* Второй порт SSH — только по явному флагу `--ssh-port N`: прежний порт продолжает работать,
закрытие — отдельным шагом `kit local ssh --close-old N`. Автоматически доступ не запираем.
* Все флаги установщика автора (`--domain`, `--sni`, `--panel-on`, `--host`, `--restore` …)
передаются как есть; есть `--dry-run` (план без изменений) и `--help`.
* Публичный ключ форка вшит в обёртку — подпись проверяется до запуска чужого кода; при смене
ключа обновляется и здесь, и в `kit`.
## v1.2.2: команды защиты сервера (поведение из StressOzz/vps-setup)
* Новые команды `kit local`: `ssh <порт>` (добавить порт SSH), `ssh --close-old` (закрыть прежние
+24 -1
View File
@@ -44,7 +44,19 @@ git push origin dev v$(cat VERSION) upstream
## Установка и обновление из этого репозитория
```bash
# установка на чистый сервер (вместо команды автора с GitHub)
# установка одной командой: наш релиз, подпись проверяется до запуска установщика,
# в конце — закрытие ping, автообновления безопасности, kit fix и kit check
bash <(curl -fsSL https://git.rukavishnikoff.ru/hacker07/3X-UI_autoVPS/raw/branch/main/scripts/3x-ui-local.sh) --domain vpn.example.com
# «а что вы вообще собираетесь запускать?» — проверка подписи релиза без установки
bash <(curl -fsSL …/scripts/3x-ui-local.sh) --verify-only
# план установки без изменений
bash <(curl -fsSL …/scripts/3x-ui-local.sh) --dry-run --domain vpn.example.com
# то же, но без защиты (--no-harden) и с добавлением второго порта SSH
bash <(curl -fsSL …/scripts/3x-ui-local.sh) --sni dl.google.com --no-harden --ssh-port 2222
# только установщик автора, без наших дополнений
bash <(curl -fsSL https://git.rukavishnikoff.ru/hacker07/3X-UI_autoVPS/raw/branch/main/scripts/3x-ui.sh)
# обновление уже стоящего сервера (тянет наш релиз и проверяет нашу подпись)
@@ -69,8 +81,19 @@ kit local help # справка по дополнениям форка
kit local version # версия, источник обновлений, дата сборки нашего файла
kit local channel # откуда берутся обновления и чем проверяется подпись
kit local seams # какие швы форка сейчас в установленном /usr/local/bin/kit
kit local masking # состояние маскировки
kit local hardening # сводка по защите сервера
# защита сервера (поведение из StressOzz/vps-setup, сделано безопаснее)
kit local ssh 2222 # добавить порт SSH (прежние продолжают работать)
kit local ssh --close-old 2222 # закрыть прежние порты после проверки
kit local ping off # не отвечать на ping (правилом ufw)
kit local upgrades on # автообновления безопасности
kit local passwd --generate # сменить пароль root и показать его один раз
```
У любой правки можно добавить `--dry-run` — покажет план и ничего не изменит.
## Грабли, о которых стоит помнить
1. **Ночное автообновление** (`kit-update.timer`, 03:00) перезаписывает `/usr/local/bin/kit`
+8 -7
View File
@@ -1,7 +1,8 @@
# 3X-UI KIT 1.2.2
04c26623f7e4782435a6d0c398adc1d141b5ffa0102f6288f338e2c5e327c96f *scripts/3x-ui.sh
ce648a971b9ab076cb9dfd597d141630a012b3ad22a3d2e77cfdcf20cafba3a9 *scripts/hysteria2.sh
46ae6f47841755998936cbf87f3303012f0a24baef903130b4da55b35713aded *scripts/kit.sh
eac3e47491ce86487f05160952ff5b4ad8a3821954f082eee3516e40575fb574 *scripts/kit-sub.py
30579dfae24239d1c797dc8efac5b2b49116bc05058923df184b382f33fe265b *scripts/kit-local.sh
c62a5cc61ac4525935753f5ec284c0a052a4b1da4b3a3580dce2b7d77a2154ae *VERSION
# 3X-UI KIT 1.2.5
c8d91ed459b4ba249166ab26361fa759ad6bdafe30158ee2cfaf3e0818e7644d scripts/3x-ui.sh
e402fb8b1e98df934f86b40eaf700696d142a43d6e761e8beacd8fc3a4c9e396 scripts/hysteria2.sh
235e314bfc6603622e259e45819ecc03422dcb5fd18666f4d839b24f626d2a26 scripts/kit.sh
eac3e47491ce86487f05160952ff5b4ad8a3821954f082eee3516e40575fb574 scripts/kit-sub.py
30579dfae24239d1c797dc8efac5b2b49116bc05058923df184b382f33fe265b scripts/kit-local.sh
40c8612011a72f4b5f1f754b593c51b5d2bff547a0e9fca2602f3d3fbd1923f9 scripts/3x-ui-local.sh
fe2b7c237b5a6e42818aa3e4f7fc5820f49c32289c32c96260ef89a8c8f6d3d7 VERSION
+2 -2
View File
@@ -1,6 +1,6 @@
-----BEGIN SSH SIGNATURE-----
U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgozRJ+f9RB6qO9S9j3BWCDtC0bV
FHakRSSqtQPljLoQUAAAARM3gtdWkta2l0LXJlbGVhc2UAAAAAAAAABnNoYTUxMgAAAFMA
AAALc3NoLWVkMjU1MTkAAABAXepKsKLK3Qne0igKGaPh3hw28rSW9P+kYu4pHE0EtmvPc4
Fe2fMJxQDA7QQSvAVvf4BVVV3f+AtReU963tmYDw==
AAALc3NoLWVkMjU1MTkAAABAh7WjPC1qvJKsop5cPtRaLQQCNUe/jmQp4Ox/1dqqlsT6Ke
NmQAWSSoHRyhUTKJaMgnYwojd7w/zFeSg4USqLDQ==
-----END SSH SIGNATURE-----
+1 -1
View File
@@ -1 +1 @@
1.2.2
1.2.5
+200
View File
@@ -0,0 +1,200 @@
#!/usr/bin/env bash
# 3X-UI KIT (форк hacker07) — установка сервера одной командой из нашего канала.
#
# Что делает (по шагам):
# 1) проверяет, что мы на чистом Debian/Ubuntu и под root, и что есть curl, ssh-keygen, openssl;
# 2) берёт из нашего Gitea релиз своей же версии, проверяет ПОДПИСЬ SHA256SUMS и SHA256 установщика;
# 3) запускает установщик автора (scripts/3x-ui.sh) — панель 3X-UI, протоколы, сайт-заглушка,
# маскировка, сертификат, подписка, ufw; все обычные флаги установщика можно передавать как есть;
# 4) досыпает то, чего у автора нет (поведение из StressOzz/vps-setup, но безопаснее):
# ответ на ping закрывается правилом ufw, включаются обновления безопасности;
# 5) при желании добавляет второй порт SSH (--ssh-port 2222) — прежний остаётся рабочим;
# 6) в конце: kit fix (время и безопасные починки), kit check, kit local hardening.
#
# Запуск (примеры):
# bash <(curl -fsSL https://git.rukavishnikoff.ru/hacker07/3X-UI_autoVPS/raw/tag/v1.2.3/scripts/3x-ui-local.sh) --domain vpn.example.com
# ... 3x-ui-local.sh --sni dl.google.com --harden
# ... 3x-ui-local.sh --ssh-port 2222 --no-harden
#
# Флаги самого обёрточного скрипта (остальные уходят установщику автора):
# --no-harden не отключать ping и не включать автообновления безопасности
# --ssh-port N добавить порт SSH N (прежний порт продолжает работать)
# --no-time не запускать kit fix (синхронизация времени и безопасные починки)
# --no-check не запускать в конце kit check
# --dry-run показать план и ничего не делать
# -h | --help эта справка
#
# Наш файл: авторские релизы его не перезаписывают, а правки форка живут в scripts/kit-local.sh.
set -Eeuo pipefail
KIT_VERSION="1.2.5" # версия сборки форка; должна совпадать с VERSION релиза
GITEA="${KIT_FORK_BASE:-https://git.rukavishnikoff.ru/hacker07/3X-UI_autoVPS}"
NS="3x-ui-kit-release"
SIG_ID="releases@3x-ui-kit"
# Публичный ключ форка. Меняется только вместе с ключом подписи (тогда обновляется и здесь, и в kit).
SIGNER_PUB='ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKM0Sfn/UQeqjvUvY9wVgg7QtG1RR2pEUkqrUD5Yy6EF 3X-UI KIT fork releases (hacker07)'
G=$'\e[32m'; Y=$'\e[33m'; R=$'\e[31m'; B=$'\e[1m'; D=$'\e[2m'; N=$'\e[0m'
[[ -t 1 ]] || { G=; Y=; R=; B=; D=; N=; }
say() { printf '%s\n' "${G}==>${N} $*"; }
warn() { printf '%s\n' "${Y}!${N} $*" >&2; }
die() { printf '%s\n' "${R}✗${N} $*" >&2; exit 1; }
usage() {
cat <<'EOF'
3X-UI KIT (форк hacker07) — установка сервера одной командой из нашего канала.
bash <(curl -fsSL <наш Gitea>/raw/tag/v<версия>/scripts/3x-ui-local.sh) [флаги…]
Всё, что скрипт не знает сам, он передаёт установщику автора как есть:
--domain vpn.example.com свой домен для маскировки (A-запись на этот сервер, свободный 80)
--sni сайт.com маскировка под чужой сайт
--panel-on domain | ip где открывать панель и подписку
--host IP, --user имя, --port N, --protocols …, --restore файл
Флаги этого скрипта:
--no-harden не отключать ответ на ping и не включать автообновления безопасности
--ssh-port N добавить порт SSH N (прежний порт продолжает работать)
--no-time не запускать kit fix (время и безопасные починки)
--no-check не запускать в конце kit check
--verify-only только проверить релиз (подпись и SHA256) и выйти
--dry-run показать план и ничего не делать
-h | --help эта справка
Что скрипт делает: проверяет сервер → скачивает релиз своей же версии из нашего Gitea,
проверяет подпись SHA256SUMS и SHA256 установщика → запускает установщик автора → досыпает
защиту (ping off правилом ufw, автообновления безопасности, при желании второй порт SSH) →
kit fix и kit check.
EOF
}
# ------------------------------------------------------------------ разбор флагов
INSTALLER_ARGS=(); harden=yes; ssh_port=""; fix_time=yes; do_check=yes; dry=no; verify_only=no
while (($#)); do
case $1 in
--no-harden) harden=no ;;
--ssh-port) ssh_port=${2:-}; shift || die "--ssh-port: нужен номер порта" ;;
--ssh-port=*) ssh_port=${1#*=} ;;
--no-time) fix_time=no ;;
--no-check) do_check=no ;;
--verify-only) verify_only=yes ;;
--dry-run) dry=yes ;;
-h | --help) usage; exit 0 ;;
*) INSTALLER_ARGS+=("$1") ;;
esac
shift
done
[[ -z $ssh_port || $ssh_port =~ ^[0-9]{1,5}$ ]] || die "--ssh-port: нужен номер порта, например 2222"
pre() { printf ' %s\n' "$*"; }
if [[ $dry == yes ]]; then
say "план установки (--dry-run: ничего не делаю)"
pre "версия сборки: $KIT_VERSION"
pre "откуда: $GITEA (тег v$KIT_VERSION), подпись проверяется ключом форка"
if ((${#INSTALLER_ARGS[@]})); then pre "установщик автора: bash scripts/3x-ui.sh ${INSTALLER_ARGS[*]}"; else pre "установщик автора: bash scripts/3x-ui.sh (без доп. флагов)"; fi
pre "маскировка: своя заглушка/домен — как решит установщик автора"
if [[ $harden == yes ]]; then pre "защита: ping off (правилом ufw) + автообновления безопасности"; else pre "защита: пропускаю (--no-harden)"; fi
[[ -n $ssh_port ]] && pre "порт SSH: добавляю $ssh_port (прежний остаётся рабочим)"
[[ $fix_time == yes ]] && pre "после: kit fix (время, безопасные починки)"
[[ $do_check == yes ]] && pre "проверка: kit check + kit local hardening"
echo
say "запуск без --dry-run выполнит всё это на сервере"
exit 0
fi
# ------------------------------------------------------------------ релиз: скачать и проверить подпись
# Подпись проверяем ДО запуска чужого кода, поэтому здесь нужны только curl/ssh-keygen/openssl.
for c in curl ssh-keygen openssl; do command -v "$c" >/dev/null || die "нет $c — поставьте: apt-get update && apt-get install -y $c"; done
say "беру релиз v$KIT_VERSION и проверяю подпись"
tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' EXIT
raw="$GITEA/raw/tag/v$KIT_VERSION"
for f in SHA256SUMS SHA256SUMS.sig scripts/3x-ui.sh; do
mkdir -p "$tmp/$(dirname "$f")"
curl -fsSL --retry 3 -m 60 -o "$tmp/$f" "$raw/$f" || die "не скачался $f из $raw (Gitea доступна с сервера?)"
done
printf '%s namespaces="%s" %s\n' "$SIG_ID" "$NS" "$SIGNER_PUB" >"$tmp/allowed_signers"
ssh-keygen -Y verify -f "$tmp/allowed_signers" -I "$SIG_ID" -n "$NS" -s "$tmp/SHA256SUMS.sig" <"$tmp/SHA256SUMS" >/dev/null 2>&1 \
|| die "подпись релиза v$KIT_VERSION не сошлась с ключом форка — это не наш релиз, ничего не запускаю"
sum=$(awk '{f = $2; sub(/^\*/, "", f)} f == "scripts/3x-ui.sh" {print $1}' "$tmp/SHA256SUMS")
[[ $(printf '%s' "$sum" | wc -c) -eq 64 ]] || die "в SHA256SUMS нет установщика — релиз собран неверно"
got=$(sha256sum "$tmp/scripts/3x-ui.sh" | awk '{print $1}')
[[ $got == "$sum" ]] || die "SHA256 установщика не совпал с подписанным — не запускаю"
bash -n "$tmp/scripts/3x-ui.sh" || die "установщик не проходит проверку синтаксиса"
printf ' ✓ подпись сошлась, SHA256 установщика совпал\n'
if [[ $verify_only == yes ]]; then
say "релиз v$KIT_VERSION проверен: подпись и SHA256 сошлись, установщик не запускался"
exit 0
fi
# ------------------------------------------------------------------ предполётные проверки
say "проверяю сервер"
[[ ${EUID:-0} -eq 0 ]] || die "нужен root: запустите от root (на чистом VPS обычно так и есть)"
[[ -r /etc/os-release ]] || die "не вижу /etc/os-release — это не Debian/Ubuntu?"
# shellcheck disable=SC1091
. /etc/os-release
case ${ID:-} in debian | ubuntu | raspbian) ;; *) warn "система ${PRETTY_NAME:-?}: поддерживаются Debian и Ubuntu" ;; esac
printf ' %s\n' "${PRETTY_NAME:-Linux}, ядро $(uname -r), памяти $(awk '/MemTotal/ {printf "%.1f ГБ", $2 / 1048576}' /proc/meminfo 2>/dev/null || echo '?')"
df -P / | awk 'NR==2 {gsub("%","",$5); if ($5 >= 95) exit 1}' || warn "диск занят почти полностью — установка может не пройти"
for p in 443 80; do ss -H -ltn 2>/dev/null | awk '{print $4}' | grep -qE "[:.]$p\$" && warn "порт $p уже кем-то занят"; done
# ------------------------------------------------------------------ установка
say "запускаю установщик автора (панель 3X-UI, протоколы, сайт-заглушка, подписка)"
if ((${#INSTALLER_ARGS[@]})); then printf ' флаги: %s\n' "${INSTALLER_ARGS[*]}"; fi
# stdin: если есть терминал — отдаём его установщику (там есть вопросы), иначе /dev/null,
# иначе установщик начнёт читать наш собственный скрипт вместо ответов.
if [[ -t 0 ]] || { : </dev/tty; } 2>/dev/null; then
bash "$tmp/scripts/3x-ui.sh" ${INSTALLER_ARGS[@]+"${INSTALLER_ARGS[@]}"} </dev/tty || die "установщик остановился с ошибкой — он ничего не тронул дальше своего лога"
else
bash "$tmp/scripts/3x-ui.sh" ${INSTALLER_ARGS[@]+"${INSTALLER_ARGS[@]}"} </dev/null || die "установщик остановился с ошибкой (нет терминала — вопросы задать некому)"
fi
command -v kit >/dev/null || die "после установки нет команды kit — что-то пошло не так, смотрите вывод выше"
# ------------------------------------------------------------------ наши дополнения
if [[ $fix_time == yes ]]; then
say "kit fix: синхронизация времени и безопасные починки (авторская команда, ничего необратимого)"
kit fix || warn "kit fix завершился с замечаниями — посмотрите вывод"
fi
if [[ $harden == yes ]]; then
say "защита сервера: закрываю ответ на ping и включаю обновления безопасности"
kit local ping off || warn "не удалось закрыть ping — повторите: kit local ping off"
kit local upgrades on || warn "не удалось включить автообновления — повторите: kit local upgrades on"
fi
if [[ -n $ssh_port ]]; then
say "добавляю порт SSH $ssh_port (прежний порт продолжает работать)"
kit local ssh "$ssh_port" || warn "порт не добавился — сделайте это отдельно: kit local ssh $ssh_port"
cat <<EOF
${Y}Дальше обязательно:${N}
проверьте вход во ВТОРОМ окне: ssh -p $ssh_port root@<IP сервера>
убедились — закройте прежние порты: kit local ssh --close-old $ssh_port
EOF
fi
# ------------------------------------------------------------------ проверка
if [[ $do_check == yes ]]; then
say "проверяю, что получилось"
kit check || warn "kit check нашёл замечания — читайте выше; безопасные починки: kit fix"
kit local hardening
fi
cat <<EOF
${G}${B}Готово.${N} Сервер поставлен из нашей сборки (3X-UI KIT $KIT_VERSION, канал: наш Gitea).
подписка и ссылки: kit user link admin (или страница подписки из вывода установщика)
если что-то не так: kit check --deep, затем kit fix
вернуться к авторскому каналу: положить авторский kit поверх и выполнить kit update --force
EOF
+1 -1
View File
@@ -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.2"
KIT_VERSION="1.2.5"
# 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,
+1 -1
View File
@@ -8,7 +8,7 @@
# Код выхода 1 при любом запуске (и при `__update_binary`) – старый `hy2 update` на нём
# останавливается и не заменяет команду hy2.
KIT_VERSION="1.2.2"
KIT_VERSION="1.2.5"
cat >&2 <<'MSG'
Отдельный установщик Hysteria2 больше не поддерживается.
+1 -1
View File
@@ -12,7 +12,7 @@
set -Eeuo pipefail
export LC_ALL=C.UTF-8 # ширина колонок по символам, а не байтам
KIT_VERSION="1.2.2"
KIT_VERSION="1.2.5"
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"; }
+8 -1
View File
@@ -169,9 +169,16 @@ def main():
"tools/release.sh",
"FILES=(scripts/3x-ui.sh scripts/hysteria2.sh scripts/kit.sh scripts/kit-sub.py VERSION)",
False,
"FILES=(scripts/3x-ui.sh scripts/hysteria2.sh scripts/kit.sh scripts/kit-sub.py scripts/kit-local.sh VERSION)",
"FILES=(scripts/3x-ui.sh scripts/hysteria2.sh scripts/kit.sh scripts/kit-sub.py scripts/kit-local.sh scripts/3x-ui-local.sh VERSION)",
"наш файл в подписанном списке релиза",
),
(
"tools/release.sh",
'{ echo "# 3X-UI KIT $v"; sha "${FILES[@]}"; } >SHA256SUMS',
False,
"{ echo \"# 3X-UI KIT $v\"; sha \"${FILES[@]}\" | awk '{ sub(/^\\*/, \"\", $2); print $1\" \"$2 }'; } >SHA256SUMS",
"суммы в POSIX-виде без звёздочки (на Windows sha256sum её ставит, и kit её не понимает)",
),
# --- свои записи о версии (наш файл, авторский CHANGELOG не трогаем) ----
(
"tools/release.sh",
+2 -2
View File
@@ -19,7 +19,7 @@ key=${1:-$HOME/.ssh/3xui_kit_release}
[[ -f $key ]] || die "Нет закрытого ключа $key. Создать: ssh-keygen -t ed25519 -C \"3X-UI KIT releases\" -f $key"
NS="3x-ui-kit-release"
ID="releases@3x-ui-kit"
FILES=(scripts/3x-ui.sh scripts/hysteria2.sh scripts/kit.sh scripts/kit-sub.py scripts/kit-local.sh VERSION)
FILES=(scripts/3x-ui.sh scripts/hysteria2.sh scripts/kit.sh scripts/kit-sub.py scripts/kit-local.sh scripts/3x-ui-local.sh VERSION)
v=$(tr -d '[:space:]' <VERSION)
[[ $v =~ ^[0-9]+(\.[0-9]+)+$ ]] || die "VERSION: $v"
@@ -70,7 +70,7 @@ pub=$(ssh-keygen -y -f "$key" | awk '{print $1, $2}')
signers scripts/kit.sh | awk '{print $1, $2}' | grep -qxF "$pub" || die "Ключа $key нет в KIT_SIGNERS – серверы не примут такую подпись."
ok "Ключ подписи записан в kit"
{ echo "# 3X-UI KIT $v"; sha "${FILES[@]}"; } >SHA256SUMS
{ echo "# 3X-UI KIT $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
tmp=$(mktemp)