Files

623 lines
19 KiB
Bash
Executable File

#!/bin/bash
# VPN Panel Management Script
# Version: 2.0.0
# Author: houseassassin
# GitHub: https://github.com/houseassassin/proxy-core
# Управление установленными панелями
set -euo pipefail
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
log() { echo -e "${GREEN}[INFO]${NC} $1"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
error() { echo -e "${RED}[ERROR]${NC} $1"; }
success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; }
get_server_ip() {
curl -s -4 ifconfig.me || curl -s -4 api.ipify.org || curl -s -4 ipinfo.io/ip
}
validate_client_name() {
local client_name=$1
[[ "$client_name" =~ ^[a-zA-Z0-9_-]+$ ]]
}
remove_wg_peer_block() {
local client_name=$1
local tmp_conf
tmp_conf="$(mktemp)"
awk -v marker="# ${client_name}" '
BEGIN {skip=0}
$0 == marker {skip=1; next}
skip && /^\[Peer\]/ {skip=0}
!skip {print}
' /etc/wireguard/wg0.conf > "$tmp_conf"
mv "$tmp_conf" /etc/wireguard/wg0.conf
}
run_remote_script() {
local url=$1
local tmp_script
tmp_script="$(mktemp /tmp/proxy-core-remote.XXXXXX.sh)"
curl -fsSL "$url" -o "$tmp_script"
chmod 700 "$tmp_script"
bash "$tmp_script"
rm -f "$tmp_script"
}
# WireGuard Management
manage_wireguard() {
if ! systemctl is-active --quiet wg-quick@wg0; then
error "WireGuard не установлен или не запущен"
return 1
fi
while true; do
clear
echo -e "${BLUE}╔════════════════════════════════════════╗${NC}"
echo -e "${BLUE}║ WireGuard Management ║${NC}"
echo -e "${BLUE}╚════════════════════════════════════════╝${NC}"
echo ""
echo -e "${YELLOW}1.${NC} Показать статус"
echo -e "${YELLOW}2.${NC} Добавить клиента"
echo -e "${YELLOW}3.${NC} Список клиентов"
echo -e "${YELLOW}4.${NC} Удалить клиента"
echo -e "${YELLOW}5.${NC} Показать QR-код"
echo -e "${YELLOW}6.${NC} Перезапустить сервис"
echo -e "${YELLOW}0.${NC} Назад"
echo ""
read -p "Выберите опцию: " choice
case $choice in
1)
echo ""
systemctl status wg-quick@wg0 --no-pager
wg show
read -p "Нажмите Enter..."
;;
2)
add_wireguard_client
;;
3)
list_wireguard_clients
;;
4)
remove_wireguard_client
;;
5)
show_wireguard_qr
;;
6)
systemctl restart wg-quick@wg0
success "WireGuard перезапущен"
sleep 2
;;
0)
return 0
;;
*)
warn "Неверный выбор"
sleep 1
;;
esac
done
}
add_wireguard_client() {
read -p "Введите имя клиента: " CLIENT_NAME
if [ -z "$CLIENT_NAME" ]; then
error "Имя не может быть пустым"
return 1
fi
if ! validate_client_name "$CLIENT_NAME"; then
error "Неверное имя: только буквы, цифры, _ и -"
return 1
fi
CLIENT_DIR="/etc/wireguard/clients/$CLIENT_NAME"
if [ -d "$CLIENT_DIR" ]; then
error "Клиент $CLIENT_NAME уже существует"
return 1
fi
mkdir -p "$CLIENT_DIR"
cd "$CLIENT_DIR"
# Generate keys
wg genkey | tee private.key | wg pubkey > public.key
chmod 600 private.key
CLIENT_PRIVATE_KEY=$(cat private.key)
CLIENT_PUBLIC_KEY=$(cat public.key)
SERVER_PUBLIC_KEY=$(cat /etc/wireguard/server_public.key)
SERVER_IP=$(get_server_ip)
SERVER_PORT=$(grep ListenPort /etc/wireguard/wg0.conf | awk '{print $3}')
# Get next available IP
LAST_IP=$(grep "AllowedIPs" /etc/wireguard/wg0.conf | grep -oE "10\.0\.0\.[0-9]+" | sort -t . -k 4 -n | tail -1)
if [ -z "$LAST_IP" ]; then
CLIENT_IP="10.0.0.2"
else
LAST_NUM=$(echo $LAST_IP | cut -d. -f4)
NEXT_NUM=$((LAST_NUM + 1))
if [ "$NEXT_NUM" -gt 254 ]; then
error "Пул адресов WireGuard исчерпан (10.0.0.2-10.0.0.254)"
return 1
fi
CLIENT_IP="10.0.0.$NEXT_NUM"
fi
# Add peer to server config
cat >> /etc/wireguard/wg0.conf <<EOF
[Peer]
# $CLIENT_NAME
PublicKey = $CLIENT_PUBLIC_KEY
AllowedIPs = $CLIENT_IP/32
EOF
# Create client config
cat > client.conf <<EOF
[Interface]
PrivateKey = $CLIENT_PRIVATE_KEY
Address = $CLIENT_IP/24
DNS = 8.8.8.8, 1.1.1.1
[Peer]
PublicKey = $SERVER_PUBLIC_KEY
Endpoint = $SERVER_IP:$SERVER_PORT
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 25
EOF
systemctl restart wg-quick@wg0
success "Клиент $CLIENT_NAME создан"
log "IP адрес: $CLIENT_IP"
log "Конфигурация: $CLIENT_DIR/client.conf"
echo ""
log "QR-код для мобильных устройств:"
if command -v qrencode >/dev/null 2>&1; then
qrencode -t ansiutf8 < client.conf
else
warn "qrencode не установлен, пропускаем QR-код"
fi
echo ""
read -p "Нажмите Enter..."
}
list_wireguard_clients() {
echo ""
log "Список клиентов WireGuard:"
echo ""
if [ ! -d "/etc/wireguard/clients" ]; then
warn "Клиенты не найдены"
read -p "Нажмите Enter..."
return
fi
for client in /etc/wireguard/clients/*; do
if [ -d "$client" ]; then
CLIENT_NAME=$(basename "$client")
CLIENT_IP=$(grep -A 2 "# $CLIENT_NAME" /etc/wireguard/wg0.conf | grep AllowedIPs | awk '{print $3}' | cut -d/ -f1)
echo -e "${GREEN}${NC} $CLIENT_NAME ${BLUE}($CLIENT_IP)${NC}"
fi
done
echo ""
read -p "Нажмите Enter..."
}
remove_wireguard_client() {
read -p "Введите имя клиента для удаления: " CLIENT_NAME
if [ -z "$CLIENT_NAME" ]; then
error "Имя не может быть пустым"
return 1
fi
if ! validate_client_name "$CLIENT_NAME"; then
error "Неверное имя: только буквы, цифры, _ и -"
return 1
fi
CLIENT_DIR="/etc/wireguard/clients/$CLIENT_NAME"
if [ ! -d "$CLIENT_DIR" ]; then
error "Клиент $CLIENT_NAME не найден"
return 1
fi
remove_wg_peer_block "$CLIENT_NAME"
rm -rf "$CLIENT_DIR"
systemctl restart wg-quick@wg0
success "Клиент $CLIENT_NAME удален"
sleep 2
}
show_wireguard_qr() {
read -p "Введите имя клиента: " CLIENT_NAME
if [ -z "$CLIENT_NAME" ]; then
error "Имя не может быть пустым"
return 1
fi
if ! validate_client_name "$CLIENT_NAME"; then
error "Неверное имя: только буквы, цифры, _ и -"
return 1
fi
CLIENT_DIR="/etc/wireguard/clients/$CLIENT_NAME"
if [ ! -d "$CLIENT_DIR" ]; then
error "Клиент $CLIENT_NAME не найден"
return 1
fi
echo ""
log "Конфигурация клиента $CLIENT_NAME:"
cat "$CLIENT_DIR/client.conf"
echo ""
log "QR-код:"
if command -v qrencode >/dev/null 2>&1; then
qrencode -t ansiutf8 < "$CLIENT_DIR/client.conf"
else
warn "qrencode не установлен, пропускаем QR-код"
fi
echo ""
read -p "Нажмите Enter..."
}
# 3x-ui Management
manage_3xui() {
if ! command -v x-ui &> /dev/null; then
error "3x-ui не установлен"
return 1
fi
while true; do
clear
echo -e "${BLUE}╔════════════════════════════════════════╗${NC}"
echo -e "${BLUE}║ 3x-ui Management ║${NC}"
echo -e "${BLUE}╚════════════════════════════════════════╝${NC}"
echo ""
echo -e "${YELLOW}1.${NC} Показать статус"
echo -e "${YELLOW}2.${NC} Запустить"
echo -e "${YELLOW}3.${NC} Остановить"
echo -e "${YELLOW}4.${NC} Перезапустить"
echo -e "${YELLOW}5.${NC} Показать логи"
echo -e "${YELLOW}6.${NC} Обновить"
echo -e "${YELLOW}7.${NC} Сбросить пароль"
echo -e "${YELLOW}0.${NC} Назад"
echo ""
read -p "Выберите опцию: " choice
case $choice in
1)
x-ui status
read -p "Нажмите Enter..."
;;
2)
x-ui start
success "3x-ui запущен"
sleep 2
;;
3)
x-ui stop
success "3x-ui остановлен"
sleep 2
;;
4)
x-ui restart
success "3x-ui перезапущен"
sleep 2
;;
5)
x-ui log
;;
6)
run_remote_script "https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh"
success "3x-ui обновлен"
sleep 2
;;
7)
x-ui reset
;;
0)
return 0
;;
*)
warn "Неверный выбор"
sleep 1
;;
esac
done
}
# Remnawave Management
manage_remnawave() {
if [ ! -d "/opt/remnawave" ]; then
error "Remnawave не установлен"
return 1
fi
while true; do
clear
echo -e "${BLUE}╔════════════════════════════════════════╗${NC}"
echo -e "${BLUE}║ Remnawave Management ║${NC}"
echo -e "${BLUE}╚════════════════════════════════════════╝${NC}"
echo ""
echo -e "${YELLOW}1.${NC} Показать статус"
echo -e "${YELLOW}2.${NC} Запустить все сервисы"
echo -e "${YELLOW}3.${NC} Остановить все сервисы"
echo -e "${YELLOW}4.${NC} Перезапустить все сервисы"
echo -e "${YELLOW}5.${NC} Показать логи"
echo -e "${YELLOW}6.${NC} Обновить"
echo -e "${YELLOW}7.${NC} Резервное копирование"
echo -e "${YELLOW}8.${NC} Восстановить из бэкапа"
echo -e "${YELLOW}0.${NC} Назад"
echo ""
read -p "Выберите опцию: " choice
case $choice in
1)
cd /opt/remnawave
docker compose ps
read -p "Нажмите Enter..."
;;
2)
cd /opt/remnawave
docker compose up -d
success "Сервисы запущены"
sleep 2
;;
3)
cd /opt/remnawave
docker compose down
success "Сервисы остановлены"
sleep 2
;;
4)
cd /opt/remnawave
docker compose restart
success "Сервисы перезапущены"
sleep 2
;;
5)
cd /opt/remnawave
docker compose logs -f
;;
6)
cd /opt/remnawave
docker compose pull
docker compose up -d
success "Remnawave обновлен"
sleep 2
;;
7)
backup_remnawave
;;
8)
restore_remnawave
;;
0)
return 0
;;
*)
warn "Неверный выбор"
sleep 1
;;
esac
done
}
backup_remnawave() {
local BACKUP_DIR="/root/remnawave-backups"
local TIMESTAMP=$(date +%Y%m%d_%H%M%S)
local BACKUP_FILE="$BACKUP_DIR/remnawave_backup_$TIMESTAMP.tar.gz"
mkdir -p "$BACKUP_DIR"
log "Создание резервной копии..."
cd /opt/remnawave
docker compose down
tar -czf "$BACKUP_FILE" \
-C /opt remnawave \
--exclude='remnawave/logs' \
--exclude='remnawave/node_modules'
docker compose up -d
success "Резервная копия создана: $BACKUP_FILE"
read -p "Нажмите Enter..."
}
restore_remnawave() {
local BACKUP_DIR="/root/remnawave-backups"
if [ ! -d "$BACKUP_DIR" ] || [ -z "$(ls -A $BACKUP_DIR)" ]; then
error "Резервные копии не найдены"
read -p "Нажмите Enter..."
return 1
fi
echo ""
log "Доступные резервные копии:"
echo ""
local i=1
declare -A backups
for backup in "$BACKUP_DIR"/*.tar.gz; do
echo -e "${YELLOW}$i.${NC} $(basename $backup)"
backups[$i]="$backup"
((i++))
done
echo ""
read -p "Выберите номер резервной копии: " choice
if [ -z "${backups[$choice]}" ]; then
error "Неверный выбор"
return 1
fi
local BACKUP_FILE="${backups[$choice]}"
warn "Это удалит текущую установку Remnawave!"
read -p "Продолжить? (y/N): " confirm
if [[ "$confirm" != "y" && "$confirm" != "Y" ]]; then
log "Отменено"
return 0
fi
log "Восстановление из резервной копии..."
cd /opt/remnawave
docker compose down
rm -rf /opt/remnawave
tar -xzf "$BACKUP_FILE" -C /opt
cd /opt/remnawave
docker compose up -d
success "Восстановление завершено"
read -p "Нажмите Enter..."
}
# Hysteria2 Management
manage_hysteria2() {
if ! systemctl cat hysteria-server.service &> /dev/null; then
error "Hysteria2 не установлен"
return 1
fi
while true; do
clear
echo -e "${BLUE}╔════════════════════════════════════════╗${NC}"
echo -e "${BLUE}║ Hysteria2 Management ║${NC}"
echo -e "${BLUE}╚════════════════════════════════════════╝${NC}"
echo ""
echo -e "${YELLOW}1.${NC} Показать статус"
echo -e "${YELLOW}2.${NC} Запустить"
echo -e "${YELLOW}3.${NC} Остановить"
echo -e "${YELLOW}4.${NC} Перезапустить"
echo -e "${YELLOW}5.${NC} Показать конфигурацию"
echo -e "${YELLOW}6.${NC} Редактировать конфигурацию"
echo -e "${YELLOW}0.${NC} Назад"
echo ""
read -p "Выберите опцию: " choice
case $choice in
1)
systemctl status hysteria-server.service --no-pager
read -p "Нажмите Enter..."
;;
2)
systemctl start hysteria-server.service
success "Hysteria2 запущен"
sleep 2
;;
3)
systemctl stop hysteria-server.service
success "Hysteria2 остановлен"
sleep 2
;;
4)
systemctl restart hysteria-server.service
success "Hysteria2 перезапущен"
sleep 2
;;
5)
cat /etc/hysteria/config.yaml
read -p "Нажмите Enter..."
;;
6)
${EDITOR:-nano} /etc/hysteria/config.yaml
systemctl restart hysteria-server.service
success "Конфигурация обновлена"
sleep 2
;;
0)
return 0
;;
*)
warn "Неверный выбор"
sleep 1
;;
esac
done
}
# Main menu
main_menu() {
while true; do
clear
echo -e "${BLUE}╔════════════════════════════════════════╗${NC}"
echo -e "${BLUE}║ VPN Panel Management ║${NC}"
echo -e "${BLUE}╚════════════════════════════════════════╝${NC}"
echo ""
echo -e "${YELLOW}1.${NC} Управление WireGuard"
echo -e "${YELLOW}2.${NC} Управление 3x-ui"
echo -e "${YELLOW}3.${NC} Управление Remnawave"
echo -e "${YELLOW}4.${NC} Управление Hysteria2"
echo -e "${YELLOW}5.${NC} Системная информация"
echo -e "${YELLOW}0.${NC} Выход"
echo ""
read -p "Выберите опцию: " choice
case $choice in
1) manage_wireguard ;;
2) manage_3xui ;;
3) manage_remnawave ;;
4) manage_hysteria2 ;;
5)
clear
echo -e "${GREEN}Системная информация:${NC}"
echo ""
echo -e "${BLUE}IP адрес:${NC} $(curl -s ifconfig.me)"
echo -e "${BLUE}ОС:${NC} $(cat /etc/os-release | grep PRETTY_NAME | cut -d'"' -f2)"
echo -e "${BLUE}Ядро:${NC} $(uname -r)"
echo -e "${BLUE}Uptime:${NC} $(uptime -p)"
echo -e "${BLUE}RAM:${NC} $(free -h | grep Mem: | awk '{print $3 "/" $2}')"
echo -e "${BLUE}Disk:${NC} $(df -h / | tail -1 | awk '{print $3 "/" $2 " (" $5 ")"}')"
echo ""
read -p "Нажмите Enter..."
;;
0)
log "Выход"
exit 0
;;
*)
warn "Неверный выбор"
sleep 1
;;
esac
done
}
# Check root
if [[ $EUID -ne 0 ]]; then
error "Этот скрипт должен быть запущен с правами root"
exit 1
fi
main_menu