diff --git a/rproxy b/rproxy index 895de50..0d19aac 100644 --- a/rproxy +++ b/rproxy @@ -3,7 +3,7 @@ # Публикация локальных сервисов через SSH-туннели + nginx на VPS # https://github.com/l-ptrol/rProxy -VERSION="1.6.5" +VERSION="1.7.0" export PATH="/opt/bin:/opt/sbin:$PATH" CONF_DIR="/opt/etc/rproxy" CONF_FILE="$CONF_DIR/rproxy.conf" @@ -355,6 +355,11 @@ show_status() { fi local domain_text="${SVC_DOMAIN:-—}" + if [ -n "$SVC_DOMAIN" ]; then + [ "$SVC_EXT_PORT" != "80" ] && [ "$SVC_EXT_PORT" != "443" ] && domain_text="$domain_text:$SVC_EXT_PORT" + [ "$SVC_PATH" != "/" ] && domain_text="$domain_text$SVC_PATH" + fi + local auto_text="" [ "$SVC_ENABLED" = "yes" ] && auto_text=" ${DIM}[авто]${NC}" @@ -464,7 +469,7 @@ do_add_interactive() { prompt "Выберите [2]: " local mode="${REPLY:-2}" - local domain="" ext_port="" use_ssl="no" vps_id="" + local domain="" ext_port="" use_ssl="no" vps_id="" path="/" if [ "$mode" = "1" ]; then prompt "Доменное имя (например, mysite.example.com): " @@ -474,16 +479,24 @@ do_add_interactive() { # Проверка на дубликаты доменов for f in "$SERVICES_DIR"/*.conf; do [ -f "$f" ] || continue - if grep -q "SVC_DOMAIN=\"$domain\"" "$f"; then + if grep -q "SVC_DOMAIN=\"$domain\"" "$f" && grep -q "SVC_PATH=\"/\"" "$f"; then + # Конфликт только если и домен и путь совпадают local conflict=$(basename "$f" .conf) - err "Домен '$domain' уже используется сервисом '$conflict'" - pause; return + warn "Домен '$domain' с путем '/' уже используется сервисом '$conflict'" + prompt "Продолжить? (д/н) [н]: " + [ "${REPLY:-н}" != "д" ] && return fi done - use_ssl="yes"; ext_port=443 + prompt "Внешний порт [443]: " + ext_port="${REPLY:-443}" + [ "$ext_port" = "443" ] && use_ssl="yes" || use_ssl="no" + + prompt "Путь на сервере (например, /app1) [/]: " + path="${REPLY:-/}" + [ "${path#/}" = "$path" ] && path="/$path" - if [ -z "$CERTBOT_EMAIL" ]; then + if [ "$use_ssl" = "yes" ] && [ -z "$CERTBOT_EMAIL" ]; then prompt "Введите Email для Certbot: " CERTBOT_EMAIL="$REPLY" sed -i "/CERTBOT_EMAIL=/d" "$CONF_FILE" @@ -502,6 +515,10 @@ do_add_interactive() { ext_port=$(next_free_ext_port) prompt "Внешний порт [$ext_port]: " ext_port="${REPLY:-$ext_port}" + + prompt "Путь на сервере (например, /app1) [/]: " + path="${REPLY:-/}" + [ "${path#/}" = "$path" ] && path="/$path" fi # Если VPS не определен автоматически — выбираем вручную @@ -528,7 +545,9 @@ do_add_interactive() { printf " ${BOLD}Цель:${NC} $t_host:$t_port\n" printf " ${BOLD}Туннель:${NC} порт $tunnel_port\n" [ -n "$domain" ] && printf " ${BOLD}Домен:${NC} $domain\n" + printf " ${BOLD}Путь:${NC} $path\n" printf " ${BOLD}Внешний порт:${NC} $ext_port\n" + [ "$use_ssl" = "yes" ] && printf " ${BOLD}SSL:${NC} Да (авто)\n" prompt "Защитить сервис паролем? (д/н) [н]: " local use_ndm_auth="no" local htpasswd_line="" @@ -577,7 +596,7 @@ do_add_interactive() { fi local tmp="/tmp/rproxy_$name.conf" - generate_nginx_conf "$name" "$t_host" "$t_port" "$tunnel_port" "$domain" "$ext_port" "$use_ndm_auth" "$tmp" + generate_nginx_conf "$name" "$t_host" "$t_port" "$tunnel_port" "$domain" "$ext_port" "$use_ndm_auth" "$path" "$tmp" # Деплой # Деплой htpasswd если нужно @@ -608,6 +627,7 @@ do_add_interactive() { printf 'SVC_TUNNEL_PORT="%s"\n' "$tunnel_port" printf 'SVC_EXT_PORT="%s"\n' "$ext_port" printf 'SVC_DOMAIN="%s"\n' "$domain" + printf 'SVC_PATH="%s"\n' "$path" printf 'SVC_SSL="%s"\n' "$use_ssl" printf 'SVC_NDM_AUTH="%s"\n' "$use_ndm_auth" printf "SVC_HTPASSWD='%s'\n" "$htpasswd_line" @@ -820,8 +840,16 @@ do_edit_interactive() { new_host="127.0.0.1" fi + prompt "Внешний порт [$SVC_EXT_PORT]: " + local new_ext_port="${REPLY:-$SVC_EXT_PORT}" + + prompt "Путь на сервере [$SVC_PATH]: " + local new_path="${REPLY:-$SVC_PATH}" + [ "${new_path#/}" = "$new_path" ] && new_path="/$new_path" + # Если ничего не изменилось - if [ "$new_host" = "$SVC_TARGET_HOST" ] && [ "$new_port" = "$SVC_TARGET_PORT" ]; then + if [ "$new_host" = "$SVC_TARGET_HOST" ] && [ "$new_port" = "$SVC_TARGET_PORT" ] && \ + [ "$new_ext_port" = "$SVC_EXT_PORT" ] && [ "$new_path" = "$SVC_PATH" ]; then msg "Параметры не изменились." pause return @@ -829,8 +857,10 @@ do_edit_interactive() { printf "\n" draw_separator - printf " ${DIM}Было:${NC} $SVC_TARGET_HOST:$SVC_TARGET_PORT\n" - printf " ${GREEN}Стало:${NC} $new_host:$new_port\n" + printf " ${DIM}Параметр Было Стало${NC}\n" + printf " Цель: %-22s %s\n" "$SVC_TARGET_HOST:$SVC_TARGET_PORT" "$new_host:$new_port" + printf " Порт: %-22s %s\n" "$SVC_EXT_PORT" "$new_ext_port" + printf " Путь: %-22s %s\n" "$SVC_PATH" "$new_path" draw_separator prompt "Применить изменения? (д/н) [д]: " @@ -852,13 +882,19 @@ do_edit_interactive() { # Обновить локальный конфиг сервиса sed -i "s|SVC_TARGET_HOST=\".*\"|SVC_TARGET_HOST=\"$new_host\"|" "$SERVICES_DIR/$name.conf" sed -i "s|SVC_TARGET_PORT=\".*\"|SVC_TARGET_PORT=\"$new_port\"|" "$SERVICES_DIR/$name.conf" + sed -i "s|SVC_EXT_PORT=\".*\"|SVC_EXT_PORT=\"$new_ext_port\"|" "$SERVICES_DIR/$name.conf" + if grep -q "SVC_PATH=" "$SERVICES_DIR/$name.conf"; then + sed -i "s|SVC_PATH=\".*\"|SVC_PATH=\"$new_path\"|" "$SERVICES_DIR/$name.conf" + else + echo "SVC_PATH=\"$new_path\"" >> "$SERVICES_DIR/$name.conf" + fi # Перезагружаем переменные для деплоя load_service "$name" # Перегенерация и деплой конфига Nginx на VPS local tmp="/tmp/rproxy_edit_$name.conf" - generate_nginx_conf "$name" "$SVC_TARGET_HOST" "$SVC_TARGET_PORT" "$SVC_TUNNEL_PORT" "$SVC_DOMAIN" "$SVC_EXT_PORT" "$SVC_NDM_AUTH" "$tmp" + generate_nginx_conf "$name" "$SVC_TARGET_HOST" "$SVC_TARGET_PORT" "$SVC_TUNNEL_PORT" "$SVC_DOMAIN" "$SVC_EXT_PORT" "$SVC_NDM_AUTH" "$SVC_PATH" "$tmp" scp_cmd "$tmp" "$VPS_USER@$VPS_HOST:$REMOTE_NGINX_DIR/rproxy_$name.conf" rm -f "$tmp" @@ -1072,7 +1108,7 @@ do_stop_service() { _clear_svc_vars() { unset SVC_NAME SVC_VPS SVC_TARGET_HOST SVC_TARGET_PORT SVC_TUNNEL_PORT - unset SVC_EXT_PORT SVC_DOMAIN SVC_SSL SVC_NDM_AUTH SVC_HTPASSWD SVC_ENABLED + unset SVC_EXT_PORT SVC_DOMAIN SVC_PATH SVC_SSL SVC_NDM_AUTH SVC_HTPASSWD SVC_ENABLED } load_service() { @@ -1091,7 +1127,11 @@ generate_nginx_conf() { local domain="$5" local ext_port="$6" local use_ndm_auth="$7" - local target_file="$8" + local path="$8" + local target_file="$9" + + # Гарантируем, что путь начинается с / + [ "${path#/}" = "$path" ] && path="/$path" local stealth_host="$t_host" [ "$t_port" != "80" ] && stealth_host="$t_host:$t_port" @@ -1107,13 +1147,13 @@ generate_nginx_conf() { if [ -n "$domain" ]; then cat > "$target_file" << NGINXEOF server { - listen 80; + listen $ext_port; server_name "$domain"; proxy_buffering off; proxy_request_buffering off; - location / { + location $path { $auth_config - proxy_pass http://127.0.0.1:$tunnel_port; + 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"; @@ -1124,6 +1164,7 @@ server { proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto \$scheme; proxy_cookie_domain "$t_host" "\$host"; + proxy_redirect off; } } NGINXEOF @@ -1133,9 +1174,9 @@ server { listen $ext_port; proxy_buffering off; proxy_request_buffering off; - location / { + location $path { $auth_config - proxy_pass http://127.0.0.1:$tunnel_port; + 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"; @@ -1144,6 +1185,7 @@ server { proxy_set_header X-Real-IP \$remote_addr; proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; proxy_cookie_domain "$t_host" "\$host"; + proxy_redirect off; } } NGINXEOF