901 lines
28 KiB
Bash
Executable File
901 lines
28 KiB
Bash
Executable File
#!/bin/bash
|
||
|
||
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(){
|
||
echo -e "\033[31m\033[01m$1\033[0m"
|
||
}
|
||
|
||
green(){
|
||
echo -e "\033[32m\033[01m$1\033[0m"
|
||
}
|
||
|
||
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=*)
|
||
CUSTOM_SNI="${arg#*=}"
|
||
shift
|
||
;;
|
||
--help)
|
||
echo "Использование: $0 [--custom-sni=example.com]"
|
||
echo ""
|
||
echo "Опции:"
|
||
echo " --custom-sni=HOSTNAME Указать свой SNI хост (по умолчанию: web.max.ru)"
|
||
echo " --help Показать эту справку"
|
||
exit 0
|
||
;;
|
||
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")
|
||
PACKAGE_INSTALL=("apt -y install" "apt -y install" "yum -y install" "yum -y install" "yum -y install" "apk add -f")
|
||
|
||
CMD=("$(grep -i pretty_name /etc/os-release 2>/dev/null | cut -d \" -f2)" "$(hostnamectl 2>/dev/null | grep -i system | cut -d : -f2)" "$(lsb_release -sd 2>/dev/null)" "$(grep -i description /etc/lsb-release 2>/dev/null | cut -d \" -f2)" "$(grep . /etc/redhat-release 2>/dev/null)" "$(grep . /etc/issue 2>/dev/null | cut -d \\ -f1 | sed '/^[ ]*$/d')")
|
||
|
||
for i in "${CMD[@]}"; do
|
||
SYS="$i" && [[ -n $SYS ]] && break
|
||
done
|
||
|
||
for ((int = 0; int < ${#REGEX[@]}; int++)); do
|
||
[[ $(echo "$SYS" | tr '[:upper:]' '[:lower:]') =~ ${REGEX[int]} ]] && SYSTEM="${RELEASE[int]}" && [[ -n $SYSTEM ]] && break
|
||
done
|
||
|
||
[[ -z $SYSTEM ]] && red "Текущая система VPS не поддерживается, используйте основную операционную систему" && exit 1
|
||
|
||
# Функция для установки необходимых пакетов
|
||
install_dependencies() {
|
||
if [[ -z $(type -P curl) ]]; then
|
||
if [[ ! $SYSTEM == "CentOS" ]]; then
|
||
${PACKAGE_UPDATE[int]}
|
||
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 2>/dev/null) || ip=$(curl -s6m8 ip.sb -k 2>/dev/null)
|
||
echo "$ip"
|
||
}
|
||
|
||
# Функция для генерации пароля
|
||
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)
|
||
|
||
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"
|
||
}
|
||
|
||
# Функция для сохранения ссылки пользователя в файл
|
||
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"
|
||
}
|
||
|
||
# Функция для обновления конфигурации 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
|
||
}
|
||
|
||
# Функция установки 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' ;;
|
||
*)
|
||
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
|
||
After=network.target
|
||
|
||
[Service]
|
||
Type=simple
|
||
ExecStart=/usr/local/bin/hysteria server --config /etc/hysteria/config.yaml
|
||
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
|
||
|
||
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..."
|
||
|
||
if [[ -n "$CUSTOM_SNI" ]]; then
|
||
local sni_host="$CUSTOM_SNI"
|
||
yellow "Используется кастомный SNI: $sni_host"
|
||
else
|
||
local sni_host="web.max.ru"
|
||
yellow "Используется SNI по умолчанию: $sni_host"
|
||
fi
|
||
|
||
local masquerade_url="$sni_host"
|
||
local port="443"
|
||
local obfs_pwd=$(generate_password)
|
||
|
||
# Генерируем 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: $CONFIG_DIR/cert.crt
|
||
key: $CONFIG_DIR/private.key
|
||
|
||
obfs:
|
||
type: salamander
|
||
salamander:
|
||
password: $obfs_pwd
|
||
|
||
auth:
|
||
type: userpass
|
||
userpass:
|
||
_placeholder: "_placeholder"
|
||
|
||
masquerade:
|
||
type: proxy
|
||
proxy:
|
||
url: https://$masquerade_url
|
||
rewriteHost: true
|
||
|
||
quic:
|
||
initStreamReceiveWindow: 16777216
|
||
maxStreamReceiveWindow: 16777216
|
||
initConnReceiveWindow: 33554432
|
||
maxConnReceiveWindow: 33554432
|
||
EOF
|
||
|
||
green "Базовая конфигурация создана"
|
||
}
|
||
|
||
# Функция добавления пользователя
|
||
add_user() {
|
||
if [[ ! -f /usr/local/bin/hysteria ]]; then
|
||
red "Hysteria2 не установлен! Сначала выполните установку."
|
||
return
|
||
fi
|
||
|
||
echo
|
||
cyan "=== Добавление нового пользователя ==="
|
||
echo
|
||
|
||
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
|
||
}
|
||
|
||
# Функция удаления пользователя
|
||
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
|
||
|
||
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
|
||
|
||
green "Восстановление завершено!"
|
||
}
|
||
|
||
# Функция изменения SNI
|
||
change_sni() {
|
||
if [[ ! -f "$CONFIG_DIR/config.yaml" ]]; then
|
||
red "Конфигурация не найдена!"
|
||
return
|
||
fi
|
||
|
||
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
|
||
|
||
# Обновляем конфиг
|
||
sed -i "s|url: https://[^/]*|url: https://$new_sni|" "$CONFIG_DIR/config.yaml"
|
||
|
||
# Обновляем сертификат
|
||
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"
|
||
}
|
||
|
||
# Функция отображения меню
|
||
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() {
|
||
while true; do
|
||
show_menu
|
||
read -p "Выберите действие (0-13): " choice
|
||
echo
|
||
|
||
case $choice in
|
||
1)
|
||
install_hysteria
|
||
;;
|
||
2)
|
||
uninstall_hysteria
|
||
;;
|
||
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
|
||
|
||
echo
|
||
read -p "Нажмите Enter для продолжения..."
|
||
done
|
||
}
|
||
|
||
# Запуск основной программы
|
||
main |