From ad60deabb48feb2b49891c079bb882a2f273cb3f Mon Sep 17 00:00:00 2001 From: Sergey Antropoff Date: Mon, 23 Feb 2026 19:55:29 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=B8=D1=82?= =?UTF-8?q?=D1=8C=20install.sh?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- install.sh | 1099 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 746 insertions(+), 353 deletions(-) diff --git a/install.sh b/install.sh index 82f62d6..6bb30ba 100644 --- a/install.sh +++ b/install.sh @@ -2,9 +2,13 @@ export LANG=ru_RU.UTF-8 +# Цвета для вывода RED="\033[31m" GREEN="\033[32m" YELLOW="\033[33m" +BLUE="\033[34m" +PURPLE="\033[35m" +CYAN="\033[36m" PLAIN="\033[0m" red(){ @@ -19,12 +23,31 @@ yellow(){ echo -e "\033[33m\033[01m$1\033[0m" } +blue(){ + echo -e "\033[34m\033[01m$1\033[0m" +} + +purple(){ + echo -e "\033[35m\033[01m$1\033[0m" +} + +cyan(){ + echo -e "\033[36m\033[01m$1\033[0m" +} + +# Проверка прав root if [[ $EUID -ne 0 ]]; then red "Внимание: Запустите скрипт от имени root пользователя" exit 1 fi +# Параметры по умолчанию CUSTOM_SNI="" +CONFIG_DIR="/etc/hysteria" +USERS_FILE="$CONFIG_DIR/users.txt" +HYSTERIA_SERVICE="hysteria-server" + +# Обработка аргументов командной строки for arg in "$@"; do case $arg in --custom-sni=*) @@ -42,6 +65,7 @@ for arg in "$@"; do esac done +# Определение ОС REGEX=("debian" "ubuntu" "centos|red hat|kernel|oracle linux|alma|rocky" "'amazon linux'" "fedora" "alpine") RELEASE=("Debian" "Ubuntu" "CentOS" "CentOS" "Fedora" "Alpine") PACKAGE_UPDATE=("apt-get update" "apt-get update" "yum -y update" "yum -y update" "yum -y update" "apk update -f") @@ -59,300 +83,252 @@ done [[ -z $SYSTEM ]] && red "Текущая система VPS не поддерживается, используйте основную операционную систему" && exit 1 -if [[ -z $(type -P curl) ]]; then - if [[ ! $SYSTEM == "CentOS" ]]; then - ${PACKAGE_UPDATE[int]} +# Функция для установки необходимых пакетов +install_dependencies() { + if [[ -z $(type -P curl) ]]; then + if [[ ! $SYSTEM == "CentOS" ]]; then + ${PACKAGE_UPDATE[int]} + fi + ${PACKAGE_INSTALL[int]} curl fi - ${PACKAGE_INSTALL[int]} curl -fi + + if [[ -z $(type -P openssl) ]]; then + ${PACKAGE_INSTALL[int]} openssl + fi + + if [[ -z $(type -P qrencode) ]]; then + ${PACKAGE_INSTALL[int]} qrencode + fi + + if [[ -z $(type -P md5sum) ]]; then + ${PACKAGE_INSTALL[int]} coreutils + fi +} +# Функция для получения IP адреса get_ip() { - local ip=$(curl -s4m8 ip.sb -k) || ip=$(curl -s6m8 ip.sb -k) + local ip=$(curl -s4m8 ip.sb -k 2>/dev/null) || ip=$(curl -s6m8 ip.sb -k 2>/dev/null) echo "$ip" } -install_server_core() { - yellow "Установка Hysteria2..." +# Функция для генерации пароля +generate_password() { + date +%s%N | md5sum | cut -c 1-16 +} + +# Функция для получения obfs пароля из конфига +get_obfs_password() { + if [[ -f "$CONFIG_DIR/config.yaml" ]]; then + grep -A 2 "obfs:" "$CONFIG_DIR/config.yaml" | grep "password:" | head -1 | awk '{print $2}' + else + echo "" + fi +} + +# Функция для получения SNI из конфига +get_sni() { + if [[ -n "$CUSTOM_SNI" ]]; then + echo "$CUSTOM_SNI" + elif [[ -f "$CONFIG_DIR/config.yaml" ]]; then + grep "url: https://" "$CONFIG_DIR/config.yaml" | sed 's|.*https://\([^/]*\).*|\1|' + else + echo "web.max.ru" + fi +} + +# Функция для генерации ссылки пользователя +generate_user_link() { + local username=$1 + local password=$2 + local sni_host=$(get_sni) + local server_ip=$(get_ip) + local port="443" + local obfs_pwd=$(get_obfs_password) - set -e + if [[ -z "$obfs_pwd" ]]; then + obfs_pwd="unknown" + fi + + local user_link="hy2://$password@$server_ip:$port?mport&security=tls&sni=$sni_host&allowInsecure=true&alpn&obfs=salamander&obfs-password=$obfs_pwd#$username" + + echo "$user_link" +} - SCRIPT_ARGS=("$@") +# Функция для сохранения ссылки пользователя в файл +save_user_link() { + local username=$1 + local password=$2 + local user_link=$(generate_user_link "$username" "$password") + + echo "$user_link" > "/root/hysteria2_${username}.txt" + echo "$user_link" +} - EXECUTABLE_INSTALL_PATH="/usr/local/bin/hysteria" +# Функция для обновления конфигурации Hysteria с пользователями +update_hysteria_config() { + if [[ ! -f "$CONFIG_DIR/config.yaml" ]]; then + red "Конфигурационный файл не найден!" + return 1 + fi + + if [[ ! -f "$USERS_FILE" ]]; then + # Если нет файла пользователей, создаем временный с заглушкой + local temp_users=$(mktemp) + echo " userpass:" > "$temp_users" + echo " _placeholder: \"_placeholder\"" >> "$temp_users" + else + local temp_users=$(mktemp) + echo " userpass:" > "$temp_users" + while IFS=: read -r username password; do + if [[ -n "$username" && -n "$password" ]]; then + echo " $username: \"$password\"" >> "$temp_users" + fi + done < "$USERS_FILE" + fi + + # Создаем резервную копию + cp "$CONFIG_DIR/config.yaml" "$CONFIG_DIR/config.yaml.backup" + + # Обновляем конфиг + if grep -q "userpass:" "$CONFIG_DIR/config.yaml"; then + # Удаляем старую секцию userpass + sed -i '/userpass:/,/^[^ ]/ { + /userpass:/! { /^[^ ]/! d } + }' "$CONFIG_DIR/config.yaml" + + # Вставляем новую секцию после auth: + sed -i "/auth:/r $temp_users" "$CONFIG_DIR/config.yaml" + else + red "Не удалось найти секцию auth в конфигурации" + rm -f "$temp_users" + return 1 + fi + + rm -f "$temp_users" + + # Перезапускаем сервис + systemctl restart "$HYSTERIA_SERVICE" + + return 0 +} - SYSTEMD_SERVICES_DIR="/etc/systemd/system" - - CONFIG_DIR="/etc/hysteria" - - REPO_URL="https://github.com/apernet/hysteria" - - HY2_API_BASE_URL="https://api.hy2.io/v1" - - CURL_FLAGS=(-L -f -q --retry 5 --retry-delay 10 --retry-max-time 60) - - PACKAGE_MANAGEMENT_INSTALL="${PACKAGE_MANAGEMENT_INSTALL:-}" - - OPERATING_SYSTEM="${OPERATING_SYSTEM:-}" - - ARCHITECTURE="${ARCHITECTURE:-}" - - HYSTERIA_USER="${HYSTERIA_USER:-}" - - HYSTERIA_HOME_DIR="${HYSTERIA_HOME_DIR:-}" - - OPERATION= - - VERSION= - - FORCE= - - LOCAL_FILE= - - has_command() { - local _command=$1 - type -P "$_command" > /dev/null 2>&1 - } - - curl() { - command curl "${CURL_FLAGS[@]}" "$@" - } - - mktemp() { - command mktemp "$@" "/tmp/hyservinst.XXXXXXXXXX" - } - - note() { - local _msg="$1" - echo -e "$SCRIPT_NAME: $(tput bold)note: $_msg$(tput sgr0)" - } - - warning() { - local _msg="$1" - echo -e "$SCRIPT_NAME: $(tput setaf 3)warning: $_msg$(tput sgr0)" - } - - error() { - local _msg="$1" - echo -e "$SCRIPT_NAME: $(tput setaf 1)error: $_msg$(tput sgr0)" - } - - check_environment_operating_system() { - if [[ -n "$OPERATING_SYSTEM" ]]; then - warning "OPERATING_SYSTEM=$OPERATING_SYSTEM обнаружено, определение ОС выполняться не будет." - return - fi - - if [[ "x$(uname)" == "xLinux" ]]; then - OPERATING_SYSTEM=linux - return - fi - - error "Этот скрипт поддерживает только Linux." - exit 95 - } - - check_environment_architecture() { - if [[ -n "$ARCHITECTURE" ]]; then - warning "ARCHITECTURE=$ARCHITECTURE обнаружено, определение архитектуры выполняться не будет." - return - fi - - case "$(uname -m)" in - 'i386' | 'i686') - ARCHITECTURE='386' - ;; - 'amd64' | 'x86_64') - ARCHITECTURE='amd64' - ;; - 'armv5tel' | 'armv6l' | 'armv7' | 'armv7l') - ARCHITECTURE='arm' - ;; - 'armv8' | 'aarch64') - ARCHITECTURE='arm64' - ;; - 'mips' | 'mipsle' | 'mips64' | 'mips64le') - ARCHITECTURE='mipsle' - ;; - 's390x') - ARCHITECTURE='s390x' - ;; +# Функция установки Hysteria2 +install_hysteria() { + yellow "Начинаем установку Hysteria2..." + + # Проверяем, установлен ли уже Hysteria + if [[ -f /usr/local/bin/hysteria ]]; then + red "Hysteria2 уже установлен!" + read -p "Хотите переустановить? (y/n): " -n 1 -r + echo + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + return + fi + uninstall_hysteria + fi + + install_dependencies + + # Определяем архитектуру + case "$(uname -m)" in + 'i386' | 'i686') ARCH='386' ;; + 'amd64' | 'x86_64') ARCH='amd64' ;; + 'armv5tel' | 'armv6l' | 'armv7' | 'armv7l') ARCH='arm' ;; + 'armv8' | 'aarch64') ARCH='arm64' ;; + 'mips' | 'mipsle' | 'mips64' | 'mips64le') ARCH='mipsle' ;; + 's390x') ARCH='s390x' ;; *) - error "Архитектура '$(uname -a)' не поддерживается." - exit 8 - ;; - esac - } - - check_environment_systemd() { - if [[ -d "/run/systemd/system" ]] || grep -q systemd <(ls -l /sbin/init); then - return - fi - - case "$FORCE_NO_SYSTEMD" in - '1') - warning "FORCE_NO_SYSTEMD=1, продолжим даже если systemd не обнаружен." - ;; - '2') - warning "FORCE_NO_SYSTEMD=2, продолжим но пропустим все команды связанные с systemd." - ;; - *) - error "Этот скрипт поддерживает только дистрибутивы Linux с systemd." - exit 1 - ;; - esac - } - - update_packages() { - ${PACKAGE_UPDATE[int]} - } - - check_environment_curl() { - if has_command curl; then - return - fi - ${PACKAGE_INSTALL[int]} curl - } - - check_environment_grep() { - if has_command grep; then - return - fi - ${PACKAGE_INSTALL[int]} grep - } - - check_environment_qrencode() { - if has_command qrencode; then - return - fi - ${PACKAGE_INSTALL[int]} qrencode - } - - check_environment() { - update_packages - check_environment_operating_system - check_environment_architecture - check_environment_systemd - check_environment_curl - check_environment_grep - check_environment_qrencode - } - - install_content() { - local _install_flags="$1" - local _content="$2" - local _destination="$3" - local _overwrite="$4" - - local _tmpfile="$(mktemp)" - - echo -ne "Установка $_destination ... " - echo "$_content" > "$_tmpfile" - if [[ -z "$_overwrite" && -e "$_destination" ]]; then - echo -e "существует" - elif install "$_install_flags" "$_tmpfile" "$_destination"; then - echo -e "ок" - fi - - rm -f "$_tmpfile" - } - - get_latest_version() { - if [[ -n "$VERSION" ]]; then - echo "$VERSION" - return - fi - - local _tmpfile=$(mktemp) - if ! curl -sS "$HY2_API_BASE_URL/update?cver=installscript&plat=${OPERATING_SYSTEM}&arch=${ARCHITECTURE}&chan=release&side=server" -o "$_tmpfile"; then - error "Ошибка получения последней версии от Hysteria 2 API" - exit 11 - fi - - local _latest_version=$(grep -oP '"lver":\s*\K"v.*?"' "$_tmpfile" | head -1) - _latest_version=${_latest_version#'"'} - _latest_version=${_latest_version%'"'} - - if [[ -n "$_latest_version" ]]; then - echo "$_latest_version" - fi - - rm -f "$_tmpfile" - } - - download_hysteria() { - local _version="$1" - local _destination="$2" - - local _download_url="$REPO_URL/releases/download/app/$_version/hysteria-$OPERATING_SYSTEM-$ARCHITECTURE" - echo "Загрузка бинарного файла hysteria: $_download_url ..." - if ! curl -R -H 'Cache-Control: no-cache' "$_download_url" -o "$_destination"; then - error "Ошибка загрузки, проверьте ваше соединение и попробуйте снова." - return 11 - fi - return 0 - } - - perform_install_hysteria_binary() { - local _tmpfile=$(mktemp) - local _version=$(get_latest_version) - - if ! download_hysteria "$_version" "$_tmpfile"; then - rm -f "$_tmpfile" - exit 11 - fi - - echo -ne "Установка исполняемого файла hysteria ... " - if install -Dm755 "$_tmpfile" "$EXECUTABLE_INSTALL_PATH"; then - echo "ок" - else - exit 13 - fi - - rm -f "$_tmpfile" - - mkdir -p /etc/hysteria - } - - perform_install_hysteria_systemd() { - if [[ "x$FORCE_NO_SYSTEMD" == "x2" ]]; then - return - fi - - local _service_content=$(cat << 'EOF' + red "Архитектура не поддерживается!" + exit 1 + ;; + esac + + # Скачиваем последнюю версию + green "Загружаем последнюю версию Hysteria2..." + LATEST_VERSION=$(curl -s https://api.github.com/repos/apernet/hysteria/releases/latest | grep tag_name | cut -d '"' -f 4) + + if [[ -z "$LATEST_VERSION" ]]; then + red "Не удалось получить последнюю версию" + exit 1 + fi + + DOWNLOAD_URL="https://github.com/apernet/hysteria/releases/download/app/$LATEST_VERSION/hysteria-linux-$ARCH" + + curl -L -o /usr/local/bin/hysteria "$DOWNLOAD_URL" + chmod +x /usr/local/bin/hysteria + + # Создаем директорию для конфигурации + mkdir -p "$CONFIG_DIR" + + # Настройка Hysteria + configure_hysteria + + # Создаем systemd сервис + cat << 'EOF' > /etc/systemd/system/hysteria-server.service [Unit] -Description=Hysteria Server Service (config.yaml) +Description=Hysteria Server Service After=network.target [Service] Type=simple ExecStart=/usr/local/bin/hysteria server --config /etc/hysteria/config.yaml -WorkingDirectory=~ +WorkingDirectory=/etc/hysteria User=root Group=root Environment=HYSTERIA_LOG_LEVEL=info CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW NoNewPrivileges=true +Restart=always +RestartSec=5 [Install] WantedBy=multi-user.target EOF -) - install_content -Dm644 "$_service_content" "$SYSTEMD_SERVICES_DIR/hysteria-server.service" "1" - - systemctl daemon-reload - } - - check_environment - HYSTERIA_USER="root" - HYSTERIA_HOME_DIR="/root" - - perform_install_hysteria_binary - perform_install_hysteria_systemd - - green "Hysteria2 core успешно установлен!" + + systemctl daemon-reload + systemctl enable hysteria-server + systemctl start hysteria-server + + if systemctl is-active hysteria-server > /dev/null; then + green "Hysteria2 успешно установлен и запущен!" + + # Создаем первого пользователя + echo + yellow "Создаем первого пользователя..." + local admin_user="user1" + local admin_pass=$(generate_password) + echo "$admin_user:$admin_pass" > "$USERS_FILE" + + # Обновляем конфиг + update_hysteria_config + + # Сохраняем ссылку + local user_link=$(save_user_link "$admin_user" "$admin_pass") + + green "Первый пользователь создан:" + echo "======================================================" + echo "Имя пользователя: $admin_user" + echo "Пароль: $admin_pass" + echo "Ссылка для подключения:" + echo "$user_link" + echo "======================================================" + + if command -v qrencode &> /dev/null; then + echo "QR код для подключения:" + qrencode -t ANSIUTF8 "$user_link" + fi + + echo + yellow "Файл со ссылкой сохранен: /root/hysteria2_${admin_user}.txt" + else + red "Ошибка запуска Hysteria-server" + systemctl status hysteria-server + exit 1 + fi } +# Функция настройки Hysteria configure_hysteria() { yellow "Настройка сервера Hysteria2..." @@ -361,27 +337,26 @@ configure_hysteria() { yellow "Используется кастомный SNI: $sni_host" else local sni_host="web.max.ru" + yellow "Используется SNI по умолчанию: $sni_host" fi - + local masquerade_url="$sni_host" local port="443" - - mkdir -p /etc/hysteria - - local auth_pwd=$(date +%s%N | md5sum | cut -c 1-16) - local obfs_pwd=$(date +%s%N | md5sum | cut -c 1-16) - - openssl ecparam -genkey -name prime256v1 -out /etc/hysteria/private.key - openssl req -new -x509 -days 36500 -key /etc/hysteria/private.key -out /etc/hysteria/cert.crt -subj "/CN=$sni_host" - chmod 600 /etc/hysteria/cert.crt - chmod 600 /etc/hysteria/private.key + local obfs_pwd=$(generate_password) - cat << EOF > /etc/hysteria/config.yaml + # Генерируем SSL сертификат + openssl ecparam -genkey -name prime256v1 -out "$CONFIG_DIR/private.key" + openssl req -new -x509 -days 36500 -key "$CONFIG_DIR/private.key" -out "$CONFIG_DIR/cert.crt" -subj "/CN=$sni_host" + chmod 600 "$CONFIG_DIR/cert.crt" + chmod 600 "$CONFIG_DIR/private.key" + + # Создаем базовую конфигурацию + cat << EOF > "$CONFIG_DIR/config.yaml" listen: :$port tls: - cert: /etc/hysteria/cert.crt - key: /etc/hysteria/private.key + cert: $CONFIG_DIR/cert.crt + key: $CONFIG_DIR/private.key obfs: type: salamander @@ -389,8 +364,9 @@ obfs: password: $obfs_pwd auth: - type: password - password: $auth_pwd + type: userpass + userpass: + _placeholder: "_placeholder" masquerade: type: proxy @@ -405,104 +381,521 @@ quic: maxConnReceiveWindow: 33554432 EOF - local server_ip=$(get_ip) - - cat << EOF > /root/hysteria2.txt -hy2://$auth_pwd@$server_ip:$port?mport&security=tls&sni=$sni_host&allowInsecure=true&alpn&obfs=salamander&obfs-password=$obfs_pwd#Test -EOF + green "Базовая конфигурация создана" +} - green "Настройка завершена!" +# Функция добавления пользователя +add_user() { + if [[ ! -f /usr/local/bin/hysteria ]]; then + red "Hysteria2 не установлен! Сначала выполните установку." + return + fi + echo - yellow "IP сервера: $server_ip" - yellow "Порт: $port" - yellow "SNI: $sni_host" - yellow "Пароль аутентификации: $auth_pwd" - yellow "Пароль обфускации: $obfs_pwd" - yellow "Маскировка: https://$masquerade_url" + cyan "=== Добавление нового пользователя ===" echo - if [[ -n "$CUSTOM_SNI" ]]; then - green "Использован кастомный SNI: $CUSTOM_SNI" + read -p "Введите имя пользователя: " username + + if [[ -z "$username" ]]; then + red "Имя пользователя не может быть пустым!" + return + fi + + # Проверяем, существует ли уже пользователь + if [[ -f "$USERS_FILE" ]] && grep -q "^$username:" "$USERS_FILE"; then + red "Пользователь $username уже существует!" + return + fi + + read -p "Введите пароль (оставьте пустым для генерации): " password + + if [[ -z "$password" ]]; then + password=$(generate_password) + green "Сгенерирован пароль: $password" + fi + + # Добавляем пользователя + echo "$username:$password" >> "$USERS_FILE" + + # Обновляем конфиг + if update_hysteria_config; then + green "Конфигурация обновлена" + + # Сохраняем ссылку + local user_link=$(save_user_link "$username" "$password") + + echo + green "Пользователь $username успешно создан!" + echo "======================================================" + echo "Имя пользователя: $username" + echo "Пароль: $password" + echo "Ссылка для подключения:" + echo "$user_link" + echo "======================================================" + echo "Ссылка также сохранена в /root/hysteria2_${username}.txt" + echo + + if command -v qrencode &> /dev/null; then + echo "QR код для подключения:" + qrencode -t ANSIUTF8 "$user_link" + fi + else + red "Ошибка при обновлении конфигурации" + # Удаляем пользователя из файла в случае ошибки + sed -i "/^$username:/d" "$USERS_FILE" fi } -start_service() { - yellow "Запуск службы Hysteria2..." +# Функция удаления пользователя +delete_user() { + if [[ ! -f "$USERS_FILE" ]]; then + red "Нет пользователей для удаления" + return + fi + echo + cyan "=== Удаление пользователя ===" + echo + + # Показываем список пользователей + list_users + + echo + read -p "Введите имя пользователя для удаления: " username + + if [[ -z "$username" ]]; then + red "Имя пользователя не может быть пустым!" + return + fi + + # Проверяем, существует ли пользователь + if ! grep -q "^$username:" "$USERS_FILE"; then + red "Пользователь $username не найден!" + return + fi + + # Подтверждение + read -p "Вы уверены, что хотите удалить пользователя $username? (y/n): " -n 1 -r + echo + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + yellow "Удаление отменено" + return + fi + + # Удаляем пользователя + sed -i "/^$username:/d" "$USERS_FILE" + + # Удаляем файл со ссылкой если существует + if [[ -f "/root/hysteria2_${username}.txt" ]]; then + rm "/root/hysteria2_${username}.txt" + fi + + # Обновляем конфиг + if update_hysteria_config; then + green "Пользователь $username успешно удален!" + else + red "Ошибка при обновлении конфигурации" + fi +} + +# Функция показа списка пользователей +list_users() { + if [[ ! -f "$USERS_FILE" ]]; then + yellow "Нет пользователей" + return + fi + + echo + cyan "=== Список пользователей Hysteria2 ===" + echo "----------------------------------------" + printf "%-20s | %-30s | %s\n" "Имя пользователя" "Пароль" "Файл ссылки" + echo "----------------------------------------" + + local count=0 + while IFS=: read -r username password; do + if [[ -n "$username" && "$username" != "_placeholder" ]]; then + link_file="/root/hysteria2_${username}.txt" + if [[ -f "$link_file" ]]; then + file_status="✓ есть" + else + file_status="✗ нет" + fi + printf "%-20s | %-30s | %s\n" "$username" "$password" "$file_status" + ((count++)) + fi + done < "$USERS_FILE" + + echo "----------------------------------------" + green "Всего пользователей: $count" + echo +} + +# Функция показа ссылок пользователей +show_links() { + if [[ ! -f "$USERS_FILE" ]]; then + red "Нет пользователей" + return + fi + + echo + cyan "=== Ссылки для подключения ===" + echo + + while IFS=: read -r username password; do + if [[ -n "$username" && "$username" != "_placeholder" ]]; then + echo "----------------------------------------" + yellow "Пользователь: $username" + local user_link=$(generate_user_link "$username" "$password") + echo "$user_link" + echo + fi + done < "$USERS_FILE" +} + +# Функция показа QR-кодов +show_qrcodes() { + if [[ ! -f "$USERS_FILE" ]]; then + red "Нет пользователей" + return + fi + + if ! command -v qrencode &> /dev/null; then + red "qrencode не установлен" + ${PACKAGE_INSTALL[int]} qrencode + fi + + echo + cyan "=== QR-коды для подключения ===" + echo + + while IFS=: read -r username password; do + if [[ -n "$username" && "$username" != "_placeholder" ]]; then + echo "----------------------------------------" + yellow "Пользователь: $username" + local user_link=$(generate_user_link "$username" "$password") + qrencode -t ANSIUTF8 "$user_link" + echo + fi + done < "$USERS_FILE" +} + +# Функция проверки статуса +check_status() { + echo + cyan "=== Статус Hysteria2 ===" + echo + + if [[ -f /usr/local/bin/hysteria ]]; then + green "✓ Hysteria2 установлен" + + if systemctl is-active hysteria-server > /dev/null; then + green "✓ Сервис запущен" + else + red "✗ Сервис остановлен" + fi + + if systemctl is-enabled hysteria-server > /dev/null 2>&1; then + green "✓ Сервис добавлен в автозагрузку" + else + yellow "✗ Сервис не в автозагрузке" + fi + + # Показываем версию + local version=$(/usr/local/bin/hysteria version 2>/dev/null | head -1) + if [[ -n "$version" ]]; then + green "Версия: $version" + fi + + # Показываем основную информацию + echo + cyan "Информация о сервере:" + echo "----------------------------------------" + echo "IP адрес: $(get_ip)" + echo "SNI: $(get_sni)" + echo "Порт: 443" + echo "OBFS пароль: $(get_obfs_password)" + echo "Количество пользователей: $(grep -c "^[^_]" "$USERS_FILE" 2>/dev/null || echo 0)" + echo "----------------------------------------" + else + red "✗ Hysteria2 не установлен" + fi +} + +# Функция перезапуска сервиса +restart_service() { + if [[ ! -f /usr/local/bin/hysteria ]]; then + red "Hysteria2 не установлен!" + return + fi + + yellow "Перезапуск сервиса Hysteria2..." + systemctl restart hysteria-server + + if systemctl is-active hysteria-server > /dev/null; then + green "✓ Сервис успешно перезапущен" + else + red "✗ Ошибка при перезапуске сервиса" + fi +} + +# Функция просмотра логов +view_logs() { + if [[ ! -f /usr/local/bin/hysteria ]]; then + red "Hysteria2 не установлен!" + return + fi + + yellow "Просмотр логов Hysteria2 (Ctrl+C для выхода):" + journalctl -u hysteria-server -f -n 50 +} + +# Функция полного удаления Hysteria2 +uninstall_hysteria() { + echo + cyan "=== Удаление Hysteria2 ===" + echo + + if [[ ! -f /usr/local/bin/hysteria ]]; then + red "Hysteria2 не установлен!" + return + fi + + # Подтверждение + read -p "Вы уверены, что хотите полностью удалить Hysteria2? (y/n): " -n 1 -r + echo + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + yellow "Удаление отменено" + return + fi + + yellow "Останавливаем сервис..." + systemctl stop hysteria-server + systemctl disable hysteria-server + + yellow "Удаляем файлы..." + rm -f /usr/local/bin/hysteria + rm -f /etc/systemd/system/hysteria-server.service systemctl daemon-reload - systemctl enable hysteria-server + + read -p "Удалить конфигурационные файлы и данные пользователей? (y/n): " -n 1 -r + echo + if [[ $REPLY =~ ^[Yy]$ ]]; then + rm -rf "$CONFIG_DIR" + rm -f /root/hysteria2_*.txt + green "Конфигурация и данные пользователей удалены" + else + green "Конфигурация сохранена в $CONFIG_DIR" + fi + + green "Hysteria2 успешно удален!" +} + +# Функция резервного копирования +backup_config() { + if [[ ! -f "$CONFIG_DIR/config.yaml" ]]; then + red "Конфигурация не найдена!" + return + fi + + local backup_dir="/root/hysteria_backup_$(date +%Y%m%d_%H%M%S)" + mkdir -p "$backup_dir" + + cp -r "$CONFIG_DIR" "$backup_dir/" + if [[ -f "$USERS_FILE" ]]; then + cp "$USERS_FILE" "$backup_dir/" + fi + + green "Резервная копия создана в: $backup_dir" +} + +# Функция восстановления из резервной копии +restore_backup() { + echo + cyan "=== Восстановление из резервной копии ===" + echo + + local backups=(/root/hysteria_backup_*) + + if [[ ${#backups[@]} -eq 0 ]] || [[ ! -d "${backups[0]}" ]]; then + red "Резервные копии не найдены" + return + fi + + echo "Доступные резервные копии:" + for i in "${!backups[@]}"; do + echo "$((i+1)). ${backups[$i]}" + done + + echo + read -p "Выберите номер резервной копии для восстановления: " choice + + if [[ ! "$choice" =~ ^[0-9]+$ ]] || [[ "$choice" -lt 1 ]] || [[ "$choice" -gt ${#backups[@]} ]]; then + red "Неверный выбор" + return + fi + + local selected_backup="${backups[$((choice-1))]}" + + # Останавливаем сервис + systemctl stop hysteria-server + + # Восстанавливаем файлы + cp -r "$selected_backup/hysteria/"* "$CONFIG_DIR/" 2>/dev/null + if [[ -f "$selected_backup/users.txt" ]]; then + cp "$selected_backup/users.txt" "$USERS_FILE" + fi + + # Запускаем сервис systemctl start hysteria-server - sleep 2 - if systemctl is-active --quiet hysteria-server; then - green "Служба Hysteria2 успешно запущена" - else - red "Ошибка запуска службы Hysteria2" - systemctl status hysteria-server - exit 1 + green "Восстановление завершено!" +} + +# Функция изменения SNI +change_sni() { + if [[ ! -f "$CONFIG_DIR/config.yaml" ]]; then + red "Конфигурация не найдена!" + return fi -} - -show_config() { - if command -v qrencode &> /dev/null; then - green "=== QR Code ===" - qrencode -t ANSIUTF8 "$(cat /root/hysteria2.txt)" - else - yellow "Установите qrencode для генерации QR кода: apt install qrencode / yum install qrencode" + + echo + cyan "=== Изменение SNI ===" + echo + + local current_sni=$(get_sni) + yellow "Текущий SNI: $current_sni" + + read -p "Введите новый SNI (например: web.max.ru): " new_sni + + if [[ -z "$new_sni" ]]; then + red "SNI не может быть пустым" + return fi -} - -uninstall_hysteria() { - red "Удаление Hysteria2..." - systemctl stop hysteria-server 2>/dev/null || true - systemctl disable hysteria-server 2>/dev/null || true - rm -f /etc/systemd/system/hysteria-server.service - rm -f /usr/local/bin/hysteria - rm -rf /etc/hysteria - rm -f /root/hysteria2.txt - systemctl daemon-reload + # Обновляем конфиг + sed -i "s|url: https://[^/]*|url: https://$new_sni|" "$CONFIG_DIR/config.yaml" - green "Hysteria2 полностью удален!" + # Обновляем сертификат + openssl req -new -x509 -days 36500 -key "$CONFIG_DIR/private.key" -out "$CONFIG_DIR/cert.crt" -subj "/CN=$new_sni" + + # Перезапускаем сервис + systemctl restart hysteria-server + + green "SNI изменен на: $new_sni" } -check_hysteria_installed() { - [[ -f "/usr/local/bin/hysteria" ]] +# Функция отображения меню +show_menu() { + clear + echo "======================================================" + blue " Hysteria2 Management Script" + echo "======================================================" + echo + + if [[ -f /usr/local/bin/hysteria ]]; then + green "✓ Hysteria2 установлен" + if systemctl is-active hysteria-server > /dev/null; then + green "✓ Сервис запущен" + else + red "✗ Сервис остановлен" + fi + else + red "✗ Hysteria2 не установлен" + fi + echo + + cyan "Основные операции:" + echo "1) 📦 Установить Hysteria2" + echo "2) 🗑️ Полностью удалить Hysteria2" + echo + + cyan "Управление пользователями:" + echo "3) ➕ Добавить пользователя" + echo "4) ❌ Удалить пользователя" + echo "5) 📋 Список пользователей" + echo "6) 🔗 Показать ссылки" + echo "7) 📱 Показать QR-коды" + echo + + cyan "Управление сервисом:" + echo "8) 🔄 Перезапустить сервис" + echo "9) 📊 Статус и информация" + echo "10) 📜 Просмотр логов" + echo + + cyan "Дополнительно:" + echo "11) 💾 Создать резервную копию" + echo "12) 🔄 Восстановить из резервной копии" + echo "13) 🌐 Изменить SNI" + echo + + cyan "Прочее:" + echo "0) 🚪 Выход" + echo + echo "======================================================" } +# Основной цикл программы main() { - if check_hysteria_installed; then - red "Hysteria2 уже установлен!" + while true; do + show_menu + read -p "Выберите действие (0-13): " choice echo - read -p "Хотите переустановить? [y/N]: " reinstall - case $reinstall in - [yY]|[yY][eE][sS]) + + case $choice in + 1) + install_hysteria + ;; + 2) uninstall_hysteria ;; - *) - echo "Выход..." + 3) + add_user + ;; + 4) + delete_user + ;; + 5) + list_users + ;; + 6) + show_links + ;; + 7) + show_qrcodes + ;; + 8) + restart_service + ;; + 9) + check_status + ;; + 10) + view_logs + ;; + 11) + backup_config + ;; + 12) + restore_backup + ;; + 13) + change_sni + ;; + 0) + green "Выход..." exit 0 ;; + *) + red "Неверный выбор! Пожалуйста, выберите 0-13" + ;; esac - fi - - install_server_core - configure_hysteria - start_service - show_config - - echo - green "Установка Hysteria2 успешно завершена!" - echo - yellow "Конфиг клиента: /root/hysteria2.txt" - yellow "Перезапуск службы: systemctl restart hysteria-server" - yellow "Проверка статуса: systemctl status hysteria-server" - echo - yellow "Hysteria2 ключ:" - cat /root/hysteria2.txt - echo - echo "Инструкции по настройке VPN приложений:" - echo "https://github.com/YukiKras/wiki/blob/main/nastroikavpn.md" + + echo + read -p "Нажмите Enter для продолжения..." + done } +# Запуск основной программы main \ No newline at end of file