set -e SCRIPT_VERSION="V1.0.0" xray_config_path="/usr/local/etc/xray/config.json" xray_binary_path="/usr/local/bin/xray" xray_install_script_url="https://github.com/XTLS/Xray-install/raw/main/install-release.sh" xray_status_info="" is_quiet=false PKG_MANAGER="" C_RESET='\033[0m' C_RED='\033[0;31m' C_GREEN='\033[0;32m' C_YELLOW='\033[0;33m' C_BLUE='\033[0;34m' C_PURPLE='\033[0;35m' C_CYAN='\033[0;36m' if [ -t 1 ]; then use_color=true else use_color=false fi cecho() { local color_name="$1" local message="$2" if [ "$use_color" = true ] && [ -n "$color_name" ]; then echo -e "${color_name}${message}${C_RESET}" else echo "$message" fi } error() { cecho "$C_RED" "[✖] $1" >&2 } info() { if [ "$is_quiet" = false ]; then cecho "$C_BLUE" "[!] $1" >&2 fi } success() { if [ "$is_quiet" = false ]; then cecho "$C_GREEN" "[✔] $1" >&2 fi } get_public_ip_v4() { local ip local sources=( "https://api-ipv4.ip.sb/ip" "https://api.ipify.org" "https://ip.seeip.org" ) for source in "${sources[@]}"; do ip=$(curl -4s --max-time 5 "$source" 2>/dev/null) if echo "$ip" | grep -qE '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$'; then echo "$ip" return fi done echo "" } get_public_ip_v6() { local ip local sources=( "https://api-ipv6.ip.sb/ip" "https://api64.ipify.org" ) for source in "${sources[@]}"; do ip=$(curl -6s --max-time 5 "$source" 2>/dev/null) if echo "$ip" | grep -q ':'; then echo "$ip" return fi done echo "" } execute_official_script() { local args="$1" local script_content info "正在下载官方安装脚本..." script_content=$(curl -sL "$xray_install_script_url") if [[ -z "$script_content" || ! "$script_content" =~ "install-release" ]]; then error "下载 Xray 官方安装脚本失败或内容异常!请检查网络连接。" return 1 fi info "正在执行官方安装脚本 ( $args )..." echo "$script_content" | bash -s -- $args } check_xray_version() { if [ ! -f "$xray_binary_path" ]; then return 1 fi if ! $xray_binary_path help 2>/dev/null | grep -q "vlessenc"; then return 1 fi return 0 } check_os_and_dependencies() { info "正在检查操作系统和依赖..." if command -v apt >/dev/null 2>&1; then PKG_MANAGER="apt" elif command -v dnf >/dev/null 2>&1; then PKG_MANAGER="dnf" elif command -v yum >/dev/null 2>&1; then PKG_MANAGER="yum" else error "错误: 未知的包管理器, 此脚本仅支持 apt, dnf, yum." exit 1 fi if ! command -v jq >/dev/null 2>&1 || ! command -v curl >/dev/null 2>&1; then info "检测到缺失的依赖 (jq/curl),正在尝试自动安装..." case "$PKG_MANAGER" in apt) apt-get update >/dev/null 2>&1 apt-get install -y jq curl >/dev/null 2>&1 ;; dnf | yum) "$PKG_MANAGER" install -y jq curl >/dev/null 2>&1 ;; esac if ! command -v jq >/dev/null 2>&1 || ! command -v curl >/dev/null 2>&1; then error "依赖 (jq/curl) 自动安装失败。请手动安装后重试。" exit 1 fi success "依赖已成功安装。" fi } pre_check() { if [ "$(id -u)" != "0" ]; then error "错误: 您必须以root用户身份运行此脚本" exit 1 fi check_os_and_dependencies } check_xray_status() { if [ ! -f "$xray_binary_path" ]; then xray_status_info="$(cecho "$C_YELLOW" "Xray 状态: 未安装")" return fi local xray_version=$($xray_binary_path version 2>/dev/null | head -n 1 | awk '{print $2}' || echo "未知") local service_status if systemctl is-active --quiet xray 2>/dev/null; then service_status="$(cecho "$C_GREEN" "运行中")" else service_status="$(cecho "$C_RED" "未运行")" fi local encryption_support if check_xray_version; then encryption_support=" | $(cecho "$C_GREEN" "支持 VLESS Encryption")" else encryption_support=" | $(cecho "$C_RED" "不支持 VLESS Encryption")" fi xray_status_info="Xray 状态: $(cecho "$C_GREEN" "已安装") | ${service_status} | 版本: $(cecho "$C_CYAN" "$xray_version")${encryption_support}" } is_valid_port() { local port="$1" if echo "$port" | grep -q '^[0-9]\+$' && [ "$port" -ge 1 ] && [ "$port" -le 65535 ]; then return 0 else return 1 fi } generate_uuid() { if [ -f "$xray_binary_path" ] && [ -x "$xray_binary_path" ]; then $xray_binary_path uuid else cat /proc/sys/kernel/random/uuid fi } generate_vless_encryption_config() { info "正在生成 VLESS Encryption 配置 (native + 0-RTT + ML-KEM-768)..." local vlessenc_output vlessenc_output=$($xray_binary_path vlessenc 2>/dev/null) if [ -z "$vlessenc_output" ]; then error "生成 VLESS Encryption 配置失败" return 1 fi local decryption_config="" local encryption_config="" local in_mlkem_section=false local parsing_encryption=false while IFS= read -r line; do if [ "$in_mlkem_section" = true ] && [[ "$line" != *'"decryption":'* ]] && [[ "$line" != *'"encryption":'* ]] && [[ "$parsing_encryption" = false ]] && [ -n "$decryption_config" ] && [ -n "$encryption_config" ]; then if [[ ! "$line" =~ ^[[:space:]]*"\"" ]]; then break fi fi if [[ "$line" == *"Authentication: ML-KEM-768, Post-Quantum"* ]]; then in_mlkem_section=true continue fi if [ "$in_mlkem_section" = false ]; then continue fi if [ "$parsing_encryption" = true ]; then encryption_config+="${line}" if [[ "$line" == *"\"" ]]; then parsing_encryption=false encryption_config=$(echo "$encryption_config" | sed 's/"$//' | tr -d '[:space:]') fi continue fi if [[ "$line" == *'"decryption":'* ]]; then decryption_config=$(echo "$line" | sed 's/.*"decryption": "\([^"]*\)".*/\1/') continue fi if [[ "$line" == *'"encryption":'* ]]; then parsing_encryption=true encryption_config=$(echo "$line" | sed 's/.*"encryption": "\([^"]*\).*/\1/') if [[ "$line" == *"\"" ]]; then parsing_encryption=false encryption_config=$(echo "$encryption_config" | sed 's/"$//' | tr -d '[:space:]') fi fi done <<< "$vlessenc_output" if [ -z "$decryption_config" ] || [ -z "$encryption_config" ]; then error "无法解析 VLESS Encryption 配置。请确保您的 Xray 版本支持此功能。" return 1 fi echo "${decryption_config}|${encryption_config}" } install_xray() { if [ -f "$xray_binary_path" ]; then if ! check_xray_version; then info "检测到已安装的 Xray 版本不支持 VLESS Encryption,需要更新。" else info "检测到 Xray 已安装。继续操作将覆盖现有配置。" fi echo -n "是否继续?[y/N]: " read -r confirm if [ "$confirm" != "y" ] && [ "$confirm" != "Y" ]; then info "操作已取消。" return fi fi info "开始配置 VLESS Encryption (native + 0-RTT + ML-KEM-768)..." local port uuid while true; do echo -n "请输入端口 [1-65535] (默认: 443): " read -r port [ -z "$port" ] && port=443 if is_valid_port "$port"; then break else error "端口无效,请输入一个1-65535之间的数字。" fi done echo -n "请输入UUID (留空将默认生成随机UUID): " read -r uuid if [ -z "$uuid" ]; then uuid=$(generate_uuid) info "已为您生成随机UUID: ${uuid}" fi run_install "$port" "$uuid" } update_xray() { if [ ! -f "$xray_binary_path" ]; then error "错误: Xray 未安装,无法执行更新。请先选择安装选项。" return fi info "正在检查最新版本..." local current_version latest_version current_version=$($xray_binary_path version | head -n 1 | awk '{print $2}' | sed 's/v//') latest_version=$(curl -s https://api.github.com/repos/XTLS/Xray-core/releases/latest | jq -r '.tag_name' | sed 's/v//' 2>/dev/null || echo "") if [ -z "$latest_version" ]; then error "获取最新版本号失败,请检查网络或稍后再试。" return fi info "当前版本: ${current_version},最新版本: ${latest_version}" if [ "$current_version" = "$latest_version" ] && check_xray_version; then success "您的 Xray 已是最新版本且支持 VLESS Encryption,无需更新。" return fi info "开始更新..." if ! execute_official_script "install"; then error "Xray 核心更新失败!" return fi info "正在更新 GeoIP 和 GeoSite 数据文件..." execute_official_script "install-geodata" if ! restart_xray; then return; fi success "Xray 更新成功!" } restart_xray() { if [ ! -f "$xray_binary_path" ]; then error "错误: Xray 未安装,无法重启。" return 1 fi info "正在重启 Xray 服务..." if ! systemctl restart xray; then error "错误: Xray 服务重启失败, 请使用菜单 5 查看日志检查具体原因。" return 1 fi sleep 1 if ! systemctl is-active --quiet xray; then error "错误: Xray 服务启动失败, 请使用菜单 5 查看日志检查具体原因。" return 1 fi success "Xray 服务已成功重启!" return 0 } uninstall_xray() { if [ ! -f "$xray_binary_path" ]; then error "错误: Xray 未安装,无需卸载。" return fi echo -n "您确定要卸载 Xray 吗?这将删除所有相关文件。[Y/n]: " read -r confirm if [ "$confirm" = "n" ] || [ "$confirm" = "N" ]; then info "卸载操作已取消。" return fi info "正在卸载 Xray..." if execute_official_script "remove --purge"; then rm -f ~/xray_vless_encryption_link.txt ~/xray_encryption_info.txt success "Xray 已成功卸载。" else error "Xray 卸载失败!" return 1 fi } view_xray_log() { if [ ! -f "$xray_binary_path" ]; then error "错误: Xray 未安装,无法查看日志。" return fi info "正在显示 Xray 实时日志... 按 Ctrl+C 退出。" journalctl -u xray -f --no-pager } modify_config() { if [ ! -f "$xray_config_path" ]; then error "错误: Xray 未安装,无法修改配置。" return fi info "读取当前配置..." local current_port current_uuid current_port=$(jq -r '.inbounds[0].port' "$xray_config_path") current_uuid=$(jq -r '.inbounds[0].settings.clients[0].id' "$xray_config_path") info "请输入新配置,直接回车则保留当前值。" local port uuid while true; do echo -n "端口 (当前: ${current_port}): " read -r port [ -z "$port" ] && port=$current_port if is_valid_port "$port"; then break else error "端口无效,请输入一个1-65535之间的数字。" fi done echo -n "UUID (当前: ${current_uuid}): " read -r uuid [ -z "$uuid" ] && uuid=$current_uuid local encryption_info encryption_info=$(generate_vless_encryption_config) if [ -z "$encryption_info" ]; then return 1 fi local decryption_config encryption_config decryption_config=$(echo "$encryption_info" | cut -d'|' -f1) encryption_config=$(echo "$encryption_info" | cut -d'|' -f2) write_config "$port" "$uuid" "$decryption_config" "$encryption_config" if ! restart_xray; then return; fi success "配置修改成功!" view_subscription_info } view_subscription_info() { if [ ! -f "$xray_config_path" ]; then error "错误: 配置文件不存在, 请先安装。" return fi local ip4 ip6 ip4=$(get_public_ip_v4) ip6=$(get_public_ip_v6) if [ -z "$ip4" ] && [ -z "$ip6" ]; then error "无法获取任何公网 IP 地址 (IPv4 或 IPv6),无法生成订阅链接。" return 1 fi local display_ip=${ip4:-$ip6} if [ -z "$display_ip" ]; then error "无法获取有效的公网IP地址。" return 1 fi local uuid port encryption uuid=$(jq -r '.inbounds[0].settings.clients[0].id' "$xray_config_path") port=$(jq -r '.inbounds[0].port' "$xray_config_path") if [ ! -f ~/xray_encryption_info.txt ]; then error "缺少客户端 encryption 信息文件,请重新安装以修复。" return fi encryption=$(cat ~/xray_encryption_info.txt 2>/dev/null) if [ -z "$encryption" ]; then error "缺少客户端 encryption 信息,可能是旧版配置,请重新安装以修复。" return fi local link_name_encoded link_name_encoded="$(hostname)%20VLESS-E" local address_for_url=$display_ip if [[ $display_ip == *":"* ]]; then address_for_url="[${display_ip}]" fi local vless_url="vless://${uuid}@${address_for_url}:${port}?encryption=${encryption}&flow=xtls-rprx-vision&type=tcp&security=none#${link_name_encoded}" if [ "$is_quiet" = true ]; then echo "${vless_url}" else echo "${vless_url}" > ~/xray_vless_encryption_link.txt echo "----------------------------------------------------------------" cecho "$C_CYAN" " --- Xray VLESS-Encryption 订阅信息 --- " echo " 名称: $(cecho "$C_GREEN" "$(hostname) VLESS-E")" if [ -n "$ip4" ]; then echo " 地址(IPv4): $(cecho "$C_GREEN" "$ip4")" fi if [ -n "$ip6" ]; then echo " 地址(IPv6): $(cecho "$C_GREEN" "$ip6")" fi echo " 端口: $(cecho "$C_GREEN" "$port")" echo " UUID: $(cecho "$C_GREEN" "$uuid")" echo " 协议: $(cecho "$C_YELLOW" "VLESS Encryption (native + 0-RTT + ML-KEM-768)")" echo " 流控: $(cecho "$C_YELLOW" "xtls-rprx-vision")" echo "----------------------------------------------------------------" cecho "$C_GREEN" " 订阅链接 (已保存到 ~/xray_vless_encryption_link.txt): " echo cecho "$C_GREEN" "$vless_url" echo "----------------------------------------------------------------" fi } write_config() { local port="$1" uuid="$2" decryption_config="$3" encryption_config="$4" echo "$encryption_config" > ~/xray_encryption_info.txt jq -n \ --argjson port "$port" \ --arg uuid "$uuid" \ --arg decryption "$decryption_config" \ --arg flow "xtls-rprx-vision" \ '{ "log": {"loglevel": "warning"}, "inbounds": [{ "listen": "::", "port": $port, "protocol": "vless", "settings": { "clients": [{"id": $uuid, "flow": $flow}], "decryption": $decryption } }], "outbounds": [{ "protocol": "freedom", "settings": { "domainStrategy": "UseIPv4v6" } }] }' > "$xray_config_path" chmod 644 "$xray_config_path" chown root:root "$xray_config_path" } run_install() { local port="$1" uuid="$2" info "正在下载并安装 Xray 核心..." if ! execute_official_script "install"; then error "Xray 核心安装失败!请检查网络连接。" exit 1 fi info "正在安装/更新 GeoIP 和 GeoSite 数据文件..." execute_official_script "install-geodata" if ! check_xray_version; then error "安装的 Xray 版本不支持 VLESS Encryption!请检查安装的版本。" exit 1 fi local encryption_info encryption_info=$(generate_vless_encryption_config) if [ -z "$encryption_info" ]; then error "生成 VLESS Encryption 配置失败!" exit 1 fi local decryption_config encryption_config decryption_config=$(echo "$encryption_info" | cut -d'|' -f1) encryption_config=$(echo "$encryption_info" | cut -d'|' -f2) info "正在写入 Xray 配置文件..." write_config "$port" "$uuid" "$decryption_config" "$encryption_config" if ! restart_xray; then exit 1; fi success "Xray VLESS Encryption 安装/配置成功!" view_subscription_info } press_any_key_to_continue() { echo "" cecho "$C_YELLOW" "按任意键返回主菜单..." read -r -n 1 -s } main_menu() { while true; do clear cecho "$C_CYAN" "--- Xray VLESS-Encryption 一键安装管理脚本 v${SCRIPT_VERSION} ---" echo check_xray_status echo " ${xray_status_info}" cecho "$C_GREEN" "─────────────────────────────────────────────────────" cecho "$C_GREEN" " 1. 安装/重装 Xray (VLESS-Encryption)" cecho "$C_GREEN" " 2. 更新 Xray" cecho "$C_GREEN" " 3. 重启 Xray" cecho "$C_GREEN" " 4. 卸载 Xray" cecho "$C_GREEN" " 5. 查看 Xray 日志" cecho "$C_GREEN" " 6. 修改节点配置" cecho "$C_GREEN" " 7. 查看订阅信息" cecho "$C_GREEN" "─────────────────────────────────────────────────────" cecho "$C_RED" " 0. 退出脚本" cecho "$C_GREEN" "─────────────────────────────────────────────────────" cecho "$C_YELLOW" " 注意: 使用 native + 0-RTT + ML-KEM-768 + xtls-rprx-vision" cecho "$C_GREEN" "─────────────────────────────────────────────────────" echo -n " 请输入选项 [0-7]: " read -r choice local needs_pause=true case $choice in 1) install_xray ;; 2) update_xray ;; 3) restart_xray ;; 4) uninstall_xray ;; 5) view_xray_log; needs_pause=false ;; 6) modify_config ;; 7) view_subscription_info ;; 0) success "感谢使用!"; exit 0 ;; *) error "无效选项,请输入 0-7 之间的数字。" ;; esac if [ "$needs_pause" = true ]; then press_any_key_to_continue fi done } main() { pre_check if [ $# -gt 0 ] && [ "$1" = "install" ]; then shift local port="" uuid="" while [ $# -gt 0 ]; do case "$1" in --port) port="$2"; shift 2 ;; --uuid) uuid="$2"; shift 2 ;; --quiet|-q) is_quiet=true; shift ;; *) error "未知参数: $1"; exit 1 ;; esac done [ -z "$port" ] && port=443 if [ -z "$uuid" ]; then uuid=$(generate_uuid) fi if ! is_valid_port "$port"; then error "参数无效。请检查端口格式。" exit 1 fi run_install "$port" "$uuid" else main_menu fi } show_help() { echo "Xray VLESS-Encryption 一键安装管理脚本 $SCRIPT_VERSION" echo echo "用法:" echo " $0 # 交互式菜单" echo " $0 install [选项] # 静默安装" echo echo "安装选项:" echo " --port <端口> # 监听端口 (默认: 443)" echo " --uuid # 用户UUID (默认: 自动生成)" echo " --quiet, -q # 静默模式,只输出订阅链接" echo echo "固定配置 (最优设置):" echo " 协议: VLESS Encryption" echo " 外观: native (原生外观,性能最佳,支持XTLS完全穿透)" echo " RTT: 0rtt (密钥复用600秒,性能优化)" echo " 认证: mlkem768 (ML-KEM-768 抗量子加密)" echo " 流控: xtls-rprx-vision (推荐的流控方式)" echo echo "示例:" echo " $0 install --port 8443" echo " $0 install --quiet --uuid 12345678-1234-1234-1234-123456789abc" echo } if [ $# -gt 0 ] && { [ "$1" = "--help" ] || [ "$1" = "-h" ]; }; then show_help exit 0 fi main "$@"