commit 893e36d8b626d4ecaf69766b6d02d18f271d8d75 Author: mango Date: Mon Apr 27 21:56:29 2026 +0800 Add proxy protocol installer mirror diff --git a/README.md b/README.md new file mode 100644 index 0000000..034ef95 --- /dev/null +++ b/README.md @@ -0,0 +1,27 @@ +# proxy-installer + +顶尖自己的协议一键脚本镜像入口,统一选择: + +- ss2022 + shadowtls +- anytls +- snell v5 +- Reality (Xray) + +## 推荐用法 + +```bash +curl -fsSL https://mjjtop.com/proxy -o proxy.sh && chmod +x proxy.sh && ./proxy.sh +``` + +## 直接指定协议 + +```bash +curl -fsSL https://mjjtop.com/proxy | bash -s -- ss +curl -fsSL https://mjjtop.com/proxy | bash -s -- anytls +curl -fsSL https://mjjtop.com/proxy | bash -s -- snell +curl -fsSL https://mjjtop.com/proxy | bash -s -- reality +``` + +## 说明 + +这里镜像的是安装脚本本身,不再依赖 `*.shuijiao.de`。脚本内部仍会从官方 GitHub / Surge CDN 拉取对应二进制;如果要完全离线/完全不依赖外部下载源,需要下一步再镜像二进制 release。 diff --git a/proxy.sh b/proxy.sh new file mode 100755 index 0000000..e28c222 --- /dev/null +++ b/proxy.sh @@ -0,0 +1,69 @@ +#!/usr/bin/env bash +# 顶尖协议一键脚本统一入口 +# Mirror: https://mjjtop.com/proxy +# Protocols: ss2022+shadowtls / anytls / snell v5 / reality + +set -euo pipefail + +BASE_URL="${MIRROR_BASE_URL:-https://mjjtop.com/raw/proxy-installer}" +TMP_DIR="/tmp/mjjtop-proxy-installer" + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +CYAN='\033[0;36m' +NC='\033[0m' + +info(){ echo -e "${GREEN}[INFO]${NC} $*"; } +warn(){ echo -e "${YELLOW}[WARN]${NC} $*"; } +err(){ echo -e "${RED}[ERROR]${NC} $*" >&2; exit 1; } + +if [[ "${PROXY_INSTALLER_SKIP_ROOT_CHECK:-0}" != "1" ]]; then + [[ ${EUID:-$(id -u)} -eq 0 ]] || err "请用 root 运行" +fi +command -v curl >/dev/null 2>&1 || err "缺少 curl,请先安装: apt install -y curl" +mkdir -p "$TMP_DIR" + +run_remote() { + local name="$1" path="$2" file="$TMP_DIR/$path" + info "下载 $name 脚本:$BASE_URL/scripts/$path" + curl -fsSL "$BASE_URL/scripts/$path" -o "$file" + chmod +x "$file" + info "开始执行 $name" + exec bash "$file" +} + +show_menu() { + clear 2>/dev/null || true + echo -e "${CYAN}========================================${NC}" + echo -e "${CYAN} 顶尖协议一键脚本 / mjjtop proxy${NC}" + echo -e "${CYAN}========================================${NC}" + echo "1) ss2022 + shadowtls" + echo "2) anytls" + echo "3) snell v5" + echo "4) Reality (Xray)" + echo "0) 退出" + echo +} + +case "${1:-}" in + ss|ss2022|shadowtls) run_remote "ss2022 + shadowtls" "ss2022-shadowtls.sh" ;; + anytls|any) run_remote "anytls" "anytls.sh" ;; + snell|snell5) run_remote "snell v5" "snell-v5.sh" ;; + reality|xray) run_remote "Reality (Xray)" "reality.sh" ;; + "") ;; + *) err "未知参数:$1,可用: ss | anytls | snell | reality" ;; +esac + +while true; do + show_menu + read -rp "请选择协议 [0-4]: " choice + case "$choice" in + 1) run_remote "ss2022 + shadowtls" "ss2022-shadowtls.sh" ;; + 2) run_remote "anytls" "anytls.sh" ;; + 3) run_remote "snell v5" "snell-v5.sh" ;; + 4) run_remote "Reality (Xray)" "reality.sh" ;; + 0|q|Q) exit 0 ;; + *) warn "无效选择"; sleep 1 ;; + esac +done diff --git a/scripts/anytls.sh b/scripts/anytls.sh new file mode 100755 index 0000000..28d752e --- /dev/null +++ b/scripts/anytls.sh @@ -0,0 +1,343 @@ +#!/bin/bash + +# ================================================================= +# anytls 管理脚本 (修复 Mihomo 缩进版) +# 描述: 自动获取 GitHub 最新版本安装,同时显示 Surge 和 Mihomo 配置。 +# ================================================================= + +# 定义输出颜色 +GREEN='\033[0;32m' +RED='\033[0;31m' +NC='\033[0m' # 无颜色 + +# --- 函数: 检查 anytls 安装和运行状态 --- +check_anytls_status() { + if [ -f /usr/local/bin/anytls-server ] && [ -f /etc/systemd/system/anytls.service ]; then + echo -e "${GREEN}anytls 状态: 已安装${NC}" + else + echo -e "${RED}anytls 状态: 未安装${NC}" + fi + + if systemctl is-active --quiet anytls; then + echo -e "${GREEN}服务状态: 运行中${NC}" + else + echo -e "${RED}服务状态: 未运行${NC}" + fi +} + +# --- 函数: 显示菜单 --- +show_menu() { + clear + echo "==================================================" + echo " anytls-go 综合管理脚本 (v1.3)" + echo "==================================================" + check_anytls_status + echo "--------------------------------------------------" + echo "1. 安装 anytls" + echo "2. 卸载 anytls" + echo "3. 修改 anytls 配置 (端口/密码)" + echo "4. 查看 anytls 配置" + echo "5. 启动 anytls 服务" + echo "6. 停止 anytls 服务" + echo "7. 重启 anytls 服务" + echo "8. 查看 anytls 运行状态" + echo "0. 退出脚本" + echo "==================================================" + echo -n "请输入选项 [0-8]: " +} + +# --- 函数: 检查 root 权限 --- +check_root() { + if [ "$(id -u)" -ne 0 ]; then + echo -e "${RED}错误:此脚本需要以 root 权限运行。${NC}" >&2 + exit 1 + fi +} + +# --- 函数: 显示配置信息 (通用模块) --- +# 参数: $1=ip, $2=port, $3=password +display_configuration() { + local ip=$1 + local port=$2 + local pwd=$3 + + echo "------------------------------------------" + echo " anytls 配置详情" + echo "------------------------------------------" + echo -e "地址 (IP) : ${GREEN}${ip}${NC}" + echo -e "端口 (Port) : ${GREEN}${port}${NC}" + echo -e "密码 (Password) : ${GREEN}${pwd}${NC}" + echo "------------------------------------------" + + echo "1. Surge 配置文件:" + echo -e "${GREEN}VPS = anytls, ${ip}, ${port}, password=\"${pwd}\", skip-cert-verify=true, udp-relay=true, reuse=false${NC}" + + echo "" + echo "2. Mihomo (Clash Meta) 配置文件:" + # 注意:下面这一行前面已经加了两个空格 + echo -e "${GREEN} - {\"name\":\"VPS\",\"server\":\"${ip}\",\"port\":${port},\"password\":\"${pwd}\",\"skip-cert-verify\":true,\"reuse\":false,\"type\":\"anytls\"}${NC}" + echo "------------------------------------------" +} + +# --- 函数: 安装 anytls --- +install_anytls() { + if [ -f /usr/local/bin/anytls-server ]; then + echo -e "${GREEN}anytls 似乎已经安装,无需重复安装。${NC}" + return + fi + + echo "--> 正在准备安装环境..." + if ! command -v curl &> /dev/null || ! command -v unzip &> /dev/null || ! command -v shuf &> /dev/null || ! command -v grep &> /dev/null; then + echo "--> 检测到依赖缺失,正在尝试自动安装..." + if command -v apt-get &> /dev/null; then + apt-get update && apt-get install -y curl unzip coreutils grep + elif command -v yum &> /dev/null; then + yum install -y curl unzip coreutils grep + else + echo -e "${RED}无法确定包管理器,请手动安装 curl, unzip, coreutils, grep 后再运行此脚本。${NC}" + exit 1 + fi + fi + + echo "--> 正在获取 anytls 最新版本信息..." + LATEST_URL=$(curl -s https://api.github.com/repos/anytls/anytls-go/releases/latest | grep "browser_download_url" | grep "linux_amd64.zip" | head -n 1 | cut -d '"' -f 4) + + if [ -z "$LATEST_URL" ]; then + echo -e "${RED}获取最新版本失败,尝试使用备用版本 (v0.0.12)...${NC}" + LATEST_URL="https://github.com/anytls/anytls-go/releases/download/v0.0.12/anytls_0.0.12_linux_amd64.zip" + else + echo -e " 检测到最新版本下载地址: ${GREEN}$LATEST_URL${NC}" + fi + + echo "--> 正在下载 anytls..." + if ! curl -sL -o anytls.zip "$LATEST_URL"; then + echo -e "${RED}下载 anytls 失败!请检查网络连接。${NC}" + exit 1 + fi + + echo "--> 正在解压并部署..." + if ! unzip -o anytls.zip; then + echo -e "${RED}解压 anytls 失败!${NC}" + rm anytls.zip + exit 1 + fi + + if [ -f anytls-server ]; then + mv anytls-server /usr/local/bin/ + else + FIND_SERVER=$(find . -maxdepth 1 -name "anytls*server*" | head -n 1) + if [ -n "$FIND_SERVER" ]; then + mv "$FIND_SERVER" /usr/local/bin/anytls-server + else + echo -e "${RED}错误:解压后未找到 anytls-server 文件。${NC}" + exit 1 + fi + fi + + rm -f anytls-client* readme.md anytls.zip anytls*.zip + chmod +x /usr/local/bin/anytls-server + echo " anytls 程序部署完成。" + + read -p "请输入 anytls 的监听端口 (留空则随机生成 10000-65535): " PORT + if [ -z "$PORT" ]; then + PORT=$((RANDOM % 55536 + 10000)) + echo -e " 使用随机端口: ${GREEN}$PORT${NC}" + fi + + read -p "请输入 anytls 的密码 (留空则随机生成): " PASSWORD + if [ -z "$PASSWORD" ]; then + ALPHANUM=$(< /dev/urandom tr -dc 'A-Za-z0-9' | head -c 14) + SPECIAL_CHARS='-/@' + S1_INDEX=$(($RANDOM % 3)) + S1=${SPECIAL_CHARS:$S1_INDEX:1} + REMAINING_CHARS=${SPECIAL_CHARS//$S1/} + S2_INDEX=$(($RANDOM % 2)) + S2=${REMAINING_CHARS:$S2_INDEX:1} + COMBINED_CHARS="${ALPHANUM}${S1}${S2}" + PASSWORD=$(echo "$COMBINED_CHARS" | grep -o . | shuf | tr -d '\n') + echo -e " 使用随机密码: ${GREEN}$PASSWORD${NC}" + fi + + echo "--> 正在创建 systemd 服务..." + cat > /etc/systemd/system/anytls.service < 正在启动服务..." + systemctl daemon-reload + systemctl enable anytls > /dev/null 2>&1 + systemctl start anytls + + echo "--> 正在获取 IP..." + local ip_address=$(curl -s https://ipv4.icanhazip.com || curl -s https://api.ipify.org) + [ -z "$ip_address" ] && ip_address="<您的服务器IP>" + + echo -e "${GREEN}🎉 anytls 安装成功!${NC}" + display_configuration "$ip_address" "$PORT" "$PASSWORD" +} + +# --- 函数: 卸载 anytls --- +uninstall_anytls() { + if [ ! -f /usr/local/bin/anytls-server ]; then + echo -e "${RED}anytls 未安装。${NC}" + return + fi + + echo -e "${RED}警告:将停止服务并删除所有文件。${NC}" + read -p "确认继续? [y/N]: " confirm + if [[ $confirm != [yY] && $confirm != [yY][eE][sS] ]]; then + echo "操作取消。" + return + fi + + systemctl stop anytls + systemctl disable anytls > /dev/null 2>&1 + rm -f /etc/systemd/system/anytls.service + rm -f /usr/local/bin/anytls-server + systemctl daemon-reload + + echo -e "${GREEN}anytls 已卸载。${NC}" + rm -- "$0" + echo "脚本已自毁,退出。" + exit 0 +} + +# --- 函数: 修改配置 --- +modify_config() { + if [ ! -f /etc/systemd/system/anytls.service ]; then + echo -e "${RED}anytls 未安装。${NC}" + return + fi + + read -p "新端口 (留空随机): " PORT + if [ -z "$PORT" ]; then + PORT=$((RANDOM % 55536 + 10000)) + fi + + read -p "新密码 (留空随机): " PASSWORD + if [ -z "$PASSWORD" ]; then + ALPHANUM=$(< /dev/urandom tr -dc 'A-Za-z0-9' | head -c 14) + SPECIAL_CHARS='-/@' + S1_INDEX=$(($RANDOM % 3)) + S1=${SPECIAL_CHARS:$S1_INDEX:1} + REMAINING_CHARS=${SPECIAL_CHARS//$S1/} + S2_INDEX=$(($RANDOM % 2)) + S2=${REMAINING_CHARS:$S2_INDEX:1} + COMBINED_CHARS="${ALPHANUM}${S1}${S2}" + PASSWORD=$(echo "$COMBINED_CHARS" | grep -o . | shuf | tr -d '\n') + fi + + cat > /etc/systemd/system/anytls.service < 正在获取 IP..." + local ip_address=$(curl -s https://ipv4.icanhazip.com || curl -s https://api.ipify.org) + [ -z "$ip_address" ] && ip_address="<您的服务器IP>" + + # 调用通用显示函数 + display_configuration "$ip_address" "$port" "$password" +} + +# --- 服务管理函数 --- +start_anytls() { + if systemctl is-active --quiet anytls; then + echo -e "${GREEN}服务已在运行。${NC}" + else + systemctl start anytls && echo -e "${GREEN}启动成功。${NC}" || echo -e "${RED}启动失败。${NC}" + fi +} + +stop_anytls() { + if ! systemctl is-active --quiet anytls; then + echo -e "${GREEN}服务未运行。${NC}" + else + systemctl stop anytls && echo -e "${GREEN}停止成功。${NC}" || echo -e "${RED}停止失败。${NC}" + fi +} + +restart_anytls() { + if [ ! -f /etc/systemd/system/anytls.service ]; then + echo -e "${RED}anytls 未安装。${NC}" + return + fi + systemctl restart anytls && echo -e "${GREEN}重启成功。${NC}" || echo -e "${RED}重启失败。${NC}" +} + +check_anytls_running() { + if [ ! -f /etc/systemd/system/anytls.service ]; then + echo -e "${RED}anytls 未安装。${NC}" + return + fi + systemctl status anytls +} + +# --- 主程序 --- +check_root + +while true; do + show_menu + read choice + case $choice in + 1) install_anytls ;; + 2) uninstall_anytls ;; + 3) modify_config ;; + 4) view_config ;; + 5) start_anytls ;; + 6) stop_anytls ;; + 7) restart_anytls ;; + 8) check_anytls_running ;; + 0) echo "退出。"; exit 0 ;; + *) echo -e "${RED}无效选项。${NC}" ;; + esac + echo "" + echo "按 Enter 键返回菜单..." + read -r +done diff --git a/scripts/reality.sh b/scripts/reality.sh new file mode 100755 index 0000000..1be66aa --- /dev/null +++ b/scripts/reality.sh @@ -0,0 +1,438 @@ +#!/bin/bash + +# ================================================================= +# Xray (xtls-rprx-vision Reality) 服务器端管理脚本 +# ================================================================= + +# 定义输出颜色 +GREEN='\033[0;32m' +RED='\033[0;31m' +NC='\033[0m' # 无颜色 + +XRAY_CONFIG_FILE="/usr/local/etc/xray/config.json" +XRAY_KEYS_FILE="/usr/local/etc/xray/reality.keys" + +# --- 通用函数 --- +check_root() { + if [ "$(id -u)" -ne 0 ]; then + echo -e "${RED}错误:此脚本需要以 root 权限运行。${NC}" >&2 + exit 1 + fi +} + +# --- 函数: 确保 jq 已安装 --- +ensure_jq() { + if ! command -v jq &> /dev/null; then + echo "--> 检测到依赖工具 jq 未安装,正在尝试自动安装..." + if command -v apt-get &> /dev/null; then + apt-get update >/dev/null && apt-get install -y jq + elif command -v yum &> /dev/null; then + yum install -y jq + else + echo -e "${RED}无法自动安装 jq。请手动安装 (sudo apt install jq / sudo yum install jq) 后再试。${NC}" + return 1 + fi + if ! command -v jq &> /dev/null; then + echo -e "${RED}jq 安装失败,请检查包管理器或手动安装。${NC}" + return 1 + fi + echo " jq 安装成功。" + fi + return 0 +} + +# --- 函数: 检查 Xray 安装和运行状态 --- +check_xray_status() { + if [ -f /usr/local/bin/xray ]; then + echo -e "${GREEN}Xray 核心: 已安装${NC}" + else + echo -e "${RED}Xray 核心: 未安装${NC}" + fi + + if [ -f "${XRAY_CONFIG_FILE}" ]; then + echo -e "${GREEN}配置状态 : 已配置${NC}" + if systemctl is-active --quiet xray; then + echo -e "${GREEN}服务状态 : 运行中${NC}" + else + echo -e "${RED}服务状态 : 未运行${NC}" + fi + else + echo -e "${RED}配置状态 : 未配置${NC}" + fi +} + + +# --- 函数: 生成 Reality 配置 --- +generate_reality_simple_config() { + echo "--> 正在配置 Reality 配置..." + read -p "请输入监听端口 (例如 443, 留空随机): " PORT + [ -z "$PORT" ] && PORT=$((RANDOM % 55536 + 10000)) + + read -p "请输入伪装域名 (留空则默认为 icloud.com): " SNI_DOMAIN + [ -z "$SNI_DOMAIN" ] && SNI_DOMAIN="icloud.com" + + local sni_domain_cleaned=$(echo "${SNI_DOMAIN}" | cut -d':' -f1) + + echo "--> 正在生成 UUID 和 Reality 密钥对..." + local uuid=$(/usr/local/bin/xray uuid) + local key_pair=$(/usr/local/bin/xray x25519) + local private_key=$(echo "$key_pair" | grep 'PrivateKey' | awk '{print $2}') + local public_key=$(echo "$key_pair" | grep 'Password' | awk '{print $2}') + + echo "PrivateKey: ${private_key}" > "${XRAY_KEYS_FILE}" + echo "PublicKey: ${public_key}" >> "${XRAY_KEYS_FILE}" + + echo "--> 正在创建配置文件 ${XRAY_CONFIG_FILE}..." + cat > "${XRAY_CONFIG_FILE}" < 正在配置 Reality (防偷)..." + read -p "请输入外部监听端口 (例如 443, 留空随机): " EXT_PORT + [ -z "$EXT_PORT" ] && EXT_PORT=$((RANDOM % 55536 + 10000)) + + read -p "请输入内部 VLESS 端口 (留空随机): " INT_PORT + [ -z "$INT_PORT" ] && INT_PORT=$((RANDOM % 55536 + 10000)) + + read -p "请输入伪装域名 (留空则默认为 icloud.com): " SNI_DOMAIN + [ -z "$SNI_DOMAIN" ] && SNI_DOMAIN="icloud.com" + + local sni_domain_cleaned=$(echo "${SNI_DOMAIN}" | cut -d':' -f1) + + echo "--> 正在生成 UUID 和 Reality 密钥对..." + local uuid=$(/usr/local/bin/xray uuid) + local key_pair=$(/usr/local/bin/xray x25519) + local private_key=$(echo "$key_pair" | grep 'PrivateKey' | awk '{print $2}') + local public_key=$(echo "$key_pair" | grep 'Password' | awk '{print $2}') + + echo "PrivateKey: ${private_key}" > "${XRAY_KEYS_FILE}" + echo "PublicKey: ${public_key}" >> "${XRAY_KEYS_FILE}" + + echo "--> 正在创建配置文件 ${XRAY_CONFIG_FILE}..." + cat > "${XRAY_CONFIG_FILE}" < 正在使用官方脚本安装 Xray 核心..." + bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install -u root + if [ ! -f /usr/local/bin/xray ]; then + echo -e "${RED}Xray 核心安装失败。${NC}" + return 1 + else + echo -e "${GREEN}Xray 核心安装成功。${NC}" + echo "--> 正在清理旧的配置文件..." + systemctl stop xray >/dev/null 2>&1 + rm -f "${XRAY_CONFIG_FILE}" + rm -f "${XRAY_KEYS_FILE}" + echo " 旧配置已清理。" + return 0 + fi +} + +# --- 函数: (包装器) 配置 Reality --- +configure_reality_simple() { + if ! [ -f /usr/local/bin/xray ]; then + echo "--> Xray 核心未安装,正在自动安装..." + install_xray_core || return + fi + + if [ -f "${XRAY_CONFIG_FILE}" ]; then + read -p "检测到现有配置,继续将覆盖它。确定吗?[y/N]: " confirm + if [[ ! "$confirm" =~ ^[yY] ]]; then echo "操作已取消。"; return; fi + fi + + generate_reality_simple_config + + echo "--> 正在测试配置并启动 Xray..." + /usr/local/bin/xray -test -config "${XRAY_CONFIG_FILE}" + if [ $? -ne 0 ]; then + echo -e "${RED}配置文件测试失败,请检查。配置未应用。${NC}"; return; fi + + systemctl restart xray + systemctl enable xray > /dev/null 2>&1 + echo -e "${GREEN}🎉 Xray Reality 配置成功!${NC}" + view_config_xray +} + +# --- 函数: (包装器) 配置 Reality (防偷) --- +configure_reality_dokodemo() { + if ! [ -f /usr/local/bin/xray ]; then + echo "--> Xray 核心未安装,正在自动安装..." + install_xray_core || return + fi + + if [ -f "${XRAY_CONFIG_FILE}" ]; then + read -p "检测到现有配置,继续将覆盖它。确定吗?[y/N]: " confirm + if [[ ! "$confirm" =~ ^[yY] ]]; then echo "操作已取消。"; return; fi + fi + + generate_reality_dokodemo_config + + echo "--> 正在测试配置并启动 Xray..." + /usr/local/bin/xray -test -config "${XRAY_CONFIG_FILE}" + if [ $? -ne 0 ]; then + echo -e "${RED}配置文件测试失败,请检查。配置未应用。${NC}"; return; fi + + systemctl restart xray + systemctl enable xray > /dev/null 2>&1 + echo -e "${GREEN}🎉 Xray Reality (防偷) 配置成功!${NC}" + view_config_xray +} + + +# --- 函数: 卸载 Xray --- +uninstall_xray() { + if [ ! -f /usr/local/bin/xray ]; then + echo -e "${RED}Xray 未安装。${NC}"; return; fi + + read -p "警告:确定要卸载 Xray 吗?这将删除所有数据。[y/N]: " confirm + if [[ ! "$confirm" =~ ^[yY]([eE][sS])?$ ]]; then + echo "卸载操作已取消。"; return; fi + + systemctl stop xray + bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ remove --purge + rm -f "${XRAY_KEYS_FILE}" + echo -e "${GREEN}Xray 已成功卸载。${NC}" +} + +# --- 函数: 查看 Xray 配置 --- +view_config_xray() { + if [ ! -f "${XRAY_CONFIG_FILE}" ]; then + echo -e "${RED}Xray 未配置。请先选择一个配置方案。${NC}"; return; fi + ensure_jq || return + + if ! jq . "${XRAY_CONFIG_FILE}" >/dev/null 2>&1; then + echo -e "${RED}错误:配置文件 ${XRAY_CONFIG_FILE} 格式无效。${NC}"; return; fi + + local ip_address=$(curl -s https://ipv4.icanhazip.com || echo "<您的服务器IP>") + local public_key="<未找到>" + if [ -f "${XRAY_KEYS_FILE}" ]; then + public_key=$(grep 'PublicKey' "${XRAY_KEYS_FILE}" | awk '{print $2}') + fi + + echo "------------------------------------------" + echo " Xray (Reality) 当前配置信息" + echo "------------------------------------------" + + # 通过 tag 判断配置类型 + if jq -e '.inbounds[] | select(.tag=="dokodemo-in")' "${XRAY_CONFIG_FILE}" >/dev/null 2>&1; then + # 防偷配置 + local ext_port=$(jq '.inbounds[] | select(.tag=="dokodemo-in") | .port' "${XRAY_CONFIG_FILE}") + local vless_inbound=$(jq '.inbounds[] | select(.protocol=="vless")' "${XRAY_CONFIG_FILE}") + local uuid=$(echo "$vless_inbound" | jq -r '.settings.clients[0].id') + local flow=$(echo "$vless_inbound" | jq -r '.settings.clients[0].flow') + local sni=$(echo "$vless_inbound" | jq -r '.streamSettings.realitySettings.serverNames[0]') + local short_id=$(echo "$vless_inbound" | jq -r '.streamSettings.realitySettings.shortIds[0]') + + echo -e "配置类型 : ${GREEN}Reality (防偷)${NC}" + echo -e "监听地址 : ${GREEN}${ip_address}${NC}" + echo -e "外部端口 : ${GREEN}${ext_port}${NC}" + echo -e "UUID : ${GREEN}${uuid}${NC}" + echo -e "Flow : ${GREEN}${flow}${NC}" + echo -e "伪装域名 : ${GREEN}${sni}${NC}" + echo -e "Short ID : ${GREEN}${short_id}${NC}" + echo -e "公钥 (pbk) : ${GREEN}${public_key}${NC}" + echo "------------------------------------------" + echo "VLESS 分享链接:" + local vless_link="vless://${uuid}@${ip_address}:${ext_port}?encryption=none&flow=${flow}&security=reality&sni=${sni}&fp=random&pbk=${public_key}&sid=${short_id}&allowInsecure=1&type=tcp&headerType=none#VPS_防偷" + echo -e "${GREEN}${vless_link}${NC}" + + else + # Reality 配置 + local vless_inbound=$(jq '.inbounds[] | select(.protocol=="vless")' "${XRAY_CONFIG_FILE}") + local port=$(echo "$vless_inbound" | jq -r '.port') + local uuid=$(echo "$vless_inbound" | jq -r '.settings.clients[0].id') + local flow=$(echo "$vless_inbound" | jq -r '.settings.clients[0].flow') + local sni=$(echo "$vless_inbound" | jq -r '.streamSettings.realitySettings.serverNames[0]') + local short_id=$(echo "$vless_inbound" | jq -r '.streamSettings.realitySettings.shortIds[0]') + + echo -e "配置类型 : ${GREEN}Reality 配置${NC}" + echo -e "监听地址 : ${GREEN}${ip_address}${NC}" + echo -e "端口 : ${GREEN}${port}${NC}" + echo -e "UUID : ${GREEN}${uuid}${NC}" + echo -e "Flow : ${GREEN}${flow}${NC}" + echo -e "伪装域名 : ${GREEN}${sni}${NC}" + echo -e "Short ID : ${GREEN}${short_id}${NC}" + echo -e "公钥 (pbk) : ${GREEN}${public_key}${NC}" + echo "------------------------------------------" + echo "VLESS 分享链接:" + local vless_link="vless://${uuid}@${ip_address}:${port}?encryption=none&flow=${flow}&security=reality&sni=${sni}&fp=random&pbk=${public_key}&sid=${short_id}&allowInsecure=1&type=tcp&headerType=none#VPS_Reality" + echo -e "${GREEN}${vless_link}${NC}" + fi + echo "------------------------------------------" +} + +# --- 函数: Xray 服务管理 --- +manage_xray_service() { + if ! systemctl list-units --type=service | grep -q "xray.service"; then + echo -e "${RED}Xray 服务未安装。${NC}"; return; fi + case $1 in + start) systemctl start xray && echo -e "${GREEN}服务启动成功。${NC}" || echo -e "${RED}服务启动失败。${NC}" ;; + stop) systemctl stop xray && echo -e "${GREEN}服务已停止。${NC}" || echo -e "${RED}服务停止失败。${NC}" ;; + restart) systemctl restart xray && echo -e "${GREEN}服务重启成功。${NC}" || echo -e "${RED}服务重启失败。${NC}" ;; + status) systemctl status xray ;; + esac +} + +# --- 函数: Xray 主菜单 --- +xray_menu() { + while true; do + clear + echo "==================================================" + echo " XTLS-RPRX-VISION Reality 管理脚本" + echo "==================================================" + check_xray_status + echo "--------------------------------------------------" + echo "1. 安装 Xray 核心" + echo "2. 配置 Reality" + echo "3. 配置 Reality (防偷)" + echo "4. 卸载 Xray" + echo "5. 查看 Xray 配置" + echo "6. 启动 Xray" + echo "7. 停止 Xray" + echo "8. 重启 Xray" + echo "9. 查看运行状态" + echo "0. 退出脚本" + echo "==================================================" + read -p "请输入选项 [0-9]: " choice + + case $choice in + 1) install_xray_core ;; + 2) configure_reality_simple ;; + 3) configure_reality_dokodemo ;; + 4) uninstall_xray ;; + 5) view_config_xray ;; + 6) manage_xray_service start ;; + 7) manage_xray_service stop ;; + 8) manage_xray_service restart ;; + 9) manage_xray_service status ;; + 0) break ;; + *) echo -e "${RED}无效选项,请重试。${NC}" ;; + esac + [ "$choice" != "0" ] && [ "$choice" != "9" ] && read -p "按 Enter 键返回..." + done +} + +# --- 脚本入口 --- +check_root +xray_menu +echo "脚本已退出。" + diff --git a/scripts/snell-v5.sh b/scripts/snell-v5.sh new file mode 100755 index 0000000..61ff3d4 --- /dev/null +++ b/scripts/snell-v5.sh @@ -0,0 +1,422 @@ +#!/bin/bash + +# ============================================================================== +# Snell v5 管理脚本 +# ============================================================================== + +# --- 函数: 检查 Snell 安装和运行状态 --- +check_snell_status() { + # 检查 Snell 是否安装 + if [ -f /usr/local/bin/snell-server ] && [ -f /etc/snell/snell-server.conf ]; then + echo -e "\033[32mSnell 状态: 已安装\033[0m" + else + echo -e "\033[31mSnell 状态: 未安装\033[0m" + fi + + # 检查 Snell 服务是否运行 + if systemctl is-active --quiet snell; then + echo -e "\033[32m服务状态: 运行中\033[0m" + else + echo -e "\033[31m服务状态: 未运行\033[0m" + fi +} + +# --- 函数: 显示菜单 --- +show_menu() { + clear + echo "==================================================" + echo " Snell v5 管理脚本" + echo "==================================================" + check_snell_status + echo "--------------------------------------------------" + echo "1. 安装 Snell" + echo "2. 卸载 Snell" + echo "3. 修改 Snell 配置" + echo "4. 查看 Snell 配置" + echo "5. 查看 Snell 运行状态" + echo "6. 启动 Snell 服务" + echo "7. 停止 Snell 服务" + echo "8. 重启 Snell 服务" + echo "0. 退出脚本" + echo "==================================================" + echo -n "请输入选项 [0-8]: " +} + +# --- 函数: 检查 root 权限 --- +check_root() { + if [ "$(id -u)" -ne 0 ]; then + echo "错误:此脚本需要以 root 权限运行。" >&2 + exit 1 + fi +} + +# --- 函数: 安装 Snell --- +install_snell() { + # --- 新增:检查 Snell 是否已安装 --- + if [ -f /usr/local/bin/snell-server ] && [ -f /etc/snell/snell-server.conf ]; then + echo -e "\033[32mSnell 似乎已经安装,无需重复安装。\033[0m" + return + fi + + # --- 步骤 1: 更新软件包列表并安装必要工具 --- + echo "--> 更新软件包列表并安装必要工具 (wget, unzip, coreutils)..." + if ! apt-get update > /dev/null; then + echo "错误:软件包列表更新失败。请检查网络连接或 apt 源。" + exit 1 + fi + # coreutils 包含 shuf 命令 + if ! apt-get install -y wget unzip coreutils > /dev/null; then + echo "错误:工具安装失败。请检查 apt 源或网络连接。" + exit 1 + fi + echo " 工具安装完成。" + + # --- 步骤 2: 下载、解压并部署 Snell --- + echo "--> 正在下载、解压并部署 Snell 服务器程序..." + if ! wget -q --show-progress https://dl.nssurge.com/snell/snell-server-v5.0.1-linux-amd64.zip -O snell.zip; then + echo "错误:Snell 下载失败!请检查网络或链接是否有效。" + exit 1 + fi + + if ! unzip -o snell.zip -d /usr/local/bin/ > /dev/null; then + echo "错误:Snell 解压失败!" + rm snell.zip + exit 1 + fi + chmod +x /usr/local/bin/snell-server + mkdir -p /etc/snell + rm snell.zip + echo " Snell 程序部署完成。" + + # --- 步骤 3: 用户输入端口和密码 --- + read -p "请输入 Snell 的监听端口 (留空则随机生成): " snell_port + if [ -z "${snell_port}" ]; then + while true; do + snell_port=$(shuf -i 30001-65535 -n 1) + if ! ss -lntu | grep -q ":${snell_port} "; then + echo " 端口未输入,使用随机端口: ${snell_port}" + break + fi + done + fi + + read -p "请输入 Snell 的密码 (PSK,留空则随机生成): " snell_psk + if [ -z "${snell_psk}" ]; then + # --- 新的密码生成逻辑 --- + # 1. 生成14位字母和数字 + ALPHANUM=$(< /dev/urandom tr -dc 'A-Za-z0-9' | head -c 14) + + # 2. 从 '-/@' 中随机选择两个不同的特殊字符 + SPECIAL_CHARS='-/@' + S1_INDEX=$(($RANDOM % 3)) + S1=${SPECIAL_CHARS:$S1_INDEX:1} + REMAINING_CHARS=${SPECIAL_CHARS//$S1/} # 移除已选的字符 + S2_INDEX=$(($RANDOM % 2)) + S2=${REMAINING_CHARS:$S2_INDEX:1} + + # 3. 组合所有字符并打乱顺序 + COMBINED_CHARS="${ALPHANUM}${S1}${S2}" + snell_psk=$(echo "$COMBINED_CHARS" | grep -o . | shuf | tr -d '\n') + + echo " 密码未输入,使用随机密码: ${snell_psk}" + fi + + # --- 步骤 4: 配置确认 --- + echo "" + echo "=============================================" + echo "端口 (Port): ${snell_port}" + echo "密码 (PSK): ${snell_psk}" + echo "=============================================" + echo "安装将在 2 秒后继续,按 Ctrl+C 取消" + sleep 2 + + # --- 步骤 5: 生成配置文件 --- + echo "--> 正在创建配置文件..." + cat > /etc/snell/snell-server.conf < 正在创建 systemd 服务并启动..." + cat > /etc/systemd/system/snell.service < /dev/null 2>&1 + systemctl start snell + + # --- 步骤 7: 显示结果 --- + echo "--> 正在获取服务器公网 IP 地址..." + ip_address=$(curl -s https://ipv4.icanhazip.com || curl -s https://api.ipify.org) + if [ -z "$ip_address" ]; then + echo "警告:无法获取公网 IP 地址,请手动检查。" + fi + + echo "" + echo "==================================================" + echo "🎉 Snell 服务器安装并配置成功!" + echo "" + echo "--------------- 服务状态 ---------------" + systemctl status snell + echo "" + echo "---------- 客户端配置信息 ----------" + echo "在Surge使用以下配置:" + echo "" + echo "vps = snell, ${ip_address:-<您的服务器IP>}, ${snell_port}, psk=${snell_psk}, version=5" + echo "" + echo "==================================================" +} + +# --- 函数: 卸载 Snell --- +uninstall_snell() { + echo "警告:此操作将彻底卸载 Snell 并删除所有相关文件!" + read -p "确定要继续吗?(y/n): " confirm + if [ "$confirm" != "y" ]; then + echo "卸载操作已取消。" + return + fi + + echo "--> 正在停止并禁用 Snell 服务..." + systemctl stop snell > /dev/null 2>&1 + systemctl disable snell > /dev/null 2>&1 + + echo "--> 正在删除 Snell systemd 服务文件..." + rm -f /etc/systemd/system/snell.service + systemctl daemon-reload + + echo "--> 正在删除 Snell 可执行文件..." + rm -f /usr/local/bin/snell-server + + echo "--> 正在删除 Snell 配置文件..." + rm -rf /etc/snell + + echo "--> 正在删除此脚本..." + rm -- "$0" + + echo "" + echo "✅ Snell 已被彻底卸载。" + echo "脚本自身也已被删除。退出。" + exit 0 +} + + +# --- 函数: 修改 Snell 配置 --- +modify_config() { + if [ -f /etc/snell/snell-server.conf ]; then + # --- 步骤 1: 用户输入新端口和密码 --- + read -p "请输入新的 Snell 监听端口 (留空则随机生成): " snell_port + if [ -z "${snell_port}" ]; then + while true; do + snell_port=$(shuf -i 30001-65535 -n 1) + if ! ss -lntu | grep -q ":${snell_port} "; then + echo " 端口未输入,使用随机端口: ${snell_port}" + break + fi + done + fi + + read -p "请输入新的 Snell 密码 (PSK,留空则随机生成): " snell_psk + if [ -z "${snell_psk}" ]; then + # --- 新的密码生成逻辑 --- + # 1. 生成14位字母和数字 + ALPHANUM=$(< /dev/urandom tr -dc 'A-Za-z0-9' | head -c 14) + + # 2. 从 '-/@' 中随机选择两个不同的特殊字符 + SPECIAL_CHARS='-/@' + S1_INDEX=$(($RANDOM % 3)) + S1=${SPECIAL_CHARS:$S1_INDEX:1} + REMAINING_CHARS=${SPECIAL_CHARS//$S1/} # 移除已选的字符 + S2_INDEX=$(($RANDOM % 2)) + S2=${REMAINING_CHARS:$S2_INDEX:1} + + # 3. 组合所有字符并打乱顺序 + COMBINED_CHARS="${ALPHANUM}${S1}${S2}" + snell_psk=$(echo "$COMBINED_CHARS" | grep -o . | shuf | tr -d '\n') + + echo " 密码未输入,使用随机密码: ${snell_psk}" + fi + + # --- 步骤 2: 配置确认 --- + echo "" + echo "=============================================" + echo "新端口 (Port): ${snell_port}" + echo "新密码 (PSK): ${snell_psk}" + echo "=============================================" + echo "配置将在 2 秒后更新,按 Ctrl+C 取消" + sleep 2 + + # --- 步骤 3: 更新配置文件 --- + echo "--> 正在更新配置文件..." + cat > /etc/snell/snell-server.conf < 正在获取服务器公网 IP 地址..." + ip_address=$(curl -s https://ipv4.icanhazip.com || curl -s https://api.ipify.org) + if [ -z "$ip_address" ]; then + echo "警告:无法获取公网 IP 地址,请手动检查。" + fi + + echo "" + echo "==================================================" + echo "🎉 Snell 配置已更新!" + echo "" + echo "---------- 客户端配置信息 ----------" + echo "在Surge使用以下配置:" + echo "" + echo "vps = snell, ${ip_address:-<您的服务器IP>}, ${snell_port}, psk=${snell_psk}, version=5" + echo "" + echo "==================================================" + + # --- 步骤 5: 自动重启服务 --- + restart_snell + else + echo "错误:Snell 配置文件不存在,可能尚未安装。" + fi +} + +# --- 函数: 查看 Snell 配置 --- +view_config() { + if [ -f /etc/snell/snell-server.conf ]; then + echo "--> Snell 配置文件内容:" + cat /etc/snell/snell-server.conf + echo "" + ip_address=$(curl -s https://ipv4.icanhazip.com || curl -s https://api.ipify.org) + # --- 使用 awk 和 cut 准确提取配置 --- + port=$(grep "listen" /etc/snell/snell-server.conf | awk -F':' '{print $NF}') + psk=$(grep "psk" /etc/snell/snell-server.conf | cut -d'=' -f2 | tr -d ' ') + echo "--> 客户端配置信息:" + echo "vps = snell, ${ip_address:-<您的服务器IP>}, ${port}, psk=${psk}, version=5" + else + echo "错误:Snell 配置文件不存在,可能尚未安装。" + fi +} + +# --- 函数: 查看 Snell 运行状态 --- +check_snell_running() { + echo "--> Snell 服务运行状态:" + systemctl status snell +} + +# --- 函数: 启动 Snell 服务 --- +start_snell() { + if [ -f /etc/systemd/system/snell.service ]; then + echo "--> 正在启动 Snell 服务..." + systemctl daemon-reload + systemctl enable snell > /dev/null 2>&1 + if systemctl start snell; then + echo " Snell 服务已启动并启用。" + echo "" + echo "--> Snell 服务运行状态:" + systemctl status snell + else + echo " 错误:Snell 服务启动失败,请使用 'journalctl -u snell' 查看日志。" + echo "" + echo "--> Snell 服务运行状态:" + systemctl status snell + fi + else + echo "错误:Snell 服务未安装。" + fi +} + +# --- 函数: 停止 Snell 服务 --- +stop_snell() { + if systemctl is-active --quiet snell || systemctl is-enabled --quiet snell; then + echo "--> 正在停止 Snell 服务..." + systemctl stop snell + systemctl disable snell > /dev/null 2>&1 + echo " Snell 服务已停止并禁用。" + echo "" + echo "--> Snell 服务运行状态:" + systemctl status snell + else + echo "错误:Snell 服务未安装或未运行。" + fi +} + +# --- 函数: 重启 Snell 服务 --- +restart_snell() { + if [ -f /etc/systemd/system/snell.service ]; then + echo "--> 正在重启 Snell 服务..." + systemctl daemon-reload + systemctl enable snell > /dev/null 2>&1 + if systemctl restart snell; then + echo " Snell 服务已重启并启用。" + echo "" + echo "--> Snell 服务运行状态:" + systemctl status snell + else + echo " 错误:Snell 服务重启失败,请使用 'journalctl -u snell' 查看日志。" + echo "" + echo "--> Snell 服务运行状态:" + systemctl status snell + fi + else + echo "错误:Snell 服务未安装。" + fi +} + +# --- 主程序: 检查 root 权限并显示菜单 --- +check_root + +while true; do + show_menu + read choice + case $choice in + 1) + install_snell + ;; + 2) + uninstall_snell + ;; + 3) + modify_config + ;; + 4) + view_config + ;; + 5) + check_snell_running + ;; + 6) + start_snell + ;; + 7) + stop_snell + ;; + 8) + restart_snell + ;; + 0) + echo "退出脚本。" + exit 0 + ;; + *) + echo "无效选项,请输入 0-8。" + ;; + esac + echo "" + echo "按 Enter 键返回菜单..." + read -r +done diff --git a/scripts/ss2022-shadowtls.sh b/scripts/ss2022-shadowtls.sh new file mode 100755 index 0000000..5139ff5 --- /dev/null +++ b/scripts/ss2022-shadowtls.sh @@ -0,0 +1,518 @@ +#!/bin/bash + +# ================================================================= +# shadowsocks-rust & shadowtls 服务器端综合管理脚本 +# 描述: 提供一个主菜单,分别进入 ss-rust 和 shadowtls 的管理界面。 +# ================================================================= + +# 定义输出颜色 +GREEN='\033[0;32m' +RED='\033[0;31m' +NC='\033[0m' # 无颜色 + +# --- 通用函数 --- +check_root() { + if [ "$(id -u)" -ne 0 ]; then + echo -e "${RED}错误:此脚本需要以 root 权限运行。${NC}" >&2 + exit 1 + fi +} + +# --- 新增函数: 检查是否所有组件都已卸载,如果是则删除脚本 --- +check_and_delete_script_if_all_uninstalled() { + # 检查 ss-rust 和 shadowtls 的二进制文件是否都不存在 + if [ ! -f /usr/local/bin/ss-rust ] && [ ! -f /usr/local/bin/shadowtls ]; then + echo -e "${GREEN}检测到 ss-rust 和 shadowtls 均已卸载。${NC}" + echo "--> 正在删除此脚本..." + rm -- "$0" + echo "脚本自身也已被删除。即将退出。" + exit 0 + fi +} + + +# ================================================================= +# S-S-R-U-S-T M-A-N-A-G-E-M-E-N-T +# ================================================================= + +# --- ss-rust 变量定义 (这里改为了动态获取,不再硬编码版本号) --- +# SS_VERSION, SS_URL, SS_TAR_FILE 将在安装函数中动态生成 + +# --- 函数: 检查 ss-rust 安装和运行状态 --- +check_ss_rust_status() { + if [ -f /usr/local/bin/ss-rust ] && [ -f /etc/systemd/system/ss-rust.service ]; then + echo -e "${GREEN}ss-rust 状态: 已安装${NC}" + else + echo -e "${RED}ss-rust 状态: 未安装${NC}" + fi + + if systemctl is-active --quiet ss-rust; then + echo -e "${GREEN}服务状态 : 运行中${NC}" + else + echo -e "${RED}服务状态 : 未运行${NC}" + fi +} + +# --- 函数: 确保 jq 已安装 --- +ensure_jq() { + if ! command -v jq &> /dev/null || ! command -v curl &> /dev/null; then + echo "--> 检测到依赖工具 jq 或 curl 未安装,正在尝试自动安装..." + if command -v apt-get &> /dev/null; then + apt-get update >/dev/null && apt-get install -y jq curl + elif command -v yum &> /dev/null; then + yum install -y jq curl + else + echo -e "${RED}无法自动安装 jq/curl。请手动安装后再试。${NC}" + return 1 + fi + fi + return 0 +} + +# --- 函数: 安装 ss-rust --- +install_ss_rust() { + if [ -f /usr/local/bin/ss-rust ]; then + echo -e "${GREEN}ss-rust 似乎已经安装,无需重复安装。${NC}" + return + fi + + # --- 新增: 自动获取最新版本逻辑 --- + ensure_jq || exit 1 + echo "--> 正在获取 ss-rust 最新版本号..." + SS_VERSION=$(curl -s "https://api.github.com/repos/shadowsocks/shadowsocks-rust/releases/latest" | jq -r .tag_name) + if [ -z "$SS_VERSION" ] || [ "$SS_VERSION" == "null" ]; then + echo -e "${RED}获取最新版本失败,请检查网络!${NC}" + exit 1 + fi + SS_URL="https://github.com/shadowsocks/shadowsocks-rust/releases/download/${SS_VERSION}/shadowsocks-${SS_VERSION}.x86_64-unknown-linux-gnu.tar.xz" + SS_TAR_FILE="shadowsocks-${SS_VERSION}.x86_64-unknown-linux-gnu.tar.xz" + echo -e "${GREEN}检测到最新版本: ${SS_VERSION}${NC}" + # ---------------------------- + + echo "--> 正在准备安装环境..." + if command -v apt-get &> /dev/null; then + apt-get update && apt-get install -y wget tar xz-utils openssl jq coreutils + elif command -v yum &> /dev/null; then + yum install -y wget tar xz-utils openssl jq coreutils + else + echo -e "${RED}无法确定包管理器,请手动安装 wget, tar, xz-utils, openssl, jq, coreutils。${NC}" + exit 1 + fi + + echo "--> 正在下载、解压并部署 ss-rust..." + if ! wget -O "${SS_TAR_FILE}" "${SS_URL}"; then + echo -e "${RED}下载 ss-rust 失败!请检查网络或链接是否有效。${NC}" + exit 1 + fi + + tar -xf "${SS_TAR_FILE}" + mv ssserver /usr/local/bin/ss-rust + chmod +x /usr/local/bin/ss-rust + rm -f sslocal ssmanager ssurl "${SS_TAR_FILE}" + echo " ss-rust 程序部署完成。" + + mkdir -p /etc/ss-rust + + read -p "请输入 ss-rust 的监听端口 (留空则随机生成): " PORT + [ -z "$PORT" ] && PORT=$((RANDOM % 55536 + 10000)) + + read -p "请输入 ss-rust 的密码 (留空则随机生成): " PASSWORD + [ -z "$PASSWORD" ] && PASSWORD=$(head -c 16 /dev/urandom | base64 -w 0) + + echo "--> 正在创建配置文件..." + cat > /etc/ss-rust/config.json < 正在创建 systemd 服务..." + cat > /etc/systemd/system/ss-rust.service < /dev/null 2>&1 + systemctl start ss-rust + + echo -e "${GREEN}🎉 ss-rust 服务器安装并配置成功!${NC}" + view_config_ss_rust +} + +# --- 函数: 卸载 ss-rust --- +uninstall_ss_rust() { + if [ ! -f /usr/local/bin/ss-rust ]; then + echo -e "${RED}ss-rust 未安装,无需卸载。${NC}" + return + fi + + read -p "警告:确定要卸载 ss-rust 吗?[y/N]: " confirm + if [[ ! "$confirm" =~ ^[yY]([eE][sS])?$ ]]; then + echo "卸载操作已取消。" + return + fi + + systemctl stop ss-rust + systemctl disable ss-rust > /dev/null 2>&1 + rm -f /etc/systemd/system/ss-rust.service + rm -f /usr/local/bin/ss-rust + rm -rf /etc/ss-rust + systemctl daemon-reload + echo -e "${GREEN}ss-rust 已成功卸载。${NC}" + + # 调用检查函数 + check_and_delete_script_if_all_uninstalled +} + +# --- 函数: 修改 ss-rust 配置 --- +modify_config_ss_rust() { + if [ ! -f /etc/ss-rust/config.json ]; then + echo -e "${RED}ss-rust 未安装,无法修改配置。${NC}"; return; fi + ensure_jq || return + + read -p "请输入新的监听端口 (留空则随机生成): " PORT + [ -z "$PORT" ] && PORT=$((RANDOM % 55536 + 10000)) + + read -p "请输入新的密码 (留空则随机生成): " PASSWORD + [ -z "$PASSWORD" ] && PASSWORD=$(head -c 16 /dev/urandom | base64 -w 0) + + jq ".server_port = ${PORT} | .password = \"${PASSWORD}\"" /etc/ss-rust/config.json > /tmp/ss-config.tmp && mv /tmp/ss-config.tmp /etc/ss-rust/config.json + + systemctl restart ss-rust + echo -e "${GREEN}🎉 ss-rust 配置已更新!${NC}" + view_config_ss_rust +} + +# --- 函数: 查看 ss-rust 配置 --- +view_config_ss_rust() { + if [ ! -f /etc/ss-rust/config.json ]; then + echo -e "${RED}ss-rust 未安装,无法查看配置。${NC}"; return; fi + ensure_jq || return + + local port=$(jq .server_port /etc/ss-rust/config.json) + local password=$(jq -r .password /etc/ss-rust/config.json) + local method=$(jq -r .method /etc/ss-rust/config.json) + local ip_address=$(curl -s https://ipv4.icanhazip.com || echo "<您的服务器IP>") + + echo "------------------------------------------" + echo " ss-rust 当前配置信息" + echo "------------------------------------------" + echo -e "端口 (Port) : ${GREEN}${port}${NC}" + echo -e "密码 (Password) : ${GREEN}${password}${NC}" + echo -e "加密 (Method) : ${GREEN}${method}${NC}" + echo "------------------------------------------" + echo "Surge 客户端配置:" + echo -e "${GREEN}VPS = ss, ${ip_address}, ${port}, encrypt-method=${method}, password=${password}, udp-relay=true${NC}" + echo "------------------------------------------" +} + +# --- 函数: ss-rust 服务管理 --- +manage_ss_rust_service() { + if [ ! -f /etc/systemd/system/ss-rust.service ]; then + echo -e "${RED}ss-rust 未安装。${NC}"; return; fi + case $1 in + start) systemctl start ss-rust && echo -e "${GREEN}服务启动成功。${NC}" || echo -e "${RED}服务启动失败。${NC}" ;; + stop) systemctl stop ss-rust && echo -e "${GREEN}服务已停止。${NC}" || echo -e "${RED}服务停止失败。${NC}" ;; + restart) systemctl restart ss-rust && echo -e "${GREEN}服务重启成功。${NC}" || echo -e "${RED}服务重启失败。${NC}" ;; + status) systemctl status ss-rust ;; + esac +} + +# --- 函数: ss-rust 子菜单 --- +ss_rust_menu() { + while true; do + clear + echo "==================================================" + echo " shadowsocks-rust 管理界面" + echo "==================================================" + check_ss_rust_status + echo "--------------------------------------------------" + echo "1. 安装 ss-rust" + echo "2. 卸载 ss-rust" + echo "3. 修改 ss-rust 配置" + echo "4. 查看 ss-rust 配置" + echo "5. 启动 ss-rust" + echo "6. 停止 ss-rust" + echo "7. 重启 ss-rust" + echo "8. 查看运行状态" + echo "0. 返回主菜单" + echo "==================================================" + read -p "请输入选项 [0-8]: " choice + + case $choice in + 1) install_ss_rust ;; + 2) uninstall_ss_rust ;; + 3) modify_config_ss_rust ;; + 4) view_config_ss_rust ;; + 5) manage_ss_rust_service start ;; + 6) manage_ss_rust_service stop ;; + 7) manage_ss_rust_service restart ;; + 8) manage_ss_rust_service status ;; + 0) return ;; + *) echo -e "${RED}无效选项,请重试。${NC}" ;; + esac + [ "$choice" != "0" ] && read -p "按 Enter 键返回..." + done +} + + +# ================================================================= +# S-H-A-D-O-W-T-L-S M-A-N-A-G-E-M-E-N-T +# ================================================================= + +# --- shadowtls 变量定义 --- +STLS_URL="https://github.com/ihciah/shadow-tls/releases/download/v0.2.25/shadow-tls-x86_64-unknown-linux-musl" + +# --- 函数: 检查 shadowtls 安装和运行状态 --- +check_shadowtls_status() { + if [ -f /usr/local/bin/shadowtls ] && [ -f /etc/systemd/system/shadowtls.service ]; then + echo -e "${GREEN}shadowtls 状态: 已安装${NC}" + else + echo -e "${RED}shadowtls 状态: 未安装${NC}" + fi + + if systemctl is-active --quiet shadowtls; then + echo -e "${GREEN}服务状态 : 运行中${NC}" + else + echo -e "${RED}服务状态 : 未运行${NC}" + fi +} + +# --- 函数: 安装 shadowtls --- +install_shadowtls() { + if [ -f /usr/local/bin/shadowtls ]; then + echo -e "${GREEN}shadowtls 似乎已经安装。${NC}"; return; fi + + echo "--> 正在下载 shadowtls..." + curl -L "$STLS_URL" -o /usr/local/bin/shadowtls + chmod +x /usr/local/bin/shadowtls + + read -p "请输入 shadowtls 监听端口 (留空默认 8443): " LISTEN_PORT + [ -z "$LISTEN_PORT" ] && LISTEN_PORT=8443 + + read -p "请输入后端的 ss-rust 端口: " SS_PORT + while [ -z "$SS_PORT" ]; do + read -p "${RED}后端 ss-rust 端口不能为空,请重新输入: ${NC}" SS_PORT + done + + read -p "请输入伪装域名 (留空默认 www.muji.com): " SNI_HOST + [ -z "$SNI_HOST" ] && SNI_HOST="www.muji.com" + + read -p "请输入 shadowtls 密码 (留空随机生成): " PASSWORD + if [ -z "$PASSWORD" ]; then + ALPHANUM=$(< /dev/urandom tr -dc 'A-Za-z0-9' | head -c 14) + SPECIAL_CHARS='-/@' + S1_INDEX=$(($RANDOM % 3)); S1=${SPECIAL_CHARS:$S1_INDEX:1} + REMAINING_CHARS=${SPECIAL_CHARS//$S1/}; S2_INDEX=$(($RANDOM % 2)); S2=${REMAINING_CHARS:$S2_INDEX:1} + COMBINED_CHARS="${ALPHANUM}${S1}${S2}" + PASSWORD=$(echo "$COMBINED_CHARS" | grep -o . | shuf | tr -d '\n') + fi + + echo "--> 正在创建 systemd 服务..." + cat > /etc/systemd/system/shadowtls.service < /dev/null 2>&1 + systemctl start shadowtls + echo -e "${GREEN}🎉 shadowtls 服务器安装并配置成功!${NC}" + view_config_shadowtls +} + +# --- 函数: 卸载 shadowtls --- +uninstall_shadowtls() { + if [ ! -f /usr/local/bin/shadowtls ]; then + echo -e "${RED}shadowtls 未安装。${NC}"; return; fi + + read -p "警告:确定要卸载 shadowtls 吗?[y/N]: " confirm + if [[ ! "$confirm" =~ ^[yY]([eE][sS])?$ ]]; then + echo "卸载操作已取消。"; return; fi + + systemctl stop shadowtls + systemctl disable shadowtls > /dev/null 2>&1 + rm -f /etc/systemd/system/shadowtls.service + rm -f /usr/local/bin/shadowtls + systemctl daemon-reload + echo -e "${GREEN}shadowtls 已成功卸载。${NC}" + + # 调用检查函数 + check_and_delete_script_if_all_uninstalled +} + +# --- 函数: 查看 shadowtls 配置 --- +view_config_shadowtls() { + if [ ! -f /etc/systemd/system/shadowtls.service ]; then + echo -e "${RED}shadowtls 未安装。${NC}"; return; fi + + local exec_start=$(grep 'ExecStart=' /etc/systemd/system/shadowtls.service) + # 使用更通用的正则表达式解析端口,以提高兼容性 + local listen_port=$(echo "$exec_start" | sed -n 's/.*--listen [^ ]*:\([0-9]*\).*/\1/p') + local server_port=$(echo "$exec_start" | sed -n 's/.*--server [^ ]*:\([0-9]*\).*/\1/p') + local sni_host=$(echo "$exec_start" | sed -n 's/.*--tls \([^:]*\):443.*/\1/p') + local stls_password=$(echo "$exec_start" | sed -n 's/.*--password \([^ ]*\).*/\1/p') + local ip_address=$(curl -s https://ipv4.icanhazip.com || echo "<您的服务器IP>") + + local ss_password="" + local ss_method="2022-blake3-aes-128-gcm" + if [ -f /etc/ss-rust/config.json ] && ensure_jq; then + ss_password=$(jq -r .password /etc/ss-rust/config.json) + ss_method=$(jq -r .method /etc/ss-rust/config.json) + fi + + echo "------------------------------------------" + echo " shadowtls 当前配置信息" + echo "------------------------------------------" + echo -e "监听端口 : ${GREEN}${listen_port}${NC}" + echo -e "密码 : ${GREEN}${stls_password}${NC}" + echo -e "后端 SS 端口: ${GREEN}${server_port}${NC}" + echo -e "伪装域名 : ${GREEN}${sni_host}${NC}" + echo "------------------------------------------" + echo "Surge 客户端配置:" + echo -e "${GREEN}VPS = ss, ${ip_address}, ${listen_port}, encrypt-method=${ss_method}, password=${ss_password}, shadow-tls-password=${stls_password}, shadow-tls-sni=${sni_host}, shadow-tls-version=3, udp-relay=true${NC}" + echo "------------------------------------------" +} + +# --- 函数: 修改 shadowtls 配置 --- +modify_config_shadowtls() { + if [ ! -f /etc/systemd/system/shadowtls.service ]; then + echo -e "${RED}shadowtls 未安装。${NC}"; return; fi + + read -p "请输入新的 shadowtls 监听端口 (留空默认 8443): " LISTEN_PORT + [ -z "$LISTEN_PORT" ] && LISTEN_PORT=8443 + + read -p "请输入新的后端 ss-rust 端口: " SS_PORT + while [ -z "$SS_PORT" ]; do + read -p "${RED}后端 ss-rust 端口不能为空,请重新输入: ${NC}" SS_PORT + done + + read -p "请输入新的伪装域名 (留空默认 www.muji.com): " SNI_HOST + [ -z "$SNI_HOST" ] && SNI_HOST="www.muji.com" + + read -p "请输入新的 shadowtls 密码 (留空随机): " PASSWORD + if [ -z "$PASSWORD" ]; then + ALPHANUM=$(< /dev/urandom tr -dc 'A-Za-z0-9' | head -c 14) + SPECIAL_CHARS='-/@' + S1_INDEX=$(($RANDOM % 3)); S1=${SPECIAL_CHARS:$S1_INDEX:1} + REMAINING_CHARS=${SPECIAL_CHARS//$S1/}; S2_INDEX=$(($RANDOM % 2)); S2=${REMAINING_CHARS:$S2_INDEX:1} + COMBINED_CHARS="${ALPHANUM}${S1}${S2}" + PASSWORD=$(echo "$COMBINED_CHARS" | grep -o . | shuf | tr -d '\n') + fi + + local exec_line="ExecStart=/usr/local/bin/shadowtls --v3 --strict server --listen 0.0.0.0:${LISTEN_PORT} --server 127.0.0.1:${SS_PORT} --tls ${SNI_HOST}:443 --password ${PASSWORD}" + sed -i "s|^ExecStart=.*|$exec_line|" /etc/systemd/system/shadowtls.service + + systemctl daemon-reload + systemctl restart shadowtls + echo -e "${GREEN}🎉 shadowtls 配置已更新!${NC}" + view_config_shadowtls +} + +# --- 函数: shadowtls 服务管理 --- +manage_shadowtls_service() { + if [ ! -f /etc/systemd/system/shadowtls.service ]; then + echo -e "${RED}shadowtls 未安装。${NC}"; return; fi + case $1 in + start) systemctl start shadowtls && echo -e "${GREEN}服务启动成功。${NC}" || echo -e "${RED}服务启动失败。${NC}" ;; + stop) systemctl stop shadowtls && echo -e "${GREEN}服务已停止。${NC}" || echo -e "${RED}服务停止失败。${NC}" ;; + restart) systemctl restart shadowtls && echo -e "${GREEN}服务重启成功。${NC}" || echo -e "${RED}服务重启失败。${NC}" ;; + status) systemctl status shadowtls ;; + esac +} + +# --- 函数: shadowtls 子菜单 --- +shadowtls_menu() { + while true; do + clear + echo "==================================================" + echo " shadowtls 管理界面" + echo "==================================================" + check_shadowtls_status + echo "--------------------------------------------------" + echo "1. 安装 shadowtls" + echo "2. 卸载 shadowtls" + echo "3. 修改 shadowtls 配置" + echo "4. 查看 shadowtls 配置" + echo "5. 启动 shadowtls" + echo "6. 停止 shadowtls" + echo "7. 重启 shadowtls" + echo "8. 查看运行状态" + echo "0. 返回主菜单" + echo "==================================================" + read -p "请输入选项 [0-8]: " choice + + case $choice in + 1) install_shadowtls ;; + 2) uninstall_shadowtls ;; + 3) modify_config_shadowtls ;; + 4) view_config_shadowtls ;; + 5) manage_shadowtls_service start ;; + 6) manage_shadowtls_service stop ;; + 7) manage_shadowtls_service restart ;; + 8) manage_shadowtls_service status ;; + 0) return ;; + *) echo -e "${RED}无效选项,请重试。${NC}" ;; + esac + [ "$choice" != "0" ] && read -p "按 Enter 键返回..." + done +} + + +# ================================================================= +# M-A-I-N M-E-N-U +# ================================================================= +main_menu() { + while true; do + clear + echo "==================================================" + echo " SS-Rust & ShadowTLS 综合管理脚本" + echo "==================================================" + echo "1. shadowsocks-rust 管理" + echo "2. shadowtls 管理" + echo "0. 退出脚本" + echo "==================================================" + read -p "请输入选项 [0-2]: " choice + + case $choice in + 1) ss_rust_menu ;; + 2) shadowtls_menu ;; + 0) break ;; + *) echo -e "${RED}无效选项,请重试。${NC}"; sleep 1 ;; + esac + done +} + +# --- 脚本入口 --- +check_root +main_menu +echo "脚本已退出。"