rProxy/rproxy

795 lines
29 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/sh
# rProxy — Менеджер обратного прокси для роутеров Keenetic
# Публикация локальных сервисов через SSH-туннели + nginx на VPS
# http://5.104.75.50:3000/Petro1990/rProxy
VERSION="1.0.0"
CONF_DIR="/opt/etc/rproxy"
CONF_FILE="$CONF_DIR/rproxy.conf"
SERVICES_DIR="$CONF_DIR/services"
PID_DIR="/opt/var/run/rproxy"
SSH_KEY="$CONF_DIR/id_rsa"
REMOTE_NGINX_DIR="/etc/nginx/sites-enabled"
BASE_TUNNEL_PORT=10000
# ─── Цвета ───────────────────────────────────────────────────────────
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
BOLD='\033[1m'
DIM='\033[2m'
NC='\033[0m'
msg() { printf "${GREEN}${NC} %s\n" "$*"; }
warn() { printf "${YELLOW}${NC} %s\n" "$*"; }
err() { printf "${RED}${NC} %s\n" "$*" >&2; }
header() { printf "\n${CYAN}${BOLD}%s${NC}\n" "$*"; }
# ─── Утилиты ─────────────────────────────────────────────────────────
clear_screen() { printf "\033[2J\033[H"; }
draw_box() {
local title="$1"
printf "${CYAN}╔══════════════════════════════════════════════╗${NC}\n"
printf "${CYAN}${NC} ${BOLD}%-44s${NC}${CYAN}${NC}\n" "$title"
printf "${CYAN}╚══════════════════════════════════════════════╝${NC}\n"
}
draw_separator() {
printf "${DIM}──────────────────────────────────────────────────${NC}\n"
}
prompt() {
printf "\n${CYAN}${NC} $1"
read -r REPLY
}
pause() {
printf "\n${DIM}Нажмите Enter для продолжения...${NC}"
read -r _
}
check_conf() {
if [ ! -f "$CONF_FILE" ]; then
return 1
fi
. "$CONF_FILE"
return 0
}
load_service() {
local svc_file="$SERVICES_DIR/$1.conf"
if [ ! -f "$svc_file" ]; then
err "Сервис '$1' не найден"
return 1
fi
. "$svc_file"
}
ssh_cmd() {
if [ "$VPS_AUTH" = "password" ]; then
if ! command -v sshpass >/dev/null 2>&1; then
err "Утилита sshpass не найдена. Авторизация по паролю невозможна."
err "Пожалуйста, перенастройте rProxy на использование SSH-ключа (rproxy setup)."
return 1
fi
sshpass -p "$VPS_PASS" ssh -o StrictHostKeyChecking=no -p "$VPS_PORT" "$VPS_USER@$VPS_HOST" "$@"
else
ssh -o StrictHostKeyChecking=no -i "$SSH_KEY" -p "$VPS_PORT" "$VPS_USER@$VPS_HOST" "$@"
fi
}
scp_cmd() {
if [ "$VPS_AUTH" = "password" ]; then
if ! command -v sshpass >/dev/null 2>&1; then
err "Утилита sshpass не найдена. Копирование по паролю невозможно."
return 1
fi
sshpass -p "$VPS_PASS" scp -o StrictHostKeyChecking=no -P "$VPS_PORT" "$@"
else
scp -o StrictHostKeyChecking=no -i "$SSH_KEY" -P "$VPS_PORT" "$@"
fi
}
next_free_port() {
local port=$BASE_TUNNEL_PORT
while true; do
local used=0
for f in "$SERVICES_DIR"/*.conf; do
[ -f "$f" ] || continue
grep -q "TUNNEL_PORT=$port" "$f" && used=1 && break
done
[ "$used" -eq 0 ] && echo "$port" && return
port=$((port + 1))
done
}
get_pid_file() { echo "$PID_DIR/$1.pid"; }
is_running() {
local pf
pf=$(get_pid_file "$1")
[ -f "$pf" ] && kill -0 "$(cat "$pf")" 2>/dev/null
}
count_services() {
local count=0
for f in "$SERVICES_DIR"/*.conf 2>/dev/null; do
[ -f "$f" ] && count=$((count + 1))
done
echo $count
}
# ══════════════════════════════════════════════════════════════════════
# ГЛАВНОЕ МЕНЮ
# ══════════════════════════════════════════════════════════════════════
main_menu() {
while true; do
clear_screen
draw_box "rProxy v$VERSION"
printf "\n"
if ! check_conf; then
printf " ${YELLOW}⚠ VPS не настроен${NC}\n\n"
printf " ${BOLD}1)${NC} Настроить подключение к VPS\n"
printf " ${BOLD}0)${NC} Выход\n"
prompt "Выберите действие: "
case "$REPLY" in
1) do_setup ;;
0|q) printf "\n"; exit 0 ;;
*) ;;
esac
continue
fi
# Подсчёт сервисов и статусов
local total=0 online=0
for f in "$SERVICES_DIR"/*.conf; do
[ -f "$f" ] || continue
total=$((total + 1))
. "$f"
is_running "$SVC_NAME" && online=$((online + 1))
done
printf " ${DIM}VPS:${NC} ${BOLD}$VPS_HOST${NC} "
printf "${DIM}Сервисов:${NC} ${BOLD}$total${NC} "
printf "${DIM}Онлайн:${NC} ${GREEN}${BOLD}$online${NC}\n"
draw_separator
printf "\n"
printf " ${BOLD}1)${NC} 📋 Список сервисов и статус\n"
printf " ${BOLD}2)${NC} Добавить сервис\n"
printf " ${BOLD}3)${NC} ❌ Удалить сервис\n"
draw_separator
printf " ${BOLD}4)${NC} ▶️ Запустить туннель\n"
printf " ${BOLD}5)${NC} ⏹️ Остановить туннель\n"
printf " ${BOLD}6)${NC} 🔄 Перезапустить туннель\n"
draw_separator
printf " ${BOLD}7)${NC} ⚙️ Настройки VPS\n"
printf " ${BOLD}0)${NC} 🚪 Выход\n"
prompt "Выберите действие: "
case "$REPLY" in
1) show_status ;;
2) do_add_interactive ;;
3) do_remove_interactive ;;
4) do_start_interactive ;;
5) do_stop_interactive ;;
6) do_restart_interactive ;;
7) do_setup ;;
0|q) clear_screen; exit 0 ;;
*) ;;
esac
done
}
# ══════════════════════════════════════════════════════════════════════
# СТАТУС
# ══════════════════════════════════════════════════════════════════════
show_status() {
clear_screen
draw_box "Список сервисов"
printf "\n"
local has_services=0
local idx=0
printf " ${BOLD}%-4s %-14s %-22s %-7s %-9s %-18s${NC}\n" "№" "ИМЯ" "ЦЕЛЬ" "ПОРТ" "СТАТУС" "ДОМЕН"
draw_separator
for f in "$SERVICES_DIR"/*.conf 2>/dev/null; do
[ -f "$f" ] || continue
has_services=1
idx=$((idx + 1))
. "$f"
local status_text
if is_running "$SVC_NAME"; then
status_text="${GREEN}● онлайн${NC}"
else
status_text="${RED}○ офлайн${NC}"
fi
local domain_text="${SVC_DOMAIN:-}"
local auto_text=""
[ "$SVC_ENABLED" = "yes" ] && auto_text=" ${DIM}[авто]${NC}"
printf " %-4s %-14s %-22s %-7s ${status_text} %-18s${auto_text}\n" \
"$idx" "$SVC_NAME" "$SVC_TARGET_HOST:$SVC_TARGET_PORT" "$SVC_EXT_PORT" "$domain_text"
done
if [ "$has_services" -eq 0 ]; then
printf "\n ${YELLOW}Нет добавленных сервисов.${NC}\n"
printf " ${DIM}Выберите «Добавить сервис» в главном меню.${NC}\n"
fi
printf "\n"
pause
}
# ══════════════════════════════════════════════════════════════════════
# ДОБАВИТЬ СЕРВИС (интерактивно)
# ══════════════════════════════════════════════════════════════════════
do_add_interactive() {
clear_screen
draw_box "Добавить новый сервис"
printf "\n"
prompt "Название сервиса (латиницей, без пробелов): "
local name="$REPLY"
[ -z "$name" ] && { warn "Название не может быть пустым"; pause; return; }
if [ -f "$SERVICES_DIR/$name.conf" ]; then
err "Сервис '$name' уже существует"
pause
return
fi
prompt "Адрес локального сервиса (например, 192.168.1.100:8080): "
local target="$REPLY"
[ -z "$target" ] && { warn "Адрес не может быть пустым"; pause; return; }
printf "\n Привязать к домену?\n"
printf " ${BOLD}1)${NC} Да — указать доменное имя (порт 80)\n"
printf " ${BOLD}2)${NC} Нет — указать внешний порт\n"
prompt "Выберите [2]: "
local mode="${REPLY:-2}"
local domain=""
local ext_port=""
if [ "$mode" = "1" ]; then
prompt "Доменное имя (например, mysite.example.com): "
domain="$REPLY"
[ -z "$domain" ] && { warn "Домен не указан"; pause; return; }
ext_port=80
else
local suggested
suggested=$(next_free_port)
prompt "Внешний порт [$suggested]: "
ext_port="${REPLY:-$suggested}"
fi
# Разбор адреса
local target_host="${target%:*}"
local target_port="${target#*:}"
if [ "$target_host" = "$target_port" ]; then
target_port="$target_host"
target_host="127.0.0.1"
fi
local tunnel_port
tunnel_port=$(next_free_port)
printf "\n"
draw_separator
printf " ${BOLD}Сервис:${NC} $name\n"
printf " ${BOLD}Цель:${NC} $target_host:$target_port\n"
printf " ${BOLD}Туннель:${NC} порт $tunnel_port\n"
[ -n "$domain" ] && printf " ${BOLD}Домен:${NC} $domain\n"
printf " ${BOLD}Внешний порт:${NC} $ext_port\n"
draw_separator
prompt "Всё верно? Добавить сервис? (д/н) [д]: "
local confirm="${REPLY:-д}"
case "$confirm" in
д|Д|y|Y|да|yes) ;;
*) msg "Отменено"; pause; return ;;
esac
printf "\n"
msg "Добавляю сервис '$name'..."
# Генерация конфига nginx
local nginx_conf=""
if [ -n "$domain" ]; then
nginx_conf="# rProxy: $name
server {
listen 80;
server_name $domain;
location / {
proxy_pass http://127.0.0.1:$tunnel_port;
proxy_http_version 1.1;
proxy_set_header Upgrade \$http_upgrade;
proxy_set_header Connection \"upgrade\";
proxy_set_header Host \$host;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto \$scheme;
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
}
"
else
nginx_conf="# rProxy: $name
server {
listen $ext_port;
location / {
proxy_pass http://127.0.0.1:$tunnel_port;
proxy_http_version 1.1;
proxy_set_header Upgrade \$http_upgrade;
proxy_set_header Connection \"upgrade\";
proxy_set_header Host \$host;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto \$scheme;
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
}
"
fi
# Деплой nginx конфига на VPS
local tmp_file="/tmp/rproxy_nginx_$name.conf"
printf '%s' "$nginx_conf" > "$tmp_file"
scp_cmd "$tmp_file" "$VPS_USER@$VPS_HOST:$REMOTE_NGINX_DIR/rproxy_$name.conf" || {
err "Не удалось загрузить конфиг nginx на VPS"
rm -f "$tmp_file"
pause
return
}
rm -f "$tmp_file"
# Перезагрузка nginx
ssh_cmd "nginx -t && systemctl reload nginx" || {
err "Ошибка конфигурации nginx на VPS"
ssh_cmd "rm -f $REMOTE_NGINX_DIR/rproxy_$name.conf"
pause
return
}
# Сохранение конфига сервиса
cat > "$SERVICES_DIR/$name.conf" <<EOF
# rProxy сервис: $name
SVC_NAME="$name"
SVC_TARGET_HOST="$target_host"
SVC_TARGET_PORT="$target_port"
SVC_TUNNEL_PORT="$tunnel_port"
SVC_EXT_PORT="$ext_port"
SVC_DOMAIN="$domain"
SVC_ENABLED="yes"
EOF
msg "Сервис '$name' добавлен!"
# Автозапуск туннеля
do_start_service "$name"
pause
}
# ══════════════════════════════════════════════════════════════════════
# УДАЛИТЬ СЕРВИС (интерактивно)
# ══════════════════════════════════════════════════════════════════════
do_remove_interactive() {
clear_screen
draw_box "Удалить сервис"
printf "\n"
local services=""
local idx=0
for f in "$SERVICES_DIR"/*.conf 2>/dev/null; do
[ -f "$f" ] || continue
idx=$((idx + 1))
. "$f"
local st="○"
is_running "$SVC_NAME" && st="●"
printf " ${BOLD}%d)${NC} %s %s (%s:%s)\n" "$idx" "$st" "$SVC_NAME" "$SVC_TARGET_HOST" "$SVC_TARGET_PORT"
services="$services $SVC_NAME"
done
if [ "$idx" -eq 0 ]; then
printf " ${YELLOW}Нет сервисов для удаления.${NC}\n"
pause
return
fi
printf " ${BOLD}0)${NC} Назад\n"
prompt "Выберите сервис для удаления: "
[ "$REPLY" = "0" ] && return
[ -z "$REPLY" ] && return
local sel_name
sel_name=$(echo "$services" | tr ' ' '\n' | sed -n "${REPLY}p")
[ -z "$sel_name" ] && { warn "Неверный выбор"; pause; return; }
prompt "Удалить сервис '$sel_name'? (д/н) [н]: "
local confirm="${REPLY:-н}"
case "$confirm" in
д|Д|y|Y|да|yes) ;;
*) msg "Отменено"; pause; return ;;
esac
load_service "$sel_name" || { pause; return; }
is_running "$sel_name" && do_stop_service "$sel_name"
msg "Удаляю конфиг nginx на VPS..."
ssh_cmd "rm -f $REMOTE_NGINX_DIR/rproxy_$sel_name.conf && nginx -t && systemctl reload nginx" || {
warn "Не удалось удалить конфиг nginx на VPS"
}
rm -f "$SERVICES_DIR/$sel_name.conf"
rm -f "$(get_pid_file "$sel_name")"
msg "Сервис '$sel_name' удалён"
pause
}
# ══════════════════════════════════════════════════════════════════════
# ВЫБОР СЕРВИСА (общий)
# ══════════════════════════════════════════════════════════════════════
select_service() {
local title="$1"
local filter="$2" # all, running, stopped
local services=""
local idx=0
for f in "$SERVICES_DIR"/*.conf 2>/dev/null; do
[ -f "$f" ] || continue
. "$f"
local running=0
is_running "$SVC_NAME" && running=1
# Фильтр
case "$filter" in
running) [ "$running" -eq 0 ] && continue ;;
stopped) [ "$running" -eq 1 ] && continue ;;
esac
idx=$((idx + 1))
local st="${RED}${NC}"
[ "$running" -eq 1 ] && st="${GREEN}${NC}"
printf " ${BOLD}%d)${NC} %b %-14s %s:%s" "$idx" "$st" "$SVC_NAME" "$SVC_TARGET_HOST" "$SVC_TARGET_PORT"
[ -n "$SVC_DOMAIN" ] && printf " ${DIM}(%s)${NC}" "$SVC_DOMAIN"
printf "\n"
services="$services $SVC_NAME"
done
if [ "$idx" -eq 0 ]; then
printf " ${YELLOW}Нет подходящих сервисов.${NC}\n"
SELECTED_SERVICE=""
return 1
fi
printf " ${BOLD}a)${NC} Все сервисы\n"
printf " ${BOLD}0)${NC} Назад\n"
prompt "Выберите сервис: "
[ "$REPLY" = "0" ] && { SELECTED_SERVICE=""; return 1; }
if [ "$REPLY" = "a" ] || [ "$REPLY" = "A" ] || [ "$REPLY" = "а" ] || [ "$REPLY" = "А" ]; then
SELECTED_SERVICE="__ALL__"
return 0
fi
SELECTED_SERVICE=$(echo "$services" | tr ' ' '\n' | sed -n "${REPLY}p")
[ -z "$SELECTED_SERVICE" ] && { warn "Неверный выбор"; return 1; }
return 0
}
# ══════════════════════════════════════════════════════════════════════
# ЗАПУСК / ОСТАНОВ / ПЕРЕЗАПУСК (интерактивно)
# ══════════════════════════════════════════════════════════════════════
do_start_interactive() {
clear_screen
draw_box "Запустить туннель"
printf "\n"
select_service "Запустить" "stopped" || { pause; return; }
if [ "$SELECTED_SERVICE" = "__ALL__" ]; then
do_start_all
else
do_start_service "$SELECTED_SERVICE"
fi
pause
}
do_stop_interactive() {
clear_screen
draw_box "Остановить туннель"
printf "\n"
select_service "Остановить" "running" || { pause; return; }
if [ "$SELECTED_SERVICE" = "__ALL__" ]; then
do_stop_all
else
do_stop_service "$SELECTED_SERVICE"
fi
pause
}
do_restart_interactive() {
clear_screen
draw_box "Перезапустить туннель"
printf "\n"
select_service "Перезапустить" "all" || { pause; return; }
if [ "$SELECTED_SERVICE" = "__ALL__" ]; then
for f in "$SERVICES_DIR"/*.conf 2>/dev/null; do
[ -f "$f" ] || continue
. "$f"
do_stop_service "$SVC_NAME"
sleep 1
do_start_service "$SVC_NAME"
done
else
load_service "$SELECTED_SERVICE"
do_stop_service "$SELECTED_SERVICE"
sleep 1
do_start_service "$SELECTED_SERVICE"
fi
pause
}
# ══════════════════════════════════════════════════════════════════════
# ЗАПУСК / ОСТАНОВ (одного сервиса)
# ══════════════════════════════════════════════════════════════════════
do_start_service() {
local name="$1"
load_service "$name" || return
if is_running "$name"; then
warn "Сервис '$name' уже запущен"
return
fi
msg "Запускаю туннель '$name' ($SVC_TARGET_HOST:$SVC_TARGET_PORT → VPS:$SVC_TUNNEL_PORT)..."
mkdir -p "$PID_DIR"
local pid_file
pid_file=$(get_pid_file "$name")
local ssh_opts="-o StrictHostKeyChecking=no -o ServerAliveInterval=30 -o ServerAliveCountMax=3 -o ExitOnForwardFailure=yes"
if [ "$VPS_AUTH" = "password" ]; then
AUTOSSH_GATETIME=0 sshpass -p "$VPS_PASS" autossh -M 0 -f -N \
$ssh_opts \
-p "$VPS_PORT" \
-R "0.0.0.0:$SVC_TUNNEL_PORT:$SVC_TARGET_HOST:$SVC_TARGET_PORT" \
"$VPS_USER@$VPS_HOST" &
else
AUTOSSH_GATETIME=0 autossh -M 0 -f -N \
$ssh_opts \
-i "$SSH_KEY" \
-p "$VPS_PORT" \
-R "0.0.0.0:$SVC_TUNNEL_PORT:$SVC_TARGET_HOST:$SVC_TARGET_PORT" \
"$VPS_USER@$VPS_HOST" &
fi
local bg_pid=$!
sleep 2
local real_pid
real_pid=$(pgrep -f "autossh.*$SVC_TUNNEL_PORT:$SVC_TARGET_HOST:$SVC_TARGET_PORT" 2>/dev/null | head -1)
[ -z "$real_pid" ] && real_pid=$(pgrep -f "ssh.*$SVC_TUNNEL_PORT:$SVC_TARGET_HOST:$SVC_TARGET_PORT" 2>/dev/null | head -1)
[ -z "$real_pid" ] && real_pid=$bg_pid
echo "$real_pid" > "$pid_file"
msg "Туннель '$name' запущен (PID: $real_pid)"
}
do_stop_service() {
local name="$1"
local pid_file
pid_file=$(get_pid_file "$name")
if [ ! -f "$pid_file" ]; then
warn "Сервис '$name' не запущен"
return
fi
local pid
pid=$(cat "$pid_file")
kill "$pid" 2>/dev/null
pkill -f "ssh.*:$name.*$VPS_HOST" 2>/dev/null
rm -f "$pid_file"
msg "Туннель '$name' остановлен"
}
do_start_all() {
for f in "$SERVICES_DIR"/*.conf 2>/dev/null; do
[ -f "$f" ] || continue
. "$f"
[ "$SVC_ENABLED" = "yes" ] && do_start_service "$SVC_NAME"
done
}
do_stop_all() {
for f in "$SERVICES_DIR"/*.conf 2>/dev/null; do
[ -f "$f" ] || continue
. "$f"
do_stop_service "$SVC_NAME"
done
}
# ══════════════════════════════════════════════════════════════════════
# НАСТРОЙКА VPS
# ══════════════════════════════════════════════════════════════════════
do_setup() {
clear_screen
draw_box "Настройка подключения к VPS"
printf "\n"
# Показать текущие настройки, если есть
if check_conf; then
printf " ${DIM}Текущие настройки:${NC}\n"
printf " Хост: ${BOLD}$VPS_HOST${NC} Порт: ${BOLD}$VPS_PORT${NC} Пользователь: ${BOLD}$VPS_USER${NC} Авторизация: ${BOLD}$VPS_AUTH${NC}\n"
draw_separator
printf "\n"
fi
prompt "IP-адрес VPS: "
local vps_host="$REPLY"
[ -z "$vps_host" ] && { warn "IP-адрес обязателен"; pause; return; }
prompt "SSH порт [22]: "
local vps_port="${REPLY:-22}"
prompt "SSH пользователь [root]: "
local vps_user="${REPLY:-root}"
printf "\n Метод авторизации:\n"
printf " ${BOLD}1)${NC} SSH-ключ (рекомендуется)\n"
printf " ${BOLD}2)${NC} Пароль\n"
prompt "Выберите [1]: "
local auth_choice="${REPLY:-1}"
local vps_auth="key"
local vps_pass=""
if [ "$auth_choice" = "2" ]; then
vps_auth="password"
if ! command -v sshpass >/dev/null 2>&1; then
printf "\n ${RED}✖ Ошибка: Утилита sshpass не найдена в системе.${NC}\n"
printf " Для вашего роутера этот пакет недоступен в репозитории.\n"
printf " Пожалуйста, используйте авторизацию по SSH-ключу.\n"
pause
return
fi
printf " SSH пароль: "
stty -echo 2>/dev/null
read -r vps_pass
stty echo 2>/dev/null
printf "\n"
fi
else
if [ ! -f "$SSH_KEY" ]; then
msg "Генерирую SSH-ключ..."
mkdir -p "$CONF_DIR"
ssh-keygen -t rsa -b 4096 -f "$SSH_KEY" -N "" -q
msg "Ключ создан: $SSH_KEY"
fi
fi
# Проверка подключения
printf "\n"
msg "Проверяю подключение к $vps_host..."
if [ "$vps_auth" = "password" ]; then
if ! sshpass -p "$vps_pass" ssh -o StrictHostKeyChecking=no -o ConnectTimeout=10 \
-p "$vps_port" "$vps_user@$vps_host" "echo ok" >/dev/null 2>&1; then
err "Не удалось подключиться к VPS. Проверьте параметры."
pause
return
fi
else
msg "Копирую SSH-ключ на VPS..."
printf " Введите пароль VPS для копирования ключа:\n"
ssh-copy-id -i "$SSH_KEY.pub" -p "$vps_port" "$vps_user@$vps_host" 2>/dev/null || {
cat "$SSH_KEY.pub" | ssh -p "$vps_port" "$vps_user@$vps_host" \
"mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"
}
if ! ssh -o StrictHostKeyChecking=no -o ConnectTimeout=10 \
-i "$SSH_KEY" -p "$vps_port" "$vps_user@$vps_host" "echo ok" >/dev/null 2>&1; then
err "Не удалось подключиться к VPS по ключу."
pause
return
fi
fi
msg "Подключение успешно!"
# Настройка nginx на VPS
msg "Настраиваю nginx на VPS..."
local ssh_setup_cmd
if [ "$vps_auth" = "password" ]; then
ssh_setup_cmd="sshpass -p \"$vps_pass\" ssh -o StrictHostKeyChecking=no -p $vps_port $vps_user@$vps_host"
else
ssh_setup_cmd="ssh -o StrictHostKeyChecking=no -i $SSH_KEY -p $vps_port $vps_user@$vps_host"
fi
eval $ssh_setup_cmd "'
if ! command -v nginx >/dev/null 2>&1; then
echo \"Устанавливаю nginx...\"
apt-get update -qq && apt-get install -y -qq nginx >/dev/null 2>&1 || \
yum install -y nginx >/dev/null 2>&1 || {
echo \"FAIL: не удалось установить nginx\"
exit 1
}
fi
mkdir -p /etc/nginx/sites-enabled
if ! grep -q \"include.*sites-enabled\" /etc/nginx/nginx.conf 2>/dev/null; then
sed -i \"/http {/a\\\\ include /etc/nginx/sites-enabled/*.conf;\" /etc/nginx/nginx.conf 2>/dev/null
fi
systemctl enable nginx 2>/dev/null
systemctl start nginx 2>/dev/null
echo OK
'" || {
warn "Не удалось автоматически настроить nginx. Убедитесь, что nginx установлен на VPS."
}
# Сохранение конфига
mkdir -p "$CONF_DIR" "$SERVICES_DIR" "$PID_DIR"
cat > "$CONF_FILE" <<EOF
# rProxy — настройки VPS
VPS_HOST="$vps_host"
VPS_PORT="$vps_port"
VPS_USER="$vps_user"
VPS_AUTH="$vps_auth"
VPS_PASS="$vps_pass"
EOF
chmod 600 "$CONF_FILE"
msg "Конфигурация сохранена!"
printf "\n ${GREEN}${BOLD}VPS настроен и готов к работе.${NC}\n"
pause
}
# ══════════════════════════════════════════════════════════════════════
# ТОЧКА ВХОДА
# ══════════════════════════════════════════════════════════════════════
mkdir -p "$CONF_DIR" "$SERVICES_DIR" "$PID_DIR" 2>/dev/null
# Поддержка прямых команд для init-скрипта и автоматизации
case "${1:-}" in
start) check_conf && do_start_all ;;
stop) check_conf && do_stop_all ;;
restart) check_conf && do_stop_all; sleep 1; do_start_all ;;
status)
check_conf || { err "VPS не настроен"; exit 1; }
for f in "$SERVICES_DIR"/*.conf 2>/dev/null; do
[ -f "$f" ] || continue
. "$f"
local state="остановлен"
is_running "$SVC_NAME" && state="работает"
local info="$SVC_NAME $SVC_TARGET_HOST:$SVC_TARGET_PORT → :$SVC_EXT_PORT"
[ -n "$SVC_DOMAIN" ] && info="$info ($SVC_DOMAIN)"
echo "$info [$state]"
done
;;
-v|--version) echo "rProxy v$VERSION" ;;
"") main_menu ;;
*) main_menu ;;
esac