From a6f53d9ad5806a71348f5d096396ed835032b735 Mon Sep 17 00:00:00 2001 From: ochenstarik-ui Date: Wed, 15 Jul 2026 13:27:24 +0700 Subject: [PATCH] Add sequential installation wizard (#2) --- README.md | 14 ++- ochenstarik-server-install.sh | 162 ++++++++++++++++++++++++++++++++++ 2 files changed, 175 insertions(+), 1 deletion(-) create mode 100644 ochenstarik-server-install.sh diff --git a/README.md b/README.md index b4ef7fe..fc68712 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ | Файл | Назначение | Можно запускать отдельно | | --- | --- | --- | +| `ochenstarik-server-install.sh` | Единый пошаговый мастер: установить, пропустить или завершить на каждом этапе | Да; рекомендуемый способ полной настройки | | `ochenstarik-server-1.sh` | Предлагает выбрать часовой пояс и русификацию терминала, создаёт swap-файл 2 ГБ и задаёт `vm.swappiness=20` | Да | | `ochenstarik-server-2.sh` | Предлагает выбрать будущий SSH-порт и режим IPv4/IPv6, обновляет систему, ставит пакеты и настраивает UFW | Да | | `ochenstarik-server-user-3.sh` | Создаёт администратора, переносит SSH на порт из этапа 2, проверяет права и включает fail2ban | После установки необходимых пакетов; проще всего сначала запустить скрипт 2 | @@ -312,7 +313,18 @@ zstd -dc /ПУТЬ/К/АРХИВУ.tar.zst | tar --acls --xattrs --numeric-owner ## Полная установка -Если нужны все модули, запускайте их по очереди: +Рекомендуемый способ — единый мастер. Он показывает этапы по порядку и перед каждым предлагает установить его, пропустить либо завершить работу. Если остальные файлы находятся рядом, мастер использует их. Если какой-либо этап отсутствует, мастер безопасно загрузит его из основной ветки, проверит `bash -n` и только потом запустит. + +```bash +curl -fLO https://raw.githubusercontent.com/ochenstarik-ui/lightweight-server/main/ochenstarik-server-install.sh +chmod 700 ochenstarik-server-install.sh +bash -n ochenstarik-server-install.sh +sudo ./ochenstarik-server-install.sh +``` + +После ошибки этап можно повторить, пропустить или завершить весь мастер. Повторный запуск мастера разрешён: каждый модуль поддерживает повторную настройку. + +Отдельные скрипты сохранены. При необходимости их по-прежнему можно запускать вручную по очереди: ```bash sudo ./ochenstarik-server-1.sh diff --git a/ochenstarik-server-install.sh b/ochenstarik-server-install.sh new file mode 100644 index 0000000..0c38652 --- /dev/null +++ b/ochenstarik-server-install.sh @@ -0,0 +1,162 @@ +#!/usr/bin/env bash +set -Eeuo pipefail + +readonly REPO_RAW_BASE="https://raw.githubusercontent.com/ochenstarik-ui/lightweight-server/main" +readonly SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)" + +declare -a STEP_FILES=( + "ochenstarik-server-1.sh" + "ochenstarik-server-2.sh" + "ochenstarik-server-user-3.sh" + "ochenstarik-server-tg-4.sh" + "ochenstarik-server-vpn-5.sh" + "ochenstarik-server-panel-warp-6.sh" + "ochenstarik-server-backup-7.sh" +) + +declare -a STEP_TITLES=( + "Часовой пояс, русификация терминала и swap" + "Базовые пакеты, будущий SSH-порт, IPv4/IPv6 и UFW" + "Администратор, перенос SSH и fail2ban" + "Telegram-уведомления о входах по SSH" + "Системный VPN через Xray" + "Панель 3x-ui и Cloudflare WARP" + "Первичный снимок и расписания резервного копирования" +) + +TEMP_FILE="" + +log() { printf '[+] %s\n' "$*"; } +warn() { printf '[!] %s\n' "$*" >&2; } +die() { printf '[x] %s\n' "$*" >&2; exit 1; } + +cleanup() { + if [[ -n "$TEMP_FILE" && "$TEMP_FILE" == "$SCRIPT_DIR"/.ochenstarik-server-* \ + && -f "$TEMP_FILE" && ! -L "$TEMP_FILE" ]]; then + rm -f -- "$TEMP_FILE" + fi +} +trap cleanup EXIT + +ensure_step_script() { + local filename="$1" result_variable="$2" target + target="${SCRIPT_DIR}/${filename}" + + if [[ -e "$target" ]]; then + [[ -f "$target" && ! -L "$target" ]] \ + || die "Отказ от запуска: $target должен быть обычным файлом" + else + command -v curl >/dev/null 2>&1 \ + || die "Не найден curl: установите его командой apt-get install -y curl ca-certificates" + [[ -d "$SCRIPT_DIR" && ! -L "$SCRIPT_DIR" && -w "$SCRIPT_DIR" ]] \ + || die "Каталог $SCRIPT_DIR недоступен для безопасной загрузки" + + log "Файл ${filename} отсутствует; загружаю его из основного репозитория" + TEMP_FILE="$(mktemp "${SCRIPT_DIR}/.ochenstarik-server-download.XXXXXX")" + chmod 600 "$TEMP_FILE" + curl -fL --retry 5 --retry-delay 5 --connect-timeout 30 \ + --proto '=https' --tlsv1.2 "${REPO_RAW_BASE}/${filename}" -o "$TEMP_FILE" + bash -n "$TEMP_FILE" || die "Загруженный файл ${filename} не прошёл проверку Bash" + chmod 700 "$TEMP_FILE" + mv -- "$TEMP_FILE" "$target" + TEMP_FILE="" + fi + + chmod 700 "$target" + bash -n "$target" || die "Синтаксическая ошибка в $target" + printf -v "$result_variable" '%s' "$target" +} + +choose_step_action() { + local step_number="$1" title="$2" result_variable="$3" answer + while :; do + printf '\n============================================================\n' + printf 'Этап %s из %s: %s\n' "$step_number" "${#STEP_FILES[@]}" "$title" + printf ' 1) Установить / запустить этот этап\n' + printf ' 2) Пропустить и перейти к следующему\n' + printf ' 3) Завершить мастер\n' + read -rp 'Выберите действие: ' answer || die "Ввод прерван" + case "$answer" in + 1|2|3) printf -v "$result_variable" '%s' "$answer"; return 0 ;; + *) warn "Введите 1, 2 или 3" ;; + esac + done +} + +choose_after_failure() { + local result_variable="$1" answer + while :; do + printf '\nЭтап завершился с ошибкой.\n' + printf ' 1) Запустить этот этап повторно\n' + printf ' 2) Пропустить и перейти к следующему\n' + printf ' 3) Завершить мастер\n' + read -rp 'Выберите действие: ' answer || die "Ввод прерван" + case "$answer" in + 1|2|3) printf -v "$result_variable" '%s' "$answer"; return 0 ;; + *) warn "Введите 1, 2 или 3" ;; + esac + done +} + +print_summary() { + local completed="$1" skipped="$2" + printf '\n============================================================\n' + printf 'Мастер установки завершён.\n' + printf 'Успешно выполнено этапов: %s\n' "$completed" + printf 'Пропущено этапов: %s\n' "$skipped" + printf '\nМастер можно запустить повторно: каждый этап поддерживает повторную настройку.\n' + printf 'Для полного сброса используйте ochenstarik-server-uninstall.sh.\n' +} + +[[ "$EUID" -eq 0 ]] || die "Запустите мастер от имени root: sudo ./ochenstarik-server-install.sh" +((${#STEP_FILES[@]} == ${#STEP_TITLES[@]})) || die "Некорректное описание этапов" + +cat <<'INTRO' + +Единый мастер установки lightweight-server + +Этапы будут показаны по порядку. Каждый из них можно выполнить, пропустить +или завершить весь мастер. Не закрывайте текущую SSH-сессию во время изменения +порта SSH и проверяйте новый вход во втором терминале. +INTRO + +completed=0 +skipped=0 + +for index in "${!STEP_FILES[@]}"; do + step_number="$((index + 1))" + action="" + choose_step_action "$step_number" "${STEP_TITLES[index]}" action + case "$action" in + 2) + skipped="$((skipped + 1))" + continue + ;; + 3) + print_summary "$completed" "$skipped" + exit 0 + ;; + esac + + script_path="" + ensure_step_script "${STEP_FILES[index]}" script_path + while :; do + log "Запуск этапа ${step_number}: ${STEP_TITLES[index]}" + if bash -- "$script_path"; then + completed="$((completed + 1))" + log "Этап ${step_number} успешно завершён" + break + fi + + warn "Этап ${step_number} вернул ошибку" + failure_action="" + choose_after_failure failure_action + case "$failure_action" in + 1) continue ;; + 2) skipped="$((skipped + 1))"; break ;; + 3) print_summary "$completed" "$skipped"; exit 1 ;; + esac + done +done + +print_summary "$completed" "$skipped"