diff --git a/FORK-CHANGELOG.md b/FORK-CHANGELOG.md index a8ce5ad..6e6ef59 100644 --- a/FORK-CHANGELOG.md +++ b/FORK-CHANGELOG.md @@ -3,6 +3,21 @@ Здесь записи о наших версиях. Файл автора (`CHANGELOG.md`) мы не трогаем — так обновления автора не конфликтуют с нашими записями. +## 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` (закрыть прежние diff --git a/FORK.md b/FORK.md index 75dc399..bd9de4c 100644 --- a/FORK.md +++ b/FORK.md @@ -44,7 +44,14 @@ 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/tag/v1.2.3/scripts/3x-ui-local.sh) --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) # обновление уже стоящего сервера (тянет наш релиз и проверяет нашу подпись) diff --git a/VERSION b/VERSION index 23aa839..0495c4a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.2.2 +1.2.3 diff --git a/scripts/3x-ui-local.sh b/scripts/3x-ui-local.sh new file mode 100644 index 0000000..70f57d7 --- /dev/null +++ b/scripts/3x-ui-local.sh @@ -0,0 +1,191 @@ +#!/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.3" # версия сборки форка; должна совпадать с 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 + --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 +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 ;; + --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 + +# ------------------------------------------------------------------ предполётные проверки + +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 +for c in curl ssh-keygen openssl; do command -v "$c" >/dev/null || die "нет $c — поставьте: apt-get update && apt-get install -y $c"; done +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 "беру релиз 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 '$2 == "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' + +# ------------------------------------------------------------------ установка + +say "запускаю установщик автора (панель 3X-UI, протоколы, сайт-заглушка, подписка)" +if ((${#INSTALLER_ARGS[@]})); then printf ' флаги: %s\n' "${INSTALLER_ARGS[*]}"; fi +# stdin: если есть терминал — отдаём его установщику (там есть вопросы), иначе /dev/null, +# иначе установщик начнёт читать наш собственный скрипт вместо ответов. +if [[ -t 0 ]] || { : /dev/null; then + bash "$tmp/scripts/3x-ui.sh" ${INSTALLER_ARGS[@]+"${INSTALLER_ARGS[@]}"} /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 < + убедились — закройте прежние порты: 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 <&2 <<'MSG' Отдельный установщик Hysteria2 больше не поддерживается. diff --git a/scripts/kit.sh b/scripts/kit.sh index 132087a..04c9f5c 100644 --- a/scripts/kit.sh +++ b/scripts/kit.sh @@ -12,7 +12,7 @@ set -Eeuo pipefail export LC_ALL=C.UTF-8 # ширина колонок по символам, а не байтам -KIT_VERSION="1.2.2" +KIT_VERSION="1.2.3" 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"; } diff --git a/tools/fork_apply.py b/tools/fork_apply.py index 9f1665a..88d5d5e 100644 --- a/tools/fork_apply.py +++ b/tools/fork_apply.py @@ -169,7 +169,7 @@ 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)", "наш файл в подписанном списке релиза", ), # --- свои записи о версии (наш файл, авторский CHANGELOG не трогаем) ---- diff --git a/tools/release.sh b/tools/release.sh index 7e389d1..10faf5c 100755 --- a/tools/release.sh +++ b/tools/release.sh @@ -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:]'