├── README.md ├── extras ├── one-bake.sh └── sing-box │ └── config.json └── one.sh /README.md: -------------------------------------------------------------------------------- 1 | # VPS一键管理脚本 2 | 3 | ## 自用的vps常用命令脚本,适用于debian与ubuntu系统,目前集成以下功能: 4 | 5 | - 查看系统配置信息; 6 | - 系统优化:更新、清理、开启BBR及ROOT登录等; 7 | - 常用工具:查找、删除、关闭进程、开启端口等; 8 | - 常用软件包安装与卸载; 9 | - 域名证书申请; 10 | - Xray官方安装、配置及卸载; 11 | - Hysteria2官方安装、配置及卸载; 12 | - Sing-Box官方安装、配置及卸载; 13 | - 1Panel官方安装、配置及卸载; 14 | - 其他功能是否添加看个人需要。 15 | 16 | ## 直接使用命令 17 | 18 | ```Bash 19 | bash <(curl -sL https://raw.githubusercontent.com/sezhai/vps-script/refs/heads/main/one.sh) 20 | ``` 21 | 22 | ## 下载使用命令 23 | 24 | ### 下载 25 | ```Bash 26 | bash -c 'curl -sL https://raw.githubusercontent.com/sezhai/vps-script/refs/heads/main/one.sh -o /usr/local/sbin/one && chmod +x /usr/local/sbin/one && /usr/local/sbin/one' 27 | ``` 28 | ### 运行 29 | ```Bash 30 | one 31 | ``` 32 | ### 卸载 33 | ```Bash 34 | sudo rm -f /usr/local/sbin/one 35 | ``` 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /extras/one-bake.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # VPS 管理脚本 3 | 4 | # ----------------------------------------------------------------------------- 5 | # 函数定义 6 | # ----------------------------------------------------------------------------- 7 | 8 | # 主菜单函数 9 | display_main_menu() { 10 | clear 11 | echo "=========================================" 12 | echo -e " \e[1;96mVPS管理脚本\e[0m" 13 | echo "=========================================" 14 | echo "1) 系统信息" 15 | echo "2) 系统优化" 16 | echo "3) 常用工具" 17 | echo "4) 常用软件包" 18 | echo "5) 申请证书" 19 | echo "6) 安装Xray" 20 | echo "7) 安装hysteria2" 21 | echo "8) 安装sing-box" 22 | echo "9) 安装1Panel" 23 | echo "=========================================" 24 | } 25 | 26 | # 系统信息 27 | view_vps_info() { 28 | echo -e "\e[1;34m主机名:\e[0m \e[32m$(hostname)\e[0m" 29 | echo -e "\e[1;34m系统版本:\e[0m \e[32m$(lsb_release -ds 2>/dev/null || grep PRETTY_NAME /etc/os-release | cut -d '"' -f2)\e[0m" 30 | echo -e "\e[1;34mLinux版本:\e[0m \e[32m$(uname -r)\e[0m" 31 | echo "-------------" 32 | echo -e "\e[1;34mCPU架构:\e[0m \e[32m$(uname -m)\e[0m" 33 | echo -e "\e[1;34mCPU型号:\e[0m \e[32m$(lscpu | grep 'Model name' | sed 's/Model name:[ \t]*//')\e[0m" 34 | echo -e "\e[1;34mCPU核心数:\e[0m \e[32m$(nproc)\e[0m" 35 | echo -e "\e[1;34mCPU频率:\e[0m \e[32m$(lscpu | grep 'CPU MHz' | awk -F: '{print $2}' | xargs) MHz\e[0m" 36 | echo "-------------" 37 | echo -e "\e[1;34mCPU占用:\e[0m \e[32m$(top -bn1 | grep 'Cpu(s)' | awk '{print $2 + $4}')%\e[0m" 38 | echo -e "\e[1;34m系统负载:\e[0m \e[32m$(awk '{print $1, $2, $3}' /proc/loadavg)\e[0m" 39 | local mem_info=$(free -m | awk '/Mem:/ {total=$2; used=$3; if (total > 0) printf "%.2f/%.2f MB (%.2f%%)", used, total, used*100/total; else print "数据不可用"}') 40 | echo -e "\e[1;34m物理内存:\e[0m \e[32m$mem_info \e[0m" 41 | local swap_info=$(free -m | awk '/Swap:/ {total=$2; used=$3; if (total > 0) printf "%.0fMB/%.0fMB (%.0f%%)", used, total, used*100/total; else print "数据不可用" }') 42 | echo -e "\e[1;34m虚拟内存:\e[0m \e[32m$swap_info\e[0m" 43 | 44 | echo -e "\e[1;34m硬盘占用:\e[0m \e[32m$(df -h / | awk '/\// {print $3 "/" $2 " (" $5 ")"}')\e[0m" 45 | echo "-------------" 46 | local NET_INTERFACE=$(ip -o link show | awk -F': ' '$2 != "lo" {print $2}' | head -n 1) 47 | if [ -n "$NET_INTERFACE" ]; then 48 | local RX_BYTES=$(cat /sys/class/net/$NET_INTERFACE/statistics/rx_bytes) 49 | local TX_BYTES=$(cat /sys/class/net/$NET_INTERFACE/statistics/tx_bytes) 50 | local RX_MB=$(awk "BEGIN {printf \"%.2f\", $RX_BYTES / 1024 / 1024}") 51 | local TX_MB=$(awk "BEGIN {printf \"%.2f\", $TX_BYTES / 1024 / 1024}") 52 | echo -e "\e[1;34m网络接口:\e[0m \e[32m$NET_INTERFACE\e[0m" 53 | echo -e "\e[1;34m总接收:\e[0m \e[32m${RX_MB} MB\e[0m" 54 | echo -e "\e[1;34m总发送:\e[0m \e[32m${TX_MB} MB\e[0m" 55 | else 56 | echo -e "\e[31m未检测到有效的网络接口!\e[0m" 57 | fi 58 | echo "-------------" 59 | if [ -f /proc/sys/net/ipv4/tcp_congestion_control ]; then 60 | echo -e "\e[1;34m网络算法:\e[0m \e[32m$(sysctl net.ipv4.tcp_congestion_control | awk '{print $3}')\e[0m" 61 | else 62 | echo -e "\e[1;34m网络算法:\e[0m \e[31mIPv4 未启用或不支持。\e[0m" 63 | fi 64 | echo "-------------" 65 | echo -e "\e[1;34m运营商:\e[0m \e[32m$(curl -s ipinfo.io/org | sed 's/^ *//;s/ *$//')\e[0m" 66 | echo -e "\e[1;34mIPv4地址:\e[0m \e[32m$(curl -s ipv4.icanhazip.com)\e[0m" 67 | echo -e "\e[1;34mIPv6地址:\e[0m \e[32m$(ip -6 addr show scope global | awk '/inet6/ && !/temporary|tentative/ {print $2}' | cut -d'/' -f1 | head -n1 | ( grep . || echo "未检测到IPv6地址" ))\e[0m" 68 | echo -e "\e[1;34mDNS地址:\e[0m \e[32m$(cat /etc/resolv.conf | grep nameserver | awk '{print $2}' | xargs | sed 's/ /, /g')\e[0m" 69 | echo -e "\e[1;34m地理位置:\e[0m \e[32m$(curl -s ipinfo.io/city), $(curl -s ipinfo.io/country)\e[0m" 70 | echo -e "\e[1;34m系统时间:\e[0m \e[32m$(timedatectl | grep 'Local time' | awk '{print $3, $4, $5}')\e[0m" 71 | echo "-------------" 72 | echo -e "\e[1;34m运行时长:\e[0m \e[32m$(uptime -p | sed 's/up //')\e[0m" 73 | echo "-------------" 74 | read -n 1 -s -r -p "按任意键返回..." 75 | } 76 | 77 | # 系统优化 78 | display_system_optimization_menu() { 79 | while true; do 80 | echo "=========================================" 81 | echo -e " \e[1;32m系统优化\e[0m " 82 | echo "=========================================" 83 | echo "1) 校准时间" 84 | echo "2) 更新系统" 85 | echo "3) 清理系统" 86 | echo "4) 开启BBR" 87 | echo "5) ROOT登录" 88 | echo "=========================================" 89 | read -p "请输入数字 [1-5] 选择 (默认回车退出):" root_choice 90 | case "$root_choice" in 91 | 1) calibrate_time ;; 92 | 2) update_system ;; 93 | 3) clean_system ;; 94 | 4) enable_bbr ;; 95 | 5) root_login ;; 96 | "") 97 | return 98 | ;; 99 | *) echo -e "\e[31m无效选项,请重新输入。\e[0m" ;; 100 | esac 101 | done 102 | } 103 | 104 | # 时间校准 105 | calibrate_time() { 106 | echo -e "\n[校准时间]" 107 | sudo timedatectl set-timezone Asia/Shanghai 108 | sudo timedatectl set-ntp true 109 | echo -e "\e[32m时间校准完成,当前时区为 Asia/Shanghai。\e[0m" 110 | read -n 1 -s -r -p "按任意键返回..." 111 | echo 112 | } 113 | 114 | # 系统更新 115 | update_system() { 116 | echo -e "\n[更新系统]" 117 | if ! sudo apt update -y && ! sudo apt full-upgrade -y; then 118 | echo -e "\e[31m系统更新失败!请检查网络连接或源列表。\e[0m" 119 | else 120 | sudo apt autoremove -y && sudo apt autoclean -y 121 | echo -e "\e[32m系统更新完成!\e[0m" 122 | fi 123 | read -n 1 -s -r -p "按任意键返回..." 124 | echo 125 | } 126 | 127 | # 系统清理 128 | clean_system() { 129 | echo -e "\n[清理系统]" 130 | sudo apt autoremove --purge -y 131 | sudo apt clean -y && sudo apt autoclean -y 132 | sudo journalctl --rotate && sudo journalctl --vacuum-time=10m 133 | sudo journalctl --vacuum-size=50M 134 | echo -e "\e[32m系统清理完成!\e[0m" 135 | read -n 1 -s -r -p "按任意键返回..." 136 | echo 137 | } 138 | 139 | # 开启 BBR 140 | enable_bbr() { 141 | echo -e "\n[开启BBR]" 142 | if sysctl net.ipv4.tcp_congestion_control | grep -q 'bbr'; then 143 | echo -e "\e[32mBBR已开启!\e[0m" 144 | else 145 | echo "net.core.default_qdisc = fq" | sudo tee -a /etc/sysctl.conf 146 | echo "net.ipv4.tcp_congestion_control = bbr" | sudo tee -a /etc/sysctl.conf 147 | if sudo sysctl -p; then 148 | echo -e "\e[32mBBR已开启!\e[0m" 149 | else 150 | echo -e "\e[31mBBR 开启失败!\e[0m" 151 | fi 152 | fi 153 | read -n 1 -s -r -p "按任意键返回..." 154 | echo 155 | } 156 | 157 | # ROOT登录 158 | root_login() { 159 | while true; do 160 | echo "=========================================" 161 | echo -e " \e[1;34mROOT登录\e[0m " 162 | echo "=========================================" 163 | echo "1) 设置密码" 164 | echo "2) 修改配置" 165 | echo "3) 重启服务" 166 | echo "=========================================" 167 | read -p "请输入数字 [1-3] 选择 (默认回车退出):" root_choice 168 | case "$root_choice" in 169 | 1) 170 | sudo passwd root 171 | read -n 1 -s -r -p "按任意键返回..." 172 | echo 173 | ;; 174 | 2) 175 | sudo sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_config; 176 | sudo sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; 177 | echo -e "\e[32m配置修改成功!\e[0m" 178 | read -n 1 -s -r -p "按任意键返回..." 179 | echo 180 | ;; 181 | 3) 182 | if sudo systemctl restart sshd.service; then 183 | echo -e "\e[32mROOT登录已开启!\e[0m" 184 | else 185 | echo -e "\e[31mROOT登录开启失败!\e[0m" 186 | fi 187 | read -n 1 -s -r -p "按任意键返回..." 188 | echo 189 | ;; 190 | "") 191 | return 192 | ;; 193 | *) echo -e "\e[31m无效选项,请重新输入。\e[0m" ;; 194 | esac 195 | done 196 | } 197 | 198 | # 常用工具 199 | common_tools() { 200 | while true; do 201 | echo "=========================================" 202 | echo -e " \e[1;32m常用工具\e[0m " 203 | echo "=========================================" 204 | echo "1) 查找文件" 205 | echo "2) 赋予权限" 206 | echo "3) 删除文件" 207 | echo "4) 查看进程" 208 | echo "5) 关闭进程" 209 | echo "6) 查看端口" 210 | echo "7) 开放端口" 211 | echo "=========================================" 212 | read -p "请输入数字 [1-7] 选择 (默认回车退出):" root_choice 213 | case "$root_choice" in 214 | 1) 215 | read -p "请输入要查找的文件名: " filename 216 | if [[ -z "$filename" ]]; then 217 | echo -e "\e[31m文件名不能为空。\e[0m" 218 | else 219 | find / -type f -name "*$filename*" 2>/dev/null 220 | [[ $? -ne 0 ]] && echo -e "\e[31m未找到匹配的文件。\e[0m" 221 | fi 222 | read -n 1 -s -r -p "按任意键返回..." 223 | echo 224 | ;; 225 | 2) 226 | read -p "请输入文件路径: " file_path 227 | if [ ! -e "$file_path" ]; then 228 | echo -e "\e[31m错误: 文件或目录 '$file_path' 不存在。\e[0m" 229 | exit 1 230 | fi 231 | chmod 755 "$file_path" 232 | if [ $? -eq 0 ]; then 233 | echo -e "\e[32m'$file_path' 权限已设置为 755!\e[0m" 234 | else 235 | echo -e "\e[31m错误: 设置 '$file_path' 权限为 755 失败。\e[0m" 236 | exit 1 237 | fi 238 | read -n 1 -s -r -p "按任意键返回..." 239 | echo 240 | ;; 241 | 242 | 3) 243 | while true; do 244 | read -p "请输入要删除的文件或目录名(默认回车退出): " filename 245 | if [[ -z "$filename" ]]; then 246 | break 247 | fi 248 | files=($(find / -type f -iname "*$filename*" -o -type d -iname "*$filename*" 2>/dev/null)) 249 | if [[ ${#files[@]} -eq 0 ]]; then 250 | echo -e "\e[31m未找到匹配的文件或目录。\e[0m" 251 | continue 252 | fi 253 | echo "找到以下文件或目录:" 254 | for i in "${!files[@]}"; do 255 | echo "$((i+1)). ${files[$i]}" 256 | done 257 | read -p "请输入要删除的文件或目录编号(可多选,使用空格分隔,按回车取消删除): " choices 258 | if [[ -z "$choices" ]]; then 259 | echo "取消删除操作。" 260 | continue 261 | fi 262 | IFS=' ' read -r -a choice_array <<< "$choices" 263 | for choice in "${choice_array[@]}"; do 264 | if [[ "$choice" -ge 1 && "$choice" -le ${#files[@]} ]]; then 265 | file="${files[$((choice-1))]}" 266 | read -p "确定要删除 $file 吗? (y/n): " confirm 267 | if [[ "$confirm" == "y" ]]; then 268 | if [[ -d "$file" ]]; then 269 | rm -rf "$file" 270 | echo -e "\e[32m目录已删除: $file\e[0m" 271 | else 272 | rm -f "$file" 273 | echo -e "\e[32m文件已删除: $file\e[0m" 274 | fi 275 | else 276 | echo "取消删除 $file。" 277 | fi 278 | else 279 | echo -e "\e[31m无效的选择: $choice\e[0m" 280 | fi 281 | done 282 | done 283 | echo 284 | read -n 1 -s -r -p "按任意键返回..." 285 | echo 286 | ;; 287 | 4) 288 | ps aux 289 | read -n 1 -s -r -p "按任意键返回..." 290 | echo 291 | ;; 292 | 5) 293 | while true; do 294 | read -p "请输入要关闭的进程 PID: " pid 295 | if [[ "$pid" =~ ^[0-9]+$ ]]; then 296 | if kill "$pid"; then 297 | echo -e "\e[32m进程 $pid 已成功关闭!\e[0m" 298 | else 299 | echo -e "\e[31m进程 $pid 无法正常关闭 (SIGTERM),是否需要强制关闭 (SIGKILL)? (y/n)\e[0m" 300 | read -p "请选择 (y/n): " choice 301 | if [[ "$choice" == "y" ]]; then 302 | if kill -9 "$pid"; then 303 | echo -e "\e[32m进程 $pid 已被强制关闭!\e[0m" 304 | else 305 | echo -e "\e[31m进程 $pid 强制关闭失败。\e[0m" 306 | fi 307 | elif [[ "$choice" == "n" ]]; then 308 | echo "取消强制关闭" 309 | else 310 | echo -e "\e[31m无效的选项,进程未关闭。\e[0m" 311 | fi 312 | fi 313 | break 314 | else 315 | echo -e "\e[31m无效的 PID,请输入一个整数。\e[0m" 316 | fi 317 | done 318 | read -n 1 -s -r -p "按任意键返回..." 319 | echo 320 | ;; 321 | 6) 322 | if command -v ss &>/dev/null; then 323 | echo -e "端口 类型 程序名 PID" 324 | ss -tulnp | awk 'NR>1 { 325 | split($5, a, ":"); 326 | split($7, b, ","); 327 | gsub(/[()]/, "", b[1]); 328 | gsub(/pid=/, "", b[2]); 329 | gsub(/users:/, "", b[1]); 330 | gsub(/"/, "", b[1]); 331 | if (a[2] != "" && a[2] != "*") { 332 | printf "%-8s %-7s %-20s %-6s\n", a[2], $1, b[1], b[2]; 333 | } 334 | }' 335 | else 336 | echo -e "端口 类型 程序名 PID" 337 | netstat -tulnp | awk 'NR>2 { 338 | split($4, a, ":"); 339 | split($7, b, "/"); 340 | gsub(/[()]/, "", b[1]); 341 | gsub(/pid=/, "", b[2]); 342 | gsub(/users:/, "", b[1]); 343 | gsub(/"/, "", b[1]); 344 | if (a[2] != "" && a[2] != "*") { 345 | printf "%-8s %-7s %-20s %-6s\n", a[2], $1, b[1], b[2]; 346 | } 347 | }' 348 | fi 349 | read -n 1 -s -r -p "按任意键返回..." 350 | echo 351 | ;; 352 | 7) 353 | while true; do 354 | echo "请选择协议:" 355 | echo "1) TCP" 356 | echo "2) UDP" 357 | read -p "请输入1或2: " protocol_choice 358 | case "$protocol_choice" in 359 | 1) protocol="tcp" ;; 360 | 2) protocol="udp" ;; 361 | *) echo -e "\e[31m无效的选择,请输入1或2。\e[0m" 362 | break 363 | esac 364 | read -p "请输入端口号: " port 365 | if ! [[ "$port" =~ ^[0-9]+$ ]] || [ "$port" -lt 1 ] || [ "$port" -gt 65535 ]; then 366 | echo -e "\e[31m无效的端口号,请输入1到65535之间的数字。\e[0m" 367 | break 368 | fi 369 | command="sudo iptables -A INPUT -p $protocol --dport $port -j ACCEPT" 370 | if $command; then 371 | echo -e "\e[32m端口$port已开放($protocol)!\e[0m" 372 | else 373 | echo -e "\e[31m执行命令失败。\e[0m" 374 | fi 375 | break 376 | done 377 | read -n 1 -s -r -p "按任意键返回..." 378 | echo 379 | ;; 380 | "") 381 | return 382 | ;; 383 | *) 384 | echo -e "\e[31m无效选项,请重新输入。\e[0m" 385 | ;; 386 | esac 387 | done 388 | } 389 | 390 | # 常用软件包 391 | install_package() { 392 | while true; do 393 | echo "=========================================" 394 | echo -e " \e[1;32m常用软件包\e[0m " 395 | echo "=========================================" 396 | echo "1) apt" 397 | echo "2) sudo" 398 | echo "3) curl" 399 | echo "4) nano" 400 | echo "5) vim" 401 | echo "6) zip" 402 | echo "7) git" 403 | echo "8) htop" 404 | echo "9) docker" 405 | echo "=========================================" 406 | read -p "请输入数字 [1-7] 选择 (默认回车退出):" opt_choice 407 | case "$opt_choice" in 408 | 1) 409 | if apt update; then 410 | echo -e "\e[32mapt 更新完成!\e[0m" 411 | else 412 | echo -e "\e[31mapt 更新失败!请检查网络连接或源列表。\e[0m" 413 | fi 414 | read -n 1 -s -r -p "按任意键返回..." 415 | echo 416 | ;; 417 | 2) 418 | echo "1) 安装" 419 | echo "2) 卸载" 420 | read -p "请选择操作 (默认回车退出):" action 421 | case "$action" in 422 | 1) if apt update && apt install sudo -y; then 423 | echo -e "\e[32msudo 安装完成!\e[0m" 424 | else 425 | echo -e "\e[31msudo 安装失败!\e[0m" 426 | fi 427 | ;; 428 | 2) if sudo apt update && sudo apt remove -y sudo; then 429 | echo -e "\e[32msudo 卸载完成!\e[0m" 430 | else 431 | echo -e "\e[31msudo 卸载失败!\e[0m" 432 | fi 433 | ;; 434 | "") ;; 435 | *) echo -e "\e[31m无效选项,请重新输入。\e[0m" ;; 436 | esac 437 | read -n 1 -s -r -p "按任意键返回..." 438 | echo 439 | ;; 440 | 3) 441 | echo "1) 安装" 442 | echo "2) 卸载" 443 | read -p "请选择操作 (默认回车退出):" action 444 | case "$action" in 445 | 1) if sudo apt update && sudo apt install -y curl; then 446 | echo -e "\e[32mcurl 安装完成!\e[0m" 447 | else 448 | echo -e "\e[31mcurl 安装失败!\e[0m" 449 | fi 450 | ;; 451 | 2) if sudo apt remove -y curl; then 452 | echo -e "\e[32mcurl 卸载完成!\e[0m" 453 | else 454 | echo -e "\e[31mcurl 卸载失败!\e[0m" 455 | fi 456 | ;; 457 | "") ;; 458 | *) echo -e "\e[31m无效选项,请重新输入。\e[0m" ;; 459 | esac 460 | read -n 1 -s -r -p "按任意键返回..." 461 | echo 462 | ;; 463 | 4) 464 | echo "1) 安装" 465 | echo "2) 卸载" 466 | read -p "请选择操作 (默认回车退出):" action 467 | case "$action" in 468 | 1) if sudo apt update && sudo apt install -y nano; then 469 | echo -e "\e[32mnano 安装完成!\e[0m" 470 | else 471 | echo -e "\e[31mnano 安装失败!\e[0m" 472 | fi 473 | ;; 474 | 2) if sudo apt remove -y nano; then 475 | echo -e "\e[32mnano 卸载完成!\e[0m" 476 | else 477 | echo -e "\e[31mnano 卸载失败!\e[0m" 478 | fi 479 | ;; 480 | "") ;; 481 | *) echo -e "\e[31m无效选项,请重新输入。\e[0m" ;; 482 | esac 483 | read -n 1 -s -r -p "按任意键返回..." 484 | echo 485 | ;; 486 | 5) 487 | echo "1) 安装" 488 | echo "2) 卸载" 489 | read -p "请选择操作 (默认回车退出):" action 490 | case "$action" in 491 | 1) if sudo apt update && sudo apt install -y vim; then 492 | echo -e "\e[32mvim 安装完成!\e[0m" 493 | else 494 | echo -e "\e[31mvim 安装失败!\e[0m" 495 | fi 496 | ;; 497 | 2) if sudo apt remove -y vim; then 498 | echo -e "\e[32mvim 卸载完成!\e[0m" 499 | else 500 | echo -e "\e[31mvim 卸载失败!\e[0m" 501 | fi 502 | ;; 503 | "") ;; 504 | *) echo -e "\e[31m无效选项,请重新输入。\e[0m" ;; 505 | esac 506 | read -n 1 -s -r -p "按任意键返回..." 507 | echo 508 | ;; 509 | 6) 510 | echo "1) 安装" 511 | echo "2) 卸载" 512 | read -p "请选择操作 (默认回车退出):" action 513 | case "$action" in 514 | 1) if sudo apt update && sudo apt install -y zip; then 515 | echo -e "\e[32mzip 安装完成!\e[0m" 516 | else 517 | echo -e "\e[31mzip 安装失败!\e[0m" 518 | fi 519 | ;; 520 | 2) if sudo apt remove -y zip; then 521 | echo -e "\e[32mzip 卸载完成!\e[0m" 522 | else 523 | echo -e "\e[31mzip 卸载失败!\e[0m" 524 | fi 525 | ;; 526 | "") ;; 527 | *) echo -e "\e[31m无效选项,请重新输入。\e[0m" ;; 528 | esac 529 | read -n 1 -s -r -p "按任意键返回..." 530 | echo 531 | ;; 532 | 7) 533 | echo "1) 安装" 534 | echo "2) 卸载" 535 | read -p "请选择操作 (默认回车退出):" action 536 | case "$action" in 537 | 1) if sudo apt update && sudo apt install -y git; then 538 | echo -e "\e[32mgit 安装完成!\e[0m" 539 | else 540 | echo -e "\e[31mgit 安装失败!\e[0m" 541 | fi 542 | ;; 543 | 2) if sudo apt remove -y git; then 544 | echo -e "\e[32mgit 卸载完成!\e[0m" 545 | else 546 | echo -e "\e[31mgit 卸载失败!\e[0m" 547 | fi 548 | ;; 549 | "") ;; 550 | *) echo -e "\e[31m无效选项,请重新输入。\e[0m" ;; 551 | esac 552 | read -n 1 -s -r -p "按任意键返回..." 553 | echo 554 | ;; 555 | 8) 556 | echo "1) 安装" 557 | echo "2) 卸载" 558 | read -p "请选择操作 (默认回车退出):" action 559 | case "$action" in 560 | 1) if sudo apt update && sudo apt install -y htop; then 561 | echo -e "\e[32mhtop 安装完成!\e[0m" 562 | else 563 | echo -e "\e[31mhtop 安装失败!\e[0m" 564 | fi 565 | ;; 566 | 2) if sudo apt remove -y htop; then 567 | echo -e "\e[32mhtop 卸载完成!\e[0m" 568 | else 569 | echo -e "\e[31mhtop 卸载失败!\e[0m" 570 | fi 571 | ;; 572 | "") ;; 573 | *) echo -e "\e[31m无效选项,请重新输入。\e[0m" ;; 574 | esac 575 | read -n 1 -s -r -p "按任意键返回..." 576 | echo 577 | ;; 578 | 9) 579 | echo "1) 安装" 580 | echo "2) 卸载" 581 | read -p "请选择操作 (默认回车退出):" action 582 | case "$action" in 583 | 1) if curl -sSL https://get.docker.com/ | sh; then 584 | echo -e "\e[32mdocker 安装完成!\e[0m" 585 | else 586 | echo -e "\e[31mdocker 安装失败!\e[0m" 587 | fi 588 | ;; 589 | 2) if sudo apt remove -y docker; then 590 | echo -e "\e[32mdocker 卸载完成!\e[0m" 591 | else 592 | echo -e "\e[31mdocker 卸载失败!\e[0m" 593 | fi 594 | ;; 595 | "") ;; 596 | *) echo -e "\e[31m无效选项,请重新输入。\e[0m" ;; 597 | esac 598 | read -n 1 -s -r -p "按任意键返回..." 599 | echo 600 | ;; 601 | "") 602 | return 603 | ;; 604 | *) echo -e "\e[31m无效选项,请重新输入。\e[0m" ;; 605 | esac 606 | done 607 | } 608 | 609 | # 申请证书 610 | apply_certificate() { 611 | while true; do 612 | echo "=========================================" 613 | echo -e " \e[1;32m申请证书\e[0m " 614 | echo "=========================================" 615 | echo "1) 安装脚本" 616 | echo "2) 申请证书" 617 | echo "3) 更换服务器" 618 | echo "4) 安装证书" 619 | echo "5) 卸载脚本" 620 | echo "=========================================" 621 | read -p "请输入数字 [1-5] 选择 (默认回车退出):" cert_choice 622 | case "$cert_choice" in 623 | 1) 624 | read -p "请输入邮箱地址: " email 625 | sudo apt update 626 | if ! command -v crontab &> /dev/null; then 627 | echo "正在安装 cron..." 628 | if sudo apt install -y cron; then 629 | echo -e "\e[32mcron 安装完成!\e[0m" 630 | else 631 | echo -e "\e[31mcron 安装失败!\e[0m" 632 | fi 633 | fi 634 | if ! command -v socat &> /dev/null; then 635 | echo "正在安装 socat..." 636 | if sudo apt install -y socat; then 637 | echo -e "\e[32msocat 安装完成!\e[0m" 638 | else 639 | echo -e "\e[31msocat 安装失败!\e[0m" 640 | fi 641 | fi 642 | if curl https://get.acme.sh | sh -s email="$email"; then 643 | echo -e "\e[32macme.sh 安装完成!\e[0m" 644 | else 645 | echo -e "\e[31macme.sh 安装失败!\e[0m" 646 | fi 647 | read -n 1 -s -r -p "按任意键返回..." 648 | echo 649 | ;; 650 | 2) 651 | while true; do 652 | read -p "请输入域名: " domain 653 | if ~/.acme.sh/acme.sh --issue --standalone -d "$domain"; then 654 | echo -e "\e[32m证书申请成功!\e[0m" 655 | else 656 | echo -e "\e[31m证书申请失败,请检查域名是否正确并重试。\e[0m" 657 | fi 658 | break 659 | done 660 | read -n 1 -s -r -p "按任意键返回..." 661 | echo 662 | ;; 663 | 3) 664 | ~/.acme.sh/acme.sh --set-default-ca --server letsencrypt 665 | if [[ $? -eq 0 ]]; then 666 | echo -e "\e[32m已切换至Let's Encrypt服务!\e[0m" 667 | else 668 | echo -e "\e[31m切换至Let's Encrypt服务失败,请检查是否正确安装acme.sh并确保网络连接正常。\e[0m" 669 | fi 670 | read -n 1 -s -r -p "按任意键返回..." 671 | echo 672 | ;; 673 | 4) 674 | read -p "请输入域名: " domain 675 | read -p "请输入证书安装路径(默认: /path/to): " install_path 676 | install_path=${install_path:-/path/to} 677 | if mkdir -p "$install_path" && \ 678 | ~/.acme.sh/acme.sh --installcert -d "$domain" \ 679 | --key-file "$install_path/private.key" --fullchain-file "$install_path/fullchain.crt" && \ 680 | sudo chmod 644 "$install_path/fullchain.crt" "$install_path/private.key"; then 681 | echo -e "\e[32m证书安装完成!路径: $install_path\e[0m" 682 | else 683 | echo -e "\e[31m证书安装失败,请检查输入。\e[0m" 684 | fi 685 | read -n 1 -s -r -p "按任意键返回..." 686 | echo 687 | ;; 688 | 5) 689 | if ~/.acme.sh/acme.sh --uninstall; then 690 | echo -e "\e[32macme.sh 已卸载。\e[0m" 691 | else 692 | echo -e "\e[31macme.sh 卸载失败!\e[0m" 693 | fi 694 | read -n 1 -s -r -p "按任意键返回..." 695 | echo 696 | ;; 697 | "") 698 | return 699 | ;; 700 | *) 701 | echo -e "\e[31m无效选项,请重新输入。\e[0m" 702 | ;; 703 | esac 704 | done 705 | } 706 | 707 | # 安装Xray 708 | install_xray() { 709 | while true; do 710 | echo "=========================================" 711 | echo -e " \e[1;32m安装Xray\e[0m " 712 | echo "=========================================" 713 | echo "1) VLESS-WS-TLS" 714 | echo "2) VLESS-TCP-REALITY" 715 | echo "3) 卸载服务" 716 | echo "=========================================" 717 | read -p "请输入数字 [1-2] 选择 (默认回车退出):" opt_choice 718 | case "$opt_choice" in 719 | 1) install_xray_tls ;; 720 | 2) install_xray_reality ;; 721 | "") 722 | return 723 | ;; 724 | 3) 725 | if bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ remove --purge; then 726 | echo -e "\e[32mXray已卸载。\e[0m" 727 | else 728 | echo -e "\e[31mXray卸载失败!\e[0m" 729 | fi 730 | read -n 1 -s -r -p "按任意键返回..." 731 | echo 732 | ;; 733 | "") 734 | return 735 | ;; 736 | *) echo -e "\e[31m无效选项,请重新输入。\e[0m" ;; 737 | esac 738 | done 739 | } 740 | 741 | # 安装VLESS-WS-TLS 742 | install_xray_tls() { 743 | while true; do 744 | echo "=========================================" 745 | echo -e " \e[1;34mVLESS-WS-TLS\e[0m " 746 | echo "=========================================" 747 | echo "1) 安装升级" 748 | echo "2) 编辑配置" 749 | echo "3) 重启服务" 750 | echo "=========================================" 751 | read -p "请输入数字 [1-3] 选择功能 (默认回车退出):" xray_choice 752 | case "$xray_choice" in 753 | 1) 754 | if bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install && \ 755 | sudo curl -o /usr/local/etc/xray/config.json "https://raw.githubusercontent.com/XTLS/Xray-examples/refs/heads/main/VLESS-TCP-TLS-WS%20(recommended)/config_server.jsonc"; then 756 | echo -e "\e[32mXray 安装升级完成!\e[0m" 757 | echo "以下是uuid:" 758 | echo -e "\e[34m$(xray uuid)\e[0m" 759 | else 760 | echo -e "\e[31mXray 安装升级失败!\e[0m" 761 | fi 762 | read -n 1 -s -r -p "按任意键返回..." 763 | echo 764 | ;; 765 | 2) 766 | echo -e "\e[33m提示:将UUID填入配置文件中。若已执行成功默认设置的“安装证书”则证书路径无须修改。\e[0m" 767 | read -n 1 -s -r -p "按任意键继续..." 768 | if ! command -v nano >/dev/null 2>&1; then 769 | sudo apt update >/dev/null 2>&1 && sudo apt install -y nano >/dev/null 2>&1 770 | fi 771 | if ! command -v nano >/dev/null 2>&1; then 772 | echo -e "\e[31m错误:无法安装或找到 nano!\e[0m" >&2 773 | exit 1 774 | fi 775 | sudo nano /usr/local/etc/xray/config.json 776 | read -n 1 -s -r -p "按任意键返回..." 777 | echo 778 | ;; 779 | 3) 780 | CONFIG_PATH="/usr/local/etc/xray/config.json" 781 | extract_field() { 782 | local pattern="$1" 783 | local match="$2" 784 | grep -aPo "\"$pattern\":\s*$match" "$CONFIG_PATH" | head -n 1 | sed -E "s/\"$pattern\":\s*//;s/^\"//;s/\"$//" 785 | } 786 | extract_list_field() { 787 | local list_parent="$1" 788 | local list_field="$2" 789 | grep -aPoz "\"$list_parent\":\s*\[\s*\{[^}]*\}\s*\]" "$CONFIG_PATH" | grep -aPo "\"$list_field\":\s*\"[^\"]*\"" | head -n 1 | sed -E "s/\"$list_field\":\s*\"([^\"]*)\"/\1/" 790 | } 791 | get_domain_from_cert() { 792 | local cert_file="$1" 793 | openssl x509 -in "$cert_file" -text -noout | grep -aPo "DNS:[^,]*" | sed 's/DNS://' | head -n 1 || 794 | openssl x509 -in "$cert_file" -text -noout | grep -aPo "CN=[^ ]*" | sed 's/CN=//' 795 | } 796 | get_public_ip() { 797 | ipv4=$(curl -s https://api.ipify.org) 798 | if [[ -n "$ipv4" ]]; then 799 | echo "$ipv4" 800 | else 801 | curl -s -6 https://api64.ipify.org || echo "127.0.0.1" 802 | fi 803 | } 804 | while true; do 805 | sudo systemctl restart xray 806 | sleep 2 807 | if ! systemctl is-active --quiet xray; then 808 | echo -e "\e[31m未能启动 xray 服务,请检查日志。\e[0m" 809 | systemctl status xray --no-pager 810 | break 811 | else 812 | echo -e "\e[32mxray已启动!\e[0m" 813 | fi 814 | UUID=$(extract_list_field "clients" "id") 815 | PORT=$(extract_field "port" "\d+") 816 | WS_PATH=$(extract_field "path" "\"[^\"]*\"") 817 | TLS=$(extract_field "security" "\"[^\"]*\"") 818 | CERT_PATH=$(extract_list_field "certificates" "certificateFile") 819 | if [[ -z "$CERT_PATH" ]]; then 820 | echo -e "\e[31m未能找到证书路径。\e[0m" 821 | break 822 | fi 823 | DOMAIN=$(get_domain_from_cert "$CERT_PATH") 824 | SNI=${DOMAIN:-"your.domain.net"} 825 | HOST=${DOMAIN:-"your.domain.net"} 826 | ADDRESS=$(get_public_ip) 827 | WS_PATH=${WS_PATH:-"/"} 828 | TLS=${TLS:-"tls"} 829 | PORT=${PORT:-"443"} 830 | vless_uri="vless://${UUID}@${ADDRESS}:${PORT}?encryption=none&security=${TLS}&sni=${SNI}&type=ws&host=${HOST}&path=${WS_PATH}#Xray" 831 | echo "VLESS链接如下" 832 | echo -e "\e[34m$vless_uri\e[0m" 833 | break 834 | done 835 | read -n 1 -s -r -p "按任意键返回..." 836 | echo 837 | ;; 838 | "") 839 | return 840 | ;; 841 | *) 842 | echo -e "\e[31m无效选项,请重新输入。\e[0m" 843 | ;; 844 | esac 845 | done 846 | } 847 | 848 | # 安装VLESS-TCP-REALITY 849 | install_xray_reality() { 850 | while true; do 851 | echo "=========================================" 852 | echo -e " \e[1;34mVLESS-TCP-REALITY\e[0m " 853 | echo "=========================================" 854 | echo "1) 安装升级" 855 | echo "2) 编辑配置" 856 | echo "3) 重启服务" 857 | echo "=========================================" 858 | read -p "请输入数字 [1-3] 选择(默认回车退出):" xray_choice 859 | case "$xray_choice" in 860 | 1) 861 | if bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install && \ 862 | sudo curl -o /usr/local/etc/xray/config.json "https://raw.githubusercontent.com/XTLS/Xray-examples/refs/heads/main/VLESS-TCP-XTLS-Vision-REALITY/config_server.jsonc"; then 863 | echo -e "\e[32mXray 安装升级完成!\e[0m" 864 | echo "以下是UUID:" 865 | echo -e "\e[34m$(xray uuid)\e[0m" 866 | echo "以下是私钥:" 867 | keys=$(xray x25519) 868 | export PRIVATE_KEY=$(echo "$keys" | head -n 1 | awk '{print $3}' | sed 's/^-//') 869 | export PUBLIC_KEY=$(echo "$keys" | tail -n 1 | awk '{print $3}' | sed 's/^-//') 870 | echo -e "\e[34m$PRIVATE_KEY\e[0m" 871 | echo "以下是ShortIds:" 872 | echo -e "\e[34m$(openssl rand -hex 8)\e[0m" 873 | else 874 | echo -e "\e[31mXray 安装升级失败!\e[0m" 875 | fi 876 | read -n 1 -s -r -p "按任意键返回..." 877 | echo 878 | ;; 879 | 2) 880 | echo -e "\e[33m提示:将UUID、目标网站及私钥填入配置文件中,ShortIds非必须。\e[0m" 881 | read -n 1 -s -r -p "按任意键继续..." 882 | if ! command -v nano >/dev/null 2>&1; then 883 | sudo apt update >/dev/null 2>&1 && sudo apt install -y nano >/dev/null 2>&1 884 | fi 885 | if ! command -v nano >/dev/null 2>&1; then 886 | echo -e "\e[31m错误:无法安装或找到 nano!\e[0m" >&2 887 | exit 1 888 | fi 889 | sudo nano /usr/local/etc/xray/config.json 890 | read -n 1 -s -r -p "按任意键返回..." 891 | echo 892 | ;; 893 | 3) 894 | CONFIG_PATH="/usr/local/etc/xray/config.json" 895 | remove_spaces_and_quotes() { 896 | echo "$1" | sed 's/[[:space:]]*$//;s/^ *//;s/^"//;s/"$//' 897 | } 898 | extract_field() { 899 | local pattern=$1 900 | local match=$2 901 | grep -aPo "\"$pattern\":\s*$match" "$CONFIG_PATH" | head -n 1 | sed -E "s/\"$pattern\":\s*//;s/^\"//;s/\"$//" 902 | } 903 | extract_server_name() { 904 | local result=$(grep -aA 2 "\"serverNames\": \[" "$CONFIG_PATH" | awk 'NR==2{gsub(/^\s+|\s*\/\/.*$/,"");split($0,a,","); for (i in a) {gsub(/^[\"\s]+|[\"\s]+$/,"",a[i]);printf "%s ",a[i]}}') 905 | if [[ -n "$result" ]]; then 906 | remove_spaces_and_quotes "$result" 907 | fi 908 | } 909 | extract_list_field() { 910 | local list_parent=$1 911 | local list_field=$2 912 | if [[ "$list_field" == "shortIds" || "$list_field" == "serverNames" ]]; then 913 | local result=$(grep -aA 2 "\"$list_field\": \[" "$CONFIG_PATH" | awk 'NR==2{gsub(/^\s+|\s*\/\/.*$/,"");split($0,a,","); for (i in a) {gsub(/^[\"\s]+|[\"\s]+$/,"",a[i]);printf "%s ",a[i]}}') 914 | if [[ -n "$result" ]]; then 915 | remove_spaces_and_quotes "$result" 916 | fi 917 | else 918 | grep -aPoz "\"$list_parent\":\s*\[\s*\{[^}]*\}\s*\]" "$CONFIG_PATH" | grep -aPo "\"$list_field\":\s*\"[^\"]*\"" | head -n 1 | sed -E "s/\"$list_field\":\s*\"([^\"]*)\"/\1/" 919 | fi 920 | } 921 | get_public_ip() { 922 | ipv4=$(curl -s https://api.ipify.org) 923 | if [[ -n "$ipv4" ]]; then 924 | echo "$ipv4" 925 | else 926 | curl -s -6 https://api64.ipify.org || echo "127.0.0.1" 927 | fi 928 | } 929 | while true; do 930 | sudo systemctl restart xray 931 | sleep 2 932 | if ! systemctl is-active --quiet xray; then 933 | echo -e "\e[31m未能启动 xray 服务,请检查日志。\e[0m" 934 | systemctl status xray --no-pager 935 | break 936 | else 937 | echo -e "\e[32mxray已启动!\e[0m" 938 | fi 939 | UUID=$(extract_list_field "clients" "id") 940 | PORT=$(extract_field "port" "\d+") 941 | TLS=$(extract_field "security" "\"[^\"]*\"") 942 | SERVER_NAME=$(extract_server_name) 943 | SHORT_IDS=$(extract_list_field "realitySettings" "shortIds") 944 | SNI=${SERVER_NAME:-"your.domain.net"} 945 | ADDRESS=$(get_public_ip) 946 | PORT=${PORT:-"443"} 947 | FLOW=$(extract_field "flow" "\"[^\"]*\"") 948 | SID=${SHORT_IDS:-""} 949 | vless_uri="vless://${UUID}@${ADDRESS}:${PORT}?encryption=none&flow=${FLOW}&security=reality&sni=${SNI}&fp=chrome&sid=${SID}&type=tcp&headerType=none#Xray" 950 | echo "VLESS链接如下:" 951 | echo -e "\e[34m$vless_uri\e[0m" 952 | echo "以下是公钥:" 953 | echo -e "\e[34m$PUBLIC_KEY\e[0m" 954 | echo -e "\e[33m提示:将公钥填入客户端中。\e[0m" 955 | break 956 | done 957 | read -n 1 -s -r -p "按任意键返回..." 958 | echo 959 | ;; 960 | "") 961 | return 962 | ;; 963 | *) 964 | echo -e "\e[31m无效选项,请重新输入。\e[0m" 965 | ;; 966 | esac 967 | done 968 | } 969 | 970 | # 安装Hysteria2 971 | install_hysteria2() { 972 | while true; do 973 | echo "=========================================" 974 | echo -e " \e[1;32m安装Hysteria2\e[0m " 975 | echo "=========================================" 976 | echo "1) 安装升级" 977 | echo "2) 编辑配置" 978 | echo "3) 重启服务" 979 | echo "4) 端口跳跃" 980 | echo "5) 卸载服务" 981 | echo "=========================================" 982 | read -p "请输入数字 [1-5] 选择 (默认回车退出):" hysteria_choice 983 | case "$hysteria_choice" in 984 | 1) 985 | if bash <(curl -fsSL https://get.hy2.sh/) && \ 986 | sudo systemctl enable --now hysteria-server.service && \ 987 | sysctl -w net.core.rmem_max=16777216 && \ 988 | sysctl -w net.core.wmem_max=16777216; then 989 | echo -e "\e[32mhysteria2 安装升级完成!\e[0m" 990 | else 991 | echo -e "\e[31mhysteria2 安装升级失败!\e[0m" 992 | fi 993 | read -n 1 -s -r -p "按任意键返回..." 994 | echo 995 | ;; 996 | 2) 997 | echo -e "\e[33m提示:将域名填入配置文件中。\e[0m" 998 | read -n 1 -s -r -p "按任意键继续..." 999 | if ! command -v nano >/dev/null 2>&1; then 1000 | sudo apt update >/dev/null 2>&1 && sudo apt install -y nano >/dev/null 2>&1 1001 | fi 1002 | if ! command -v nano >/dev/null 2>&1; then 1003 | echo -e "\e[31m错误:无法安装或找到 nano!\e[0m" >&2 1004 | exit 1 1005 | fi 1006 | sudo nano /etc/hysteria/config.yaml 1007 | read -n 1 -s -r -p "按任意键返回..." 1008 | echo 1009 | ;; 1010 | 3) 1011 | config_file="/etc/hysteria/config.yaml" 1012 | get_domain_from_cert() { 1013 | local cert_file=$1 1014 | openssl x509 -in "$cert_file" -text -noout | grep -Po "DNS:[^,]*" | head -n 1 | sed 's/DNS://' || 1015 | openssl x509 -in "$cert_file" -text -noout | grep -Po "CN=[^ ]*" | sed 's/CN=//' 1016 | } 1017 | if [ ! -f "$config_file" ]; then 1018 | echo -e "\e[31m未能找到配置文件。\e[0m" 1019 | break 1020 | fi 1021 | while true; do 1022 | sudo systemctl restart hysteria-server.service 1023 | sleep 2 1024 | if ! systemctl is-active --quiet hysteria-server.service; then 1025 | echo -e "\e[31m未能启动 hysteria 服务,请检查日志。\e[0m" 1026 | sudo systemctl status hysteria-server.service --no-pager 1027 | break 1028 | else 1029 | echo -e "\e[32mhysteria已启动!\e[0m" 1030 | fi 1031 | port=$(grep "^listen:" "$config_file" | awk -F: '{print $3}' || echo "443") 1032 | password=$(grep "^ password:" "$config_file" | awk '{print $2}') 1033 | domain=$(grep "domains:" "$config_file" -A 1 | tail -n 1 | tr -d " -") 1034 | if [ -z "$domain" ]; then 1035 | cert_path=$(grep "cert:" "$config_file" | awk '{print $2}' | tr -d '"') 1036 | if [ -z "$cert_path" ] || [ ! -f "$cert_path" ]; then 1037 | echo -e "\e[31m没有找到域名或证书。\e[0m" 1038 | break 1039 | fi 1040 | domain=$(get_domain_from_cert "$cert_path") 1041 | if [ -z "$domain" ]; then 1042 | echo -e "\e[31m从证书中提取域名失败。\e[0m" 1043 | break 1044 | fi 1045 | fi 1046 | ip=$(hostname -I | awk '{print $1}') 1047 | hysteria2_uri="hysteria2://$password@$ip:$port?sni=$domain&insecure=0#hysteria" 1048 | echo "hysteria2 链接如下:" 1049 | echo -e "\e[34m$hysteria2_uri\e[0m" 1050 | break 1051 | done 1052 | read -n 1 -s -r -p "按任意键返回..." 1053 | echo 1054 | ;; 1055 | 4) 1056 | default_redirect_port=443 1057 | default_start_port=60000 1058 | default_end_port=65535 1059 | config_file="/etc/hysteria/config.yaml" 1060 | redirect_port=$( 1061 | if [[ -f "$config_file" ]]; then 1062 | grep 'listen:' "$config_file" | awk -F':' '{print $NF}' 1063 | fi 1064 | ) 1065 | [[ -z "$redirect_port" || ! "$redirect_port" =~ ^[0-9]+$ || "$redirect_port" -lt 1 || "$redirect_port" -gt 65535 ]] && redirect_port="$default_redirect_port" 1066 | read -p "请输入起始端口号 (按 Enter 使用默认值 60000): " start_port 1067 | [[ -z "$start_port" ]] && start_port="$default_start_port" 1068 | [[ "$start_port" =~ ^[0-9]+$ && "$start_port" -ge 1 && "$start_port" -le 65535 ]] || { echo -e "\e[31m起始端口号无效, 使用默认值 60000\e[0m"; start_port="$default_start_port"; } 1069 | read -p "请输入结束端口号 (按 Enter 使用默认值 65535): " end_port 1070 | [[ -z "$end_port" ]] && end_port="$default_end_port" 1071 | [[ "$end_port" =~ ^[0-9]+$ && "$end_port" -ge 1 && "$end_port" -le 65535 && "$end_port" -ge "$start_port" ]] || { echo -e "\e[31m结束端口号无效,使用默认值 65535\e[0m"; end_port="$default_end_port"; } 1072 | interfaces=($(ip -o link | awk -F': ' '{if ($2 != "lo") print $2}')) 1073 | [[ ${#interfaces[@]} -eq 0 ]] && { echo -e "\e[31m未找到网络接口,无法执行 iptables 命令。\e[0m"; exit 1; } 1074 | selected_interface="${interfaces[0]}" 1075 | iptables_command="iptables -t nat -A PREROUTING -i $selected_interface -p udp --dport $start_port:$end_port -j REDIRECT --to-ports $redirect_port" 1076 | if eval "$iptables_command"; then 1077 | echo -e "\e[32m端口跳跃设置成功!\e[0m" 1078 | else 1079 | echo -e "\e[31miptables命令执行失败。\e[0m" 1080 | exit 1 1081 | fi 1082 | read -n 1 -s -r -p "按任意键返回..." 1083 | echo 1084 | ;; 1085 | 5) 1086 | if bash <(curl -fsSL https://get.hy2.sh/) --remove && \ 1087 | rm -rf /etc/hysteria && 1088 | userdel -r hysteria && 1089 | rm -f /etc/systemd/system/multi-user.target.wants/hysteria-server.service && 1090 | rm -f /etc/systemd/system/multi-user.target.wants/hysteria-server@*.service && 1091 | systemctl daemon-reload; then 1092 | echo -e "\e[32mhysteria2 已卸载。\e[0m" 1093 | fi 1094 | read -n 1 -s -r -p "按任意键返回..." 1095 | echo 1096 | ;; 1097 | "") 1098 | return 1099 | ;; 1100 | *) 1101 | echo -e "\e[31m无效选项,请重新输入。\e[0m" 1102 | ;; 1103 | esac 1104 | done 1105 | } 1106 | 1107 | # 安装sing-box 1108 | install_sing-box() { 1109 | while true; do 1110 | echo "=========================================" 1111 | echo -e " \e[1;32m安装sing-box\e[0m " 1112 | echo "=========================================" 1113 | echo "1) 安装升级" 1114 | echo "2) 编辑配置" 1115 | echo "3) 重启服务" 1116 | echo "4) 卸载服务" 1117 | echo "=========================================" 1118 | read -p "请输入数字 [1-4] 选择 (默认回车退出):" singbox_choice 1119 | case "$singbox_choice" in 1120 | 1) 1121 | if bash <(curl -fsSL https://sing-box.app/deb-install.sh) && \ 1122 | sudo curl -L -o /etc/sing-box/config.json "https://raw.githubusercontent.com/sezhai/VPS-Script/refs/heads/main/extras/sing-box/config.json"; then 1123 | echo -e "\e[32msing-box 安装升级成功!\e[0m" 1124 | else 1125 | echo -e "\e[31msing-box 安装升级失败!\e[0m" 1126 | fi 1127 | read -n 1 -s -r -p "按任意键返回..." 1128 | echo 1129 | ;; 1130 | 2) 1131 | echo -e "\e[33m提示:根据提示修改配置文件。\e[0m" 1132 | read -n 1 -s -r -p "按任意键继续..." 1133 | if ! command -v nano >/dev/null 2>&1; then 1134 | sudo apt update >/dev/null 2>&1 && sudo apt install -y nano >/dev/null 2>&1 1135 | fi 1136 | if ! command -v nano >/dev/null 2>&1; then 1137 | echo -e "\e[31m无法安装或找到 nano。\e[0m" >&2 1138 | exit 1 1139 | fi 1140 | sudo nano /etc/sing-box/config.json 1141 | read -n 1 -s -r -p "按任意键返回..." 1142 | echo 1143 | ;; 1144 | 3) 1145 | CONFIG_PATH="/etc/sing-box/config.json" 1146 | sudo systemctl restart sing-box 1147 | sleep 2 1148 | if ! systemctl is-active --quiet sing-box; then 1149 | echo -e "\e[31m未能启动 sing-box 服务,请检查日志。\e[0m" 1150 | systemctl status sing-box --no-pager 1151 | exit 1 1152 | else 1153 | echo -e "\e[32msing-box已启动!\e[0m" 1154 | fi 1155 | get_ip() { 1156 | curl -s https://api.ipify.org || echo "127.0.0.1" 1157 | } 1158 | urlencode() { 1159 | local s="$1" ch 1160 | for ((i=0; i<${#s}; i++)); do 1161 | ch="${s:i:1}" 1162 | case "$ch" in 1163 | [a-zA-Z0-9.~_-]) printf '%s' "$ch" ;; 1164 | *) printf '%%%02X' "'$ch" ;; 1165 | esac 1166 | done 1167 | } 1168 | ip=$(get_ip) 1169 | vmess_uuid=$(grep -Pzo '(?s)"tag": "vmess".*?uuid":\s*"\K[^"]+' "$CONFIG_PATH" | tr -d '\0') 1170 | vmess_port=$(grep -Pzo '(?s)"tag": "vmess".*?listen_port":\s*\K[0-9]+' "$CONFIG_PATH" | tr -d '\0') 1171 | vmess_path=$(grep -Pzo '(?s)"tag": "vmess".*?path":\s*"\K[^"]+' "$CONFIG_PATH" | tr -d '\0') 1172 | vmess_host=$(grep -Pzo '(?s)"tag": "vmess".*?server_name":\s*"\K[^"]+' "$CONFIG_PATH" | tr -d '\0') 1173 | vmess_sni="$vmess_host" 1174 | vmess_json=$(cat </dev/null || grep PRETTY_NAME /etc/os-release | cut -d '"' -f2)\e[0m" 30 | echo -e "\e[1;34mLinux版本:\e[0m \e[32m$(uname -r)\e[0m" 31 | echo "-------------" 32 | echo -e "\e[1;34mCPU架构:\e[0m \e[32m$(uname -m)\e[0m" 33 | echo -e "\e[1;34mCPU型号:\e[0m \e[32m$(lscpu | grep 'Model name' | sed 's/Model name:[ \t]*//')\e[0m" 34 | echo -e "\e[1;34mCPU核心数:\e[0m \e[32m$(nproc)\e[0m" 35 | echo -e "\e[1;34mCPU频率:\e[0m \e[32m$(lscpu | grep 'CPU MHz' | awk -F: '{print $2}' | xargs) MHz\e[0m" 36 | echo "-------------" 37 | echo -e "\e[1;34mCPU占用:\e[0m \e[32m$(top -bn1 | grep 'Cpu(s)' | awk '{print $2 + $4}')%\e[0m" 38 | echo -e "\e[1;34m系统负载:\e[0m \e[32m$(awk '{print $1, $2, $3}' /proc/loadavg)\e[0m" 39 | local mem_info=$(free -m | awk '/Mem:/ {total=$2; used=$3; if (total > 0) printf "%.2f/%.2f MB (%.2f%%)", used, total, used*100/total; else print "数据不可用"}') 40 | echo -e "\e[1;34m物理内存:\e[0m \e[32m$mem_info \e[0m" 41 | local swap_info=$(free -m | awk '/Swap:/ {total=$2; used=$3; if (total > 0) printf "%.0fMB/%.0fMB (%.0f%%)", used, total, used*100/total; else print "数据不可用" }') 42 | echo -e "\e[1;34m虚拟内存:\e[0m \e[32m$swap_info\e[0m" 43 | 44 | echo -e "\e[1;34m硬盘占用:\e[0m \e[32m$(df -h / | awk '/\// {print $3 "/" $2 " (" $5 ")"}')\e[0m" 45 | echo "-------------" 46 | local NET_INTERFACE=$(ip -o link show | awk -F': ' '$2 != "lo" {print $2}' | head -n 1) 47 | if [ -n "$NET_INTERFACE" ]; then 48 | local RX_BYTES=$(cat /sys/class/net/$NET_INTERFACE/statistics/rx_bytes) 49 | local TX_BYTES=$(cat /sys/class/net/$NET_INTERFACE/statistics/tx_bytes) 50 | local RX_MB=$(awk "BEGIN {printf \"%.2f\", $RX_BYTES / 1024 / 1024}") 51 | local TX_MB=$(awk "BEGIN {printf \"%.2f\", $TX_BYTES / 1024 / 1024}") 52 | echo -e "\e[1;34m网络接口:\e[0m \e[32m$NET_INTERFACE\e[0m" 53 | echo -e "\e[1;34m总接收:\e[0m \e[32m${RX_MB} MB\e[0m" 54 | echo -e "\e[1;34m总发送:\e[0m \e[32m${TX_MB} MB\e[0m" 55 | else 56 | echo -e "\e[31m未检测到有效的网络接口!\e[0m" 57 | fi 58 | echo "-------------" 59 | if [ -f /proc/sys/net/ipv4/tcp_congestion_control ]; then 60 | echo -e "\e[1;34m网络算法:\e[0m \e[32m$(sysctl net.ipv4.tcp_congestion_control | awk '{print $3}')\e[0m" 61 | else 62 | echo -e "\e[1;34m网络算法:\e[0m \e[31mIPv4 未启用或不支持。\e[0m" 63 | fi 64 | echo "-------------" 65 | echo -e "\e[1;34m运营商:\e[0m \e[32m$(curl -s ipinfo.io/org | sed 's/^ *//;s/ *$//')\e[0m" 66 | echo -e "\e[1;34mIPv4地址:\e[0m \e[32m$(curl -s ipv4.icanhazip.com)\e[0m" 67 | echo -e "\e[1;34mIPv6地址:\e[0m \e[32m$(ip -6 addr show scope global | awk '/inet6/ && !/temporary|tentative/ {print $2}' | cut -d'/' -f1 | head -n1 | ( grep . || echo "未检测到IPv6地址" ))\e[0m" 68 | echo -e "\e[1;34mDNS地址:\e[0m \e[32m$(cat /etc/resolv.conf | grep nameserver | awk '{print $2}' | xargs | sed 's/ /, /g')\e[0m" 69 | echo -e "\e[1;34m地理位置:\e[0m \e[32m$(curl -s ipinfo.io/city), $(curl -s ipinfo.io/country)\e[0m" 70 | echo -e "\e[1;34m系统时间:\e[0m \e[32m$(timedatectl | grep 'Local time' | awk '{print $3, $4, $5}')\e[0m" 71 | echo "-------------" 72 | echo -e "\e[1;34m运行时长:\e[0m \e[32m$(uptime -p | sed 's/up //')\e[0m" 73 | echo "-------------" 74 | read -n 1 -s -r -p "按任意键返回..." 75 | } 76 | 77 | # 系统优化 78 | display_system_optimization_menu() { 79 | while true; do 80 | echo "=========================================" 81 | echo -e " \e[1;32m系统优化\e[0m " 82 | echo "=========================================" 83 | echo "1) 校准时间" 84 | echo "2) 更新系统" 85 | echo "3) 清理系统" 86 | echo "4) 开启BBR" 87 | echo "5) ROOT登录" 88 | echo "=========================================" 89 | read -p "请输入数字 [1-5] 选择 (默认回车退出):" root_choice 90 | case "$root_choice" in 91 | 1) calibrate_time ;; 92 | 2) update_system ;; 93 | 3) clean_system ;; 94 | 4) enable_bbr ;; 95 | 5) root_login ;; 96 | "") 97 | return 98 | ;; 99 | *) echo -e "\e[31m无效选项,请重新输入。\e[0m" ;; 100 | esac 101 | done 102 | } 103 | 104 | # 时间校准 105 | calibrate_time() { 106 | echo -e "\n[校准时间]" 107 | sudo timedatectl set-timezone Asia/Shanghai 108 | sudo timedatectl set-ntp true 109 | echo -e "\e[32m时间校准完成,当前时区为 Asia/Shanghai。\e[0m" 110 | read -n 1 -s -r -p "按任意键返回..." 111 | echo 112 | } 113 | 114 | # 系统更新 115 | update_system() { 116 | echo -e "\n[更新系统]" 117 | if ! sudo apt update -y && ! sudo apt full-upgrade -y; then 118 | echo -e "\e[31m系统更新失败!请检查网络连接或源列表。\e[0m" 119 | else 120 | sudo apt autoremove -y && sudo apt autoclean -y 121 | echo -e "\e[32m系统更新完成!\e[0m" 122 | fi 123 | read -n 1 -s -r -p "按任意键返回..." 124 | echo 125 | } 126 | 127 | # 系统清理 128 | clean_system() { 129 | echo -e "\n[清理系统]" 130 | sudo apt autoremove --purge -y 131 | sudo apt clean -y && sudo apt autoclean -y 132 | sudo journalctl --rotate && sudo journalctl --vacuum-time=10m 133 | sudo journalctl --vacuum-size=50M 134 | echo -e "\e[32m系统清理完成!\e[0m" 135 | read -n 1 -s -r -p "按任意键返回..." 136 | echo 137 | } 138 | 139 | # 开启 BBR 140 | enable_bbr() { 141 | echo -e "\n[开启BBR]" 142 | if sysctl net.ipv4.tcp_congestion_control | grep -q 'bbr'; then 143 | echo -e "\e[32mBBR已开启!\e[0m" 144 | else 145 | echo "net.core.default_qdisc = fq" | sudo tee -a /etc/sysctl.conf 146 | echo "net.ipv4.tcp_congestion_control = bbr" | sudo tee -a /etc/sysctl.conf 147 | if sudo sysctl -p; then 148 | echo -e "\e[32mBBR已开启!\e[0m" 149 | else 150 | echo -e "\e[31mBBR 开启失败!\e[0m" 151 | fi 152 | fi 153 | read -n 1 -s -r -p "按任意键返回..." 154 | echo 155 | } 156 | 157 | # ROOT登录 158 | root_login() { 159 | while true; do 160 | echo "=========================================" 161 | echo -e " \e[1;34mROOT登录\e[0m " 162 | echo "=========================================" 163 | echo "1) 设置密码" 164 | echo "2) 修改配置" 165 | echo "3) 重启服务" 166 | echo "=========================================" 167 | read -p "请输入数字 [1-3] 选择 (默认回车退出):" root_choice 168 | case "$root_choice" in 169 | 1) 170 | sudo passwd root 171 | read -n 1 -s -r -p "按任意键返回..." 172 | echo 173 | ;; 174 | 2) 175 | sudo sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin yes/g' /etc/ssh/sshd_config; 176 | sudo sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication yes/g' /etc/ssh/sshd_config; 177 | echo -e "\e[32m配置修改成功!\e[0m" 178 | read -n 1 -s -r -p "按任意键返回..." 179 | echo 180 | ;; 181 | 3) 182 | if sudo systemctl restart sshd.service; then 183 | echo -e "\e[32mROOT登录已开启!\e[0m" 184 | else 185 | echo -e "\e[31mROOT登录开启失败!\e[0m" 186 | fi 187 | read -n 1 -s -r -p "按任意键返回..." 188 | echo 189 | ;; 190 | "") 191 | return 192 | ;; 193 | *) echo -e "\e[31m无效选项,请重新输入。\e[0m" ;; 194 | esac 195 | done 196 | } 197 | 198 | # 常用工具 199 | common_tools() { 200 | while true; do 201 | echo "=========================================" 202 | echo -e " \e[1;32m常用工具\e[0m " 203 | echo "=========================================" 204 | echo "1) 查找文件" 205 | echo "2) 赋予权限" 206 | echo "3) 删除文件" 207 | echo "4) 查看进程" 208 | echo "5) 关闭进程" 209 | echo "6) 查看端口" 210 | echo "7) 开放端口" 211 | echo "=========================================" 212 | read -p "请输入数字 [1-7] 选择 (默认回车退出):" root_choice 213 | case "$root_choice" in 214 | 1) 215 | read -p "请输入要查找的文件名: " filename 216 | if [[ -z "$filename" ]]; then 217 | echo -e "\e[31m文件名不能为空。\e[0m" 218 | else 219 | find / -type f -name "*$filename*" 2>/dev/null 220 | [[ $? -ne 0 ]] && echo -e "\e[31m未找到匹配的文件。\e[0m" 221 | fi 222 | read -n 1 -s -r -p "按任意键返回..." 223 | echo 224 | ;; 225 | 2) 226 | read -p "请输入文件路径: " file_path 227 | if [ ! -e "$file_path" ]; then 228 | echo -e "\e[31m错误: 文件或目录 '$file_path' 不存在。\e[0m" 229 | exit 1 230 | fi 231 | chmod 755 "$file_path" 232 | if [ $? -eq 0 ]; then 233 | echo -e "\e[32m'$file_path' 权限已设置为 755!\e[0m" 234 | else 235 | echo -e "\e[31m错误: 设置 '$file_path' 权限为 755 失败。\e[0m" 236 | exit 1 237 | fi 238 | read -n 1 -s -r -p "按任意键返回..." 239 | echo 240 | ;; 241 | 242 | 3) 243 | while true; do 244 | read -p "请输入要删除的文件或目录名(默认回车退出): " filename 245 | if [[ -z "$filename" ]]; then 246 | break 247 | fi 248 | files=($(find / -type f -iname "*$filename*" -o -type d -iname "*$filename*" 2>/dev/null)) 249 | if [[ ${#files[@]} -eq 0 ]]; then 250 | echo -e "\e[31m未找到匹配的文件或目录。\e[0m" 251 | continue 252 | fi 253 | echo "找到以下文件或目录:" 254 | for i in "${!files[@]}"; do 255 | echo "$((i+1)). ${files[$i]}" 256 | done 257 | read -p "请输入要删除的文件或目录编号(可多选,使用空格分隔,按回车取消删除): " choices 258 | if [[ -z "$choices" ]]; then 259 | echo "取消删除操作。" 260 | continue 261 | fi 262 | IFS=' ' read -r -a choice_array <<< "$choices" 263 | for choice in "${choice_array[@]}"; do 264 | if [[ "$choice" -ge 1 && "$choice" -le ${#files[@]} ]]; then 265 | file="${files[$((choice-1))]}" 266 | read -p "确定要删除 $file 吗? (y/n): " confirm 267 | if [[ "$confirm" == "y" ]]; then 268 | if [[ -d "$file" ]]; then 269 | rm -rf "$file" 270 | echo -e "\e[32m目录已删除: $file\e[0m" 271 | else 272 | rm -f "$file" 273 | echo -e "\e[32m文件已删除: $file\e[0m" 274 | fi 275 | else 276 | echo "取消删除 $file。" 277 | fi 278 | else 279 | echo -e "\e[31m无效的选择: $choice\e[0m" 280 | fi 281 | done 282 | done 283 | echo 284 | read -n 1 -s -r -p "按任意键返回..." 285 | echo 286 | ;; 287 | 4) 288 | ps aux 289 | read -n 1 -s -r -p "按任意键返回..." 290 | echo 291 | ;; 292 | 5) 293 | while true; do 294 | read -p "请输入要关闭的进程 PID: " pid 295 | if [[ "$pid" =~ ^[0-9]+$ ]]; then 296 | if kill "$pid"; then 297 | echo -e "\e[32m进程 $pid 已成功关闭!\e[0m" 298 | else 299 | echo -e "\e[31m进程 $pid 无法正常关闭 (SIGTERM),是否需要强制关闭 (SIGKILL)? (y/n)\e[0m" 300 | read -p "请选择 (y/n): " choice 301 | if [[ "$choice" == "y" ]]; then 302 | if kill -9 "$pid"; then 303 | echo -e "\e[32m进程 $pid 已被强制关闭!\e[0m" 304 | else 305 | echo -e "\e[31m进程 $pid 强制关闭失败。\e[0m" 306 | fi 307 | elif [[ "$choice" == "n" ]]; then 308 | echo "取消强制关闭" 309 | else 310 | echo -e "\e[31m无效的选项,进程未关闭。\e[0m" 311 | fi 312 | fi 313 | break 314 | else 315 | echo -e "\e[31m无效的 PID,请输入一个整数。\e[0m" 316 | fi 317 | done 318 | read -n 1 -s -r -p "按任意键返回..." 319 | echo 320 | ;; 321 | 6) 322 | if command -v ss &>/dev/null; then 323 | echo -e "端口 类型 程序名 PID" 324 | ss -tulnp | awk 'NR>1 { 325 | split($5, a, ":"); 326 | split($7, b, ","); 327 | gsub(/[()]/, "", b[1]); 328 | gsub(/pid=/, "", b[2]); 329 | gsub(/users:/, "", b[1]); 330 | gsub(/"/, "", b[1]); 331 | if (a[2] != "" && a[2] != "*") { 332 | printf "%-8s %-7s %-20s %-6s\n", a[2], $1, b[1], b[2]; 333 | } 334 | }' 335 | else 336 | echo -e "端口 类型 程序名 PID" 337 | netstat -tulnp | awk 'NR>2 { 338 | split($4, a, ":"); 339 | split($7, b, "/"); 340 | gsub(/[()]/, "", b[1]); 341 | gsub(/pid=/, "", b[2]); 342 | gsub(/users:/, "", b[1]); 343 | gsub(/"/, "", b[1]); 344 | if (a[2] != "" && a[2] != "*") { 345 | printf "%-8s %-7s %-20s %-6s\n", a[2], $1, b[1], b[2]; 346 | } 347 | }' 348 | fi 349 | read -n 1 -s -r -p "按任意键返回..." 350 | echo 351 | ;; 352 | 7) 353 | while true; do 354 | echo "请选择协议:" 355 | echo "1) TCP" 356 | echo "2) UDP" 357 | read -p "请输入1或2: " protocol_choice 358 | case "$protocol_choice" in 359 | 1) protocol="tcp" ;; 360 | 2) protocol="udp" ;; 361 | *) echo -e "\e[31m无效的选择,请输入1或2。\e[0m" 362 | break 363 | esac 364 | read -p "请输入端口号: " port 365 | if ! [[ "$port" =~ ^[0-9]+$ ]] || [ "$port" -lt 1 ] || [ "$port" -gt 65535 ]; then 366 | echo -e "\e[31m无效的端口号,请输入1到65535之间的数字。\e[0m" 367 | break 368 | fi 369 | command="sudo iptables -A INPUT -p $protocol --dport $port -j ACCEPT" 370 | if $command; then 371 | echo -e "\e[32m端口$port已开放($protocol)!\e[0m" 372 | else 373 | echo -e "\e[31m执行命令失败。\e[0m" 374 | fi 375 | break 376 | done 377 | read -n 1 -s -r -p "按任意键返回..." 378 | echo 379 | ;; 380 | "") 381 | return 382 | ;; 383 | *) 384 | echo -e "\e[31m无效选项,请重新输入。\e[0m" 385 | ;; 386 | esac 387 | done 388 | } 389 | 390 | # 常用软件包 391 | install_package() { 392 | while true; do 393 | echo "=========================================" 394 | echo -e " \e[1;32m常用软件包\e[0m " 395 | echo "=========================================" 396 | echo "1) apt" 397 | echo "2) sudo" 398 | echo "3) wget" 399 | echo "4) nano" 400 | echo "5) vim" 401 | echo "6) zip" 402 | echo "7) git" 403 | echo "8) htop" 404 | echo "9) docker" 405 | echo "=========================================" 406 | read -p "请输入数字 [1-7] 选择 (默认回车退出):" opt_choice 407 | case "$opt_choice" in 408 | 1) 409 | if apt update; then 410 | echo -e "\e[32mapt 更新完成!\e[0m" 411 | else 412 | echo -e "\e[31mapt 更新失败!请检查网络连接或源列表。\e[0m" 413 | fi 414 | read -n 1 -s -r -p "按任意键返回..." 415 | echo 416 | ;; 417 | 2) 418 | echo "1) 安装" 419 | echo "2) 卸载" 420 | read -p "请选择操作 (默认回车退出):" action 421 | case "$action" in 422 | 1) if apt update && apt install sudo -y; then 423 | echo -e "\e[32msudo 安装完成!\e[0m" 424 | else 425 | echo -e "\e[31msudo 安装失败!\e[0m" 426 | fi 427 | ;; 428 | 2) if sudo apt update && sudo apt remove -y sudo; then 429 | echo -e "\e[32msudo 卸载完成!\e[0m" 430 | else 431 | echo -e "\e[31msudo 卸载失败!\e[0m" 432 | fi 433 | ;; 434 | "") ;; 435 | *) echo -e "\e[31m无效选项,请重新输入。\e[0m" ;; 436 | esac 437 | read -n 1 -s -r -p "按任意键返回..." 438 | echo 439 | ;; 440 | 3) 441 | echo "1) 安装" 442 | echo "2) 卸载" 443 | read -p "请选择操作 (默认回车退出):" action 444 | case "$action" in 445 | 1) if sudo apt update && sudo apt install -y wget; then 446 | echo -e "\e[32mwget 安装完成!\e[0m" 447 | else 448 | echo -e "\e[31mwget 安装失败!\e[0m" 449 | fi 450 | ;; 451 | 2) if sudo apt remove -y wget; then 452 | echo -e "\e[32mwget 卸载完成!\e[0m" 453 | else 454 | echo -e "\e[31mwget 卸载失败!\e[0m" 455 | fi 456 | ;; 457 | "") ;; 458 | *) echo -e "\e[31m无效选项,请重新输入。\e[0m" ;; 459 | esac 460 | read -n 1 -s -r -p "按任意键返回..." 461 | echo 462 | ;; 463 | 4) 464 | echo "1) 安装" 465 | echo "2) 卸载" 466 | read -p "请选择操作 (默认回车退出):" action 467 | case "$action" in 468 | 1) if sudo apt update && sudo apt install -y nano; then 469 | echo -e "\e[32mnano 安装完成!\e[0m" 470 | else 471 | echo -e "\e[31mnano 安装失败!\e[0m" 472 | fi 473 | ;; 474 | 2) if sudo apt remove -y nano; then 475 | echo -e "\e[32mnano 卸载完成!\e[0m" 476 | else 477 | echo -e "\e[31mnano 卸载失败!\e[0m" 478 | fi 479 | ;; 480 | "") ;; 481 | *) echo -e "\e[31m无效选项,请重新输入。\e[0m" ;; 482 | esac 483 | read -n 1 -s -r -p "按任意键返回..." 484 | echo 485 | ;; 486 | 5) 487 | echo "1) 安装" 488 | echo "2) 卸载" 489 | read -p "请选择操作 (默认回车退出):" action 490 | case "$action" in 491 | 1) if sudo apt update && sudo apt install -y vim; then 492 | echo -e "\e[32mvim 安装完成!\e[0m" 493 | else 494 | echo -e "\e[31mvim 安装失败!\e[0m" 495 | fi 496 | ;; 497 | 2) if sudo apt remove -y vim; then 498 | echo -e "\e[32mvim 卸载完成!\e[0m" 499 | else 500 | echo -e "\e[31mvim 卸载失败!\e[0m" 501 | fi 502 | ;; 503 | "") ;; 504 | *) echo -e "\e[31m无效选项,请重新输入。\e[0m" ;; 505 | esac 506 | read -n 1 -s -r -p "按任意键返回..." 507 | echo 508 | ;; 509 | 6) 510 | echo "1) 安装" 511 | echo "2) 卸载" 512 | read -p "请选择操作 (默认回车退出):" action 513 | case "$action" in 514 | 1) if sudo apt update && sudo apt install -y zip; then 515 | echo -e "\e[32mzip 安装完成!\e[0m" 516 | else 517 | echo -e "\e[31mzip 安装失败!\e[0m" 518 | fi 519 | ;; 520 | 2) if sudo apt remove -y zip; then 521 | echo -e "\e[32mzip 卸载完成!\e[0m" 522 | else 523 | echo -e "\e[31mzip 卸载失败!\e[0m" 524 | fi 525 | ;; 526 | "") ;; 527 | *) echo -e "\e[31m无效选项,请重新输入。\e[0m" ;; 528 | esac 529 | read -n 1 -s -r -p "按任意键返回..." 530 | echo 531 | ;; 532 | 7) 533 | echo "1) 安装" 534 | echo "2) 卸载" 535 | read -p "请选择操作 (默认回车退出):" action 536 | case "$action" in 537 | 1) if sudo apt update && sudo apt install -y git; then 538 | echo -e "\e[32mgit 安装完成!\e[0m" 539 | else 540 | echo -e "\e[31mgit 安装失败!\e[0m" 541 | fi 542 | ;; 543 | 2) if sudo apt remove -y git; then 544 | echo -e "\e[32mgit 卸载完成!\e[0m" 545 | else 546 | echo -e "\e[31mgit 卸载失败!\e[0m" 547 | fi 548 | ;; 549 | "") ;; 550 | *) echo -e "\e[31m无效选项,请重新输入。\e[0m" ;; 551 | esac 552 | read -n 1 -s -r -p "按任意键返回..." 553 | echo 554 | ;; 555 | 8) 556 | echo "1) 安装" 557 | echo "2) 卸载" 558 | read -p "请选择操作 (默认回车退出):" action 559 | case "$action" in 560 | 1) if sudo apt update && sudo apt install -y htop; then 561 | echo -e "\e[32mhtop 安装完成!\e[0m" 562 | else 563 | echo -e "\e[31mhtop 安装失败!\e[0m" 564 | fi 565 | ;; 566 | 2) if sudo apt remove -y htop; then 567 | echo -e "\e[32mhtop 卸载完成!\e[0m" 568 | else 569 | echo -e "\e[31mhtop 卸载失败!\e[0m" 570 | fi 571 | ;; 572 | "") ;; 573 | *) echo -e "\e[31m无效选项,请重新输入。\e[0m" ;; 574 | esac 575 | read -n 1 -s -r -p "按任意键返回..." 576 | echo 577 | ;; 578 | 9) 579 | echo "1) 安装" 580 | echo "2) 卸载" 581 | read -p "请选择操作 (默认回车退出):" action 582 | case "$action" in 583 | 1) if curl -sSL https://get.docker.com/ | sh; then 584 | echo -e "\e[32mdocker 安装完成!\e[0m" 585 | else 586 | echo -e "\e[31mdocker 安装失败!\e[0m" 587 | fi 588 | ;; 589 | 2) if sudo apt remove -y docker; then 590 | echo -e "\e[32mdocker 卸载完成!\e[0m" 591 | else 592 | echo -e "\e[31mdocker 卸载失败!\e[0m" 593 | fi 594 | ;; 595 | "") ;; 596 | *) echo -e "\e[31m无效选项,请重新输入。\e[0m" ;; 597 | esac 598 | read -n 1 -s -r -p "按任意键返回..." 599 | echo 600 | ;; 601 | "") 602 | return 603 | ;; 604 | *) echo -e "\e[31m无效选项,请重新输入。\e[0m" ;; 605 | esac 606 | done 607 | } 608 | 609 | # 申请证书 610 | apply_certificate() { 611 | while true; do 612 | echo "=========================================" 613 | echo -e " \e[1;32m申请证书\e[0m " 614 | echo "=========================================" 615 | echo "1) 安装脚本" 616 | echo "2) 申请证书" 617 | echo "3) 更换服务器" 618 | echo "4) 安装证书" 619 | echo "5) 卸载脚本" 620 | echo "=========================================" 621 | read -p "请输入数字 [1-5] 选择 (默认回车退出):" cert_choice 622 | case "$cert_choice" in 623 | 1) 624 | read -p "请输入邮箱地址: " email 625 | sudo apt update 626 | if ! command -v crontab &> /dev/null; then 627 | echo "正在安装 cron..." 628 | if sudo apt install -y cron; then 629 | echo -e "\e[32mcron 安装完成!\e[0m" 630 | else 631 | echo -e "\e[31mcron 安装失败!\e[0m" 632 | fi 633 | fi 634 | if ! command -v socat &> /dev/null; then 635 | echo "正在安装 socat..." 636 | if sudo apt install -y socat; then 637 | echo -e "\e[32msocat 安装完成!\e[0m" 638 | else 639 | echo -e "\e[31msocat 安装失败!\e[0m" 640 | fi 641 | fi 642 | if curl https://get.acme.sh | sh -s email="$email"; then 643 | echo -e "\e[32macme.sh 安装完成!\e[0m" 644 | else 645 | echo -e "\e[31macme.sh 安装失败!\e[0m" 646 | fi 647 | read -n 1 -s -r -p "按任意键返回..." 648 | echo 649 | ;; 650 | 2) 651 | while true; do 652 | read -p "请输入域名: " domain 653 | if ~/.acme.sh/acme.sh --issue --standalone -d "$domain"; then 654 | echo -e "\e[32m证书申请成功!\e[0m" 655 | else 656 | echo -e "\e[31m证书申请失败,请检查域名是否正确并重试。\e[0m" 657 | fi 658 | break 659 | done 660 | read -n 1 -s -r -p "按任意键返回..." 661 | echo 662 | ;; 663 | 3) 664 | ~/.acme.sh/acme.sh --set-default-ca --server letsencrypt 665 | if [[ $? -eq 0 ]]; then 666 | echo -e "\e[32m已切换至Let's Encrypt服务!\e[0m" 667 | else 668 | echo -e "\e[31m切换至Let's Encrypt服务失败,请检查是否正确安装acme.sh并确保网络连接正常。\e[0m" 669 | fi 670 | read -n 1 -s -r -p "按任意键返回..." 671 | echo 672 | ;; 673 | 4) 674 | read -p "请输入域名: " domain 675 | read -p "请输入证书安装路径(默认: /path/to): " install_path 676 | install_path=${install_path:-/path/to} 677 | if mkdir -p "$install_path" && \ 678 | ~/.acme.sh/acme.sh --installcert -d "$domain" \ 679 | --key-file "$install_path/private.key" --fullchain-file "$install_path/fullchain.crt" && \ 680 | sudo chmod 644 "$install_path/fullchain.crt" "$install_path/private.key"; then 681 | echo -e "\e[32m证书安装完成!路径: $install_path\e[0m" 682 | else 683 | echo -e "\e[31m证书安装失败,请检查输入。\e[0m" 684 | fi 685 | read -n 1 -s -r -p "按任意键返回..." 686 | echo 687 | ;; 688 | 5) 689 | if ~/.acme.sh/acme.sh --uninstall; then 690 | echo -e "\e[32macme.sh 已卸载。\e[0m" 691 | else 692 | echo -e "\e[31macme.sh 卸载失败!\e[0m" 693 | fi 694 | read -n 1 -s -r -p "按任意键返回..." 695 | echo 696 | ;; 697 | "") 698 | return 699 | ;; 700 | *) 701 | echo -e "\e[31m无效选项,请重新输入。\e[0m" 702 | ;; 703 | esac 704 | done 705 | } 706 | 707 | # 安装Xray 708 | install_xray() { 709 | while true; do 710 | echo "=========================================" 711 | echo -e " \e[1;32m安装Xray\e[0m " 712 | echo "=========================================" 713 | echo "1) VLESS-WS-TLS" 714 | echo "2) VLESS-TCP-REALITY" 715 | echo "3) 卸载服务" 716 | echo "=========================================" 717 | read -p "请输入数字 [1-2] 选择 (默认回车退出):" opt_choice 718 | case "$opt_choice" in 719 | 1) install_xray_tls ;; 720 | 2) install_xray_reality ;; 721 | "") 722 | return 723 | ;; 724 | 3) 725 | if bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ remove --purge; then 726 | echo -e "\e[32mXray已卸载。\e[0m" 727 | else 728 | echo -e "\e[31mXray卸载失败!\e[0m" 729 | fi 730 | read -n 1 -s -r -p "按任意键返回..." 731 | echo 732 | ;; 733 | "") 734 | return 735 | ;; 736 | *) echo -e "\e[31m无效选项,请重新输入。\e[0m" ;; 737 | esac 738 | done 739 | } 740 | 741 | # 安装VLESS-WS-TLS 742 | install_xray_tls() { 743 | while true; do 744 | echo "=========================================" 745 | echo -e " \e[1;34mVLESS-WS-TLS\e[0m " 746 | echo "=========================================" 747 | echo "1) 安装升级" 748 | echo "2) 编辑配置" 749 | echo "3) 重启服务" 750 | echo "=========================================" 751 | read -p "请输入数字 [1-3] 选择功能 (默认回车退出):" xray_choice 752 | case "$xray_choice" in 753 | 1) 754 | if bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install && \ 755 | sudo curl -o /usr/local/etc/xray/config.json "https://raw.githubusercontent.com/XTLS/Xray-examples/refs/heads/main/VLESS-TCP-TLS-WS%20(recommended)/config_server.jsonc"; then 756 | echo -e "\e[32mXray 安装升级完成!\e[0m" 757 | echo "以下是uuid:" 758 | echo -e "\e[34m$(xray uuid)\e[0m" 759 | else 760 | echo -e "\e[31mXray 安装升级失败!\e[0m" 761 | fi 762 | read -n 1 -s -r -p "按任意键返回..." 763 | echo 764 | ;; 765 | 2) 766 | echo -e "\e[33m提示:将UUID填入配置文件中。若已执行成功默认设置的“安装证书”则证书路径无须修改。\e[0m" 767 | read -n 1 -s -r -p "按任意键继续..." 768 | if ! command -v nano >/dev/null 2>&1; then 769 | sudo apt update >/dev/null 2>&1 && sudo apt install -y nano >/dev/null 2>&1 770 | fi 771 | if ! command -v nano >/dev/null 2>&1; then 772 | echo -e "\e[31m错误:无法安装或找到 nano!\e[0m" >&2 773 | exit 1 774 | fi 775 | sudo nano /usr/local/etc/xray/config.json 776 | read -n 1 -s -r -p "按任意键返回..." 777 | echo 778 | ;; 779 | 3) 780 | CONFIG_PATH="/usr/local/etc/xray/config.json" 781 | extract_field() { 782 | local pattern="$1" 783 | local match="$2" 784 | grep -aPo "\"$pattern\":\s*$match" "$CONFIG_PATH" | head -n 1 | sed -E "s/\"$pattern\":\s*//;s/^\"//;s/\"$//" 785 | } 786 | extract_list_field() { 787 | local list_parent="$1" 788 | local list_field="$2" 789 | grep -aPoz "\"$list_parent\":\s*\[\s*\{[^}]*\}\s*\]" "$CONFIG_PATH" | grep -aPo "\"$list_field\":\s*\"[^\"]*\"" | head -n 1 | sed -E "s/\"$list_field\":\s*\"([^\"]*)\"/\1/" 790 | } 791 | get_domain_from_cert() { 792 | local cert_file="$1" 793 | openssl x509 -in "$cert_file" -text -noout | grep -aPo "DNS:[^,]*" | sed 's/DNS://' | head -n 1 || 794 | openssl x509 -in "$cert_file" -text -noout | grep -aPo "CN=[^ ]*" | sed 's/CN=//' 795 | } 796 | get_public_ip() { 797 | ipv4=$(curl -s https://api.ipify.org) 798 | if [[ -n "$ipv4" ]]; then 799 | echo "$ipv4" 800 | else 801 | curl -s -6 https://api64.ipify.org || echo "127.0.0.1" 802 | fi 803 | } 804 | while true; do 805 | sudo systemctl restart xray 806 | sleep 2 807 | if ! systemctl is-active --quiet xray; then 808 | echo -e "\e[31m未能启动 xray 服务,请检查日志。\e[0m" 809 | systemctl status xray --no-pager 810 | break 811 | else 812 | echo -e "\e[32mxray已启动!\e[0m" 813 | fi 814 | UUID=$(extract_list_field "clients" "id") 815 | PORT=$(extract_field "port" "\d+") 816 | WS_PATH=$(extract_field "path" "\"[^\"]*\"") 817 | TLS=$(extract_field "security" "\"[^\"]*\"") 818 | CERT_PATH=$(extract_list_field "certificates" "certificateFile") 819 | if [[ -z "$CERT_PATH" ]]; then 820 | echo -e "\e[31m未能找到证书路径。\e[0m" 821 | break 822 | fi 823 | DOMAIN=$(get_domain_from_cert "$CERT_PATH") 824 | SNI=${DOMAIN:-"your.domain.net"} 825 | HOST=${DOMAIN:-"your.domain.net"} 826 | ADDRESS=$(get_public_ip) 827 | WS_PATH=${WS_PATH:-"/"} 828 | TLS=${TLS:-"tls"} 829 | PORT=${PORT:-"443"} 830 | vless_uri="vless://${UUID}@${ADDRESS}:${PORT}?encryption=none&security=${TLS}&sni=${SNI}&type=ws&host=${HOST}&path=${WS_PATH}#Xray" 831 | echo "VLESS链接如下" 832 | echo -e "\e[34m$vless_uri\e[0m" 833 | break 834 | done 835 | read -n 1 -s -r -p "按任意键返回..." 836 | echo 837 | ;; 838 | "") 839 | return 840 | ;; 841 | *) 842 | echo -e "\e[31m无效选项,请重新输入。\e[0m" 843 | ;; 844 | esac 845 | done 846 | } 847 | 848 | # 安装VLESS-TCP-REALITY 849 | install_xray_reality() { 850 | while true; do 851 | echo "=========================================" 852 | echo -e " \e[1;34mVLESS-TCP-REALITY\e[0m " 853 | echo "=========================================" 854 | echo "1) 安装升级" 855 | echo "2) 编辑配置" 856 | echo "3) 重启服务" 857 | echo "=========================================" 858 | read -p "请输入数字 [1-3] 选择(默认回车退出):" xray_choice 859 | case "$xray_choice" in 860 | 1) 861 | if bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install && \ 862 | sudo curl -o /usr/local/etc/xray/config.json "https://raw.githubusercontent.com/XTLS/Xray-examples/refs/heads/main/VLESS-TCP-XTLS-Vision-REALITY/config_server.jsonc"; then 863 | echo -e "\e[32mXray 安装升级完成!\e[0m" 864 | echo "以下是UUID:" 865 | echo -e "\e[34m$(xray uuid)\e[0m" 866 | echo "以下是私钥:" 867 | keys=$(xray x25519) 868 | export PRIVATE_KEY=$(echo "$keys" | head -n 1 | awk '{print $3}' | sed 's/^-//') 869 | export PUBLIC_KEY=$(echo "$keys" | tail -n 1 | awk '{print $3}' | sed 's/^-//') 870 | echo -e "\e[34m$PRIVATE_KEY\e[0m" 871 | echo "以下是ShortIds:" 872 | echo -e "\e[34m$(openssl rand -hex 8)\e[0m" 873 | else 874 | echo -e "\e[31mXray 安装升级失败!\e[0m" 875 | fi 876 | read -n 1 -s -r -p "按任意键返回..." 877 | echo 878 | ;; 879 | 2) 880 | echo -e "\e[33m提示:将UUID、目标网站及私钥填入配置文件中,ShortIds非必须。\e[0m" 881 | read -n 1 -s -r -p "按任意键继续..." 882 | if ! command -v nano >/dev/null 2>&1; then 883 | sudo apt update >/dev/null 2>&1 && sudo apt install -y nano >/dev/null 2>&1 884 | fi 885 | if ! command -v nano >/dev/null 2>&1; then 886 | echo -e "\e[31m错误:无法安装或找到 nano!\e[0m" >&2 887 | exit 1 888 | fi 889 | sudo nano /usr/local/etc/xray/config.json 890 | read -n 1 -s -r -p "按任意键返回..." 891 | echo 892 | ;; 893 | 3) 894 | CONFIG_PATH="/usr/local/etc/xray/config.json" 895 | remove_spaces_and_quotes() { 896 | echo "$1" | sed 's/[[:space:]]*$//;s/^ *//;s/^"//;s/"$//' 897 | } 898 | extract_field() { 899 | local pattern=$1 900 | local match=$2 901 | grep -aPo "\"$pattern\":\s*$match" "$CONFIG_PATH" | head -n 1 | sed -E "s/\"$pattern\":\s*//;s/^\"//;s/\"$//" 902 | } 903 | extract_server_name() { 904 | local result=$(grep -aA 2 "\"serverNames\": \[" "$CONFIG_PATH" | awk 'NR==2{gsub(/^\s+|\s*\/\/.*$/,"");split($0,a,","); for (i in a) {gsub(/^[\"\s]+|[\"\s]+$/,"",a[i]);printf "%s ",a[i]}}') 905 | if [[ -n "$result" ]]; then 906 | remove_spaces_and_quotes "$result" 907 | fi 908 | } 909 | extract_list_field() { 910 | local list_parent=$1 911 | local list_field=$2 912 | if [[ "$list_field" == "shortIds" || "$list_field" == "serverNames" ]]; then 913 | local result=$(grep -aA 2 "\"$list_field\": \[" "$CONFIG_PATH" | awk 'NR==2{gsub(/^\s+|\s*\/\/.*$/,"");split($0,a,","); for (i in a) {gsub(/^[\"\s]+|[\"\s]+$/,"",a[i]);printf "%s ",a[i]}}') 914 | if [[ -n "$result" ]]; then 915 | remove_spaces_and_quotes "$result" 916 | fi 917 | else 918 | grep -aPoz "\"$list_parent\":\s*\[\s*\{[^}]*\}\s*\]" "$CONFIG_PATH" | grep -aPo "\"$list_field\":\s*\"[^\"]*\"" | head -n 1 | sed -E "s/\"$list_field\":\s*\"([^\"]*)\"/\1/" 919 | fi 920 | } 921 | get_public_ip() { 922 | ipv4=$(curl -s https://api.ipify.org) 923 | if [[ -n "$ipv4" ]]; then 924 | echo "$ipv4" 925 | else 926 | curl -s -6 https://api64.ipify.org || echo "127.0.0.1" 927 | fi 928 | } 929 | while true; do 930 | sudo systemctl restart xray 931 | sleep 2 932 | if ! systemctl is-active --quiet xray; then 933 | echo -e "\e[31m未能启动 xray 服务,请检查日志。\e[0m" 934 | systemctl status xray --no-pager 935 | break 936 | else 937 | echo -e "\e[32mxray已启动!\e[0m" 938 | fi 939 | UUID=$(extract_list_field "clients" "id") 940 | PORT=$(extract_field "port" "\d+") 941 | TLS=$(extract_field "security" "\"[^\"]*\"") 942 | SERVER_NAME=$(extract_server_name) 943 | SHORT_IDS=$(extract_list_field "realitySettings" "shortIds") 944 | SNI=${SERVER_NAME:-"your.domain.net"} 945 | ADDRESS=$(get_public_ip) 946 | PORT=${PORT:-"443"} 947 | FLOW=$(extract_field "flow" "\"[^\"]*\"") 948 | SID=${SHORT_IDS:-""} 949 | PBK=${PUBLIC_KEY} 950 | vless_uri="vless://${UUID}@${ADDRESS}:${PORT}?encryption=none&flow=${FLOW}&security=reality&sni=${SNI}&fp=chrome&pbk=${PBK}&sid=${SID}&type=tcp&headerType=none#Xray" 951 | echo "VLESS链接如下:" 952 | echo -e "\e[34m$vless_uri\e[0m" 953 | break 954 | done 955 | read -n 1 -s -r -p "按任意键返回..." 956 | echo 957 | ;; 958 | "") 959 | return 960 | ;; 961 | *) 962 | echo -e "\e[31m无效选项,请重新输入。\e[0m" 963 | ;; 964 | esac 965 | done 966 | } 967 | 968 | # 安装Hysteria2 969 | install_hysteria2() { 970 | while true; do 971 | echo "=========================================" 972 | echo -e " \e[1;32m安装Hysteria2\e[0m " 973 | echo "=========================================" 974 | echo "1) 安装升级" 975 | echo "2) 编辑配置" 976 | echo "3) 重启服务" 977 | echo "4) 端口跳跃" 978 | echo "5) 卸载服务" 979 | echo "=========================================" 980 | read -p "请输入数字 [1-5] 选择 (默认回车退出):" hysteria_choice 981 | case "$hysteria_choice" in 982 | 1) 983 | if bash <(curl -fsSL https://get.hy2.sh/) && \ 984 | sudo systemctl enable --now hysteria-server.service && \ 985 | sysctl -w net.core.rmem_max=16777216 && \ 986 | sysctl -w net.core.wmem_max=16777216; then 987 | echo -e "\e[32mhysteria2 安装升级完成!\e[0m" 988 | else 989 | echo -e "\e[31mhysteria2 安装升级失败!\e[0m" 990 | fi 991 | read -n 1 -s -r -p "按任意键返回..." 992 | echo 993 | ;; 994 | 2) 995 | echo -e "\e[33m提示:将域名填入配置文件中。\e[0m" 996 | read -n 1 -s -r -p "按任意键继续..." 997 | if ! command -v nano >/dev/null 2>&1; then 998 | sudo apt update >/dev/null 2>&1 && sudo apt install -y nano >/dev/null 2>&1 999 | fi 1000 | if ! command -v nano >/dev/null 2>&1; then 1001 | echo -e "\e[31m错误:无法安装或找到 nano!\e[0m" >&2 1002 | exit 1 1003 | fi 1004 | sudo nano /etc/hysteria/config.yaml 1005 | read -n 1 -s -r -p "按任意键返回..." 1006 | echo 1007 | ;; 1008 | 3) 1009 | config_file="/etc/hysteria/config.yaml" 1010 | get_domain_from_cert() { 1011 | local cert_file=$1 1012 | openssl x509 -in "$cert_file" -text -noout | grep -Po "DNS:[^,]*" | head -n 1 | sed 's/DNS://' || 1013 | openssl x509 -in "$cert_file" -text -noout | grep -Po "CN=[^ ]*" | sed 's/CN=//' 1014 | } 1015 | if [ ! -f "$config_file" ]; then 1016 | echo -e "\e[31m未能找到配置文件。\e[0m" 1017 | break 1018 | fi 1019 | while true; do 1020 | sudo systemctl restart hysteria-server.service 1021 | sleep 2 1022 | if ! systemctl is-active --quiet hysteria-server.service; then 1023 | echo -e "\e[31m未能启动 hysteria 服务,请检查日志。\e[0m" 1024 | sudo systemctl status hysteria-server.service --no-pager 1025 | break 1026 | else 1027 | echo -e "\e[32mhysteria已启动!\e[0m" 1028 | fi 1029 | port=$(grep "^listen:" "$config_file" | awk -F: '{print $3}' || echo "443") 1030 | password=$(grep "^ password:" "$config_file" | awk '{print $2}') 1031 | domain=$(grep "domains:" "$config_file" -A 1 | tail -n 1 | tr -d " -") 1032 | if [ -z "$domain" ]; then 1033 | cert_path=$(grep "cert:" "$config_file" | awk '{print $2}' | tr -d '"') 1034 | if [ -z "$cert_path" ] || [ ! -f "$cert_path" ]; then 1035 | echo -e "\e[31m没有找到域名或证书。\e[0m" 1036 | break 1037 | fi 1038 | domain=$(get_domain_from_cert "$cert_path") 1039 | if [ -z "$domain" ]; then 1040 | echo -e "\e[31m从证书中提取域名失败。\e[0m" 1041 | break 1042 | fi 1043 | fi 1044 | ip=$(curl -s https://ifconfig.me) 1045 | hysteria2_uri="hysteria2://$password@$ip:$port?sni=$domain&insecure=0#hysteria" 1046 | echo "hysteria2 链接如下:" 1047 | echo -e "\e[34m$hysteria2_uri\e[0m" 1048 | break 1049 | done 1050 | read -n 1 -s -r -p "按任意键返回..." 1051 | echo 1052 | ;; 1053 | 4) 1054 | default_redirect_port=443 1055 | default_start_port=60000 1056 | default_end_port=65535 1057 | config_file="/etc/hysteria/config.yaml" 1058 | redirect_port=$( 1059 | if [[ -f "$config_file" ]]; then 1060 | grep 'listen:' "$config_file" | awk -F':' '{print $NF}' 1061 | fi 1062 | ) 1063 | [[ -z "$redirect_port" || ! "$redirect_port" =~ ^[0-9]+$ || "$redirect_port" -lt 1 || "$redirect_port" -gt 65535 ]] && redirect_port="$default_redirect_port" 1064 | read -p "请输入起始端口号 (按 Enter 使用默认值 60000): " start_port 1065 | [[ -z "$start_port" ]] && start_port="$default_start_port" 1066 | [[ "$start_port" =~ ^[0-9]+$ && "$start_port" -ge 1 && "$start_port" -le 65535 ]] || { echo -e "\e[31m起始端口号无效, 使用默认值 60000\e[0m"; start_port="$default_start_port"; } 1067 | read -p "请输入结束端口号 (按 Enter 使用默认值 65535): " end_port 1068 | [[ -z "$end_port" ]] && end_port="$default_end_port" 1069 | [[ "$end_port" =~ ^[0-9]+$ && "$end_port" -ge 1 && "$end_port" -le 65535 && "$end_port" -ge "$start_port" ]] || { echo -e "\e[31m结束端口号无效,使用默认值 65535\e[0m"; end_port="$default_end_port"; } 1070 | interfaces=($(ip -o link | awk -F': ' '{if ($2 != "lo") print $2}')) 1071 | [[ ${#interfaces[@]} -eq 0 ]] && { echo -e "\e[31m未找到网络接口,无法执行 iptables 命令。\e[0m"; exit 1; } 1072 | selected_interface="${interfaces[0]}" 1073 | iptables_command="iptables -t nat -A PREROUTING -i $selected_interface -p udp --dport $start_port:$end_port -j REDIRECT --to-ports $redirect_port" 1074 | if eval "$iptables_command"; then 1075 | echo -e "\e[32m端口跳跃设置成功!\e[0m" 1076 | else 1077 | echo -e "\e[31miptables命令执行失败。\e[0m" 1078 | exit 1 1079 | fi 1080 | read -n 1 -s -r -p "按任意键返回..." 1081 | echo 1082 | ;; 1083 | 5) 1084 | if bash <(curl -fsSL https://get.hy2.sh/) --remove && \ 1085 | rm -rf /etc/hysteria && 1086 | userdel -r hysteria && 1087 | rm -f /etc/systemd/system/multi-user.target.wants/hysteria-server.service && 1088 | rm -f /etc/systemd/system/multi-user.target.wants/hysteria-server@*.service && 1089 | systemctl daemon-reload; then 1090 | echo -e "\e[32mhysteria2 已卸载。\e[0m" 1091 | fi 1092 | read -n 1 -s -r -p "按任意键返回..." 1093 | echo 1094 | ;; 1095 | "") 1096 | return 1097 | ;; 1098 | *) 1099 | echo -e "\e[31m无效选项,请重新输入。\e[0m" 1100 | ;; 1101 | esac 1102 | done 1103 | } 1104 | 1105 | # 安装sing-box 1106 | install_sing-box() { 1107 | while true; do 1108 | echo "=========================================" 1109 | echo -e " \e[1;32m安装sing-box\e[0m " 1110 | echo "=========================================" 1111 | echo "1) 安装升级" 1112 | echo "2) 编辑配置" 1113 | echo "3) 重启服务" 1114 | echo "4) 卸载服务" 1115 | echo "=========================================" 1116 | read -p "请输入数字 [1-4] 选择 (默认回车退出):" singbox_choice 1117 | case "$singbox_choice" in 1118 | 1) 1119 | if bash <(curl -fsSL https://sing-box.app/deb-install.sh) && \ 1120 | sudo curl -L -o /etc/sing-box/config.json "https://raw.githubusercontent.com/sezhai/VPS-Script/refs/heads/main/extras/sing-box/config.json"; then 1121 | echo -e "\e[32msing-box 安装升级成功!\e[0m" 1122 | echo "以下是UUID:" 1123 | echo -e "\e[34m$(sing-box generate uuid)\e[0m" 1124 | keys=$(sing-box generate reality-keypair) 1125 | export PRIVATE_KEY=$(echo "$keys" | awk '/PrivateKey/ {print $2}') 1126 | export PUBLIC_KEY=$(echo "$keys" | awk '/PublicKey/ {print $2}') 1127 | echo "以下是私钥:" 1128 | echo -e "\e[34m$PRIVATE_KEY\e[0m" 1129 | echo "以下是公钥:" 1130 | echo -e "\e[34m$PUBLIC_KEY\e[0m" 1131 | echo "以下是ShortIds:" 1132 | echo -e "\e[34m$(sing-box generate rand 8 --hex)\e[0m" 1133 | else 1134 | echo -e "\e[31msing-box 安装升级失败!\e[0m" 1135 | fi 1136 | read -n 1 -s -r -p "按任意键返回..." 1137 | echo 1138 | ;; 1139 | 2) 1140 | echo -e "\e[33m提示:根据提示修改配置文件。\e[0m" 1141 | read -n 1 -s -r -p "按任意键继续..." 1142 | if ! command -v nano >/dev/null 2>&1; then 1143 | sudo apt update >/dev/null 2>&1 && sudo apt install -y nano >/dev/null 2>&1 1144 | fi 1145 | if ! command -v nano >/dev/null 2>&1; then 1146 | echo -e "\e[31m无法安装或找到 nano。\e[0m" >&2 1147 | exit 1 1148 | fi 1149 | sudo nano /etc/sing-box/config.json 1150 | read -n 1 -s -r -p "按任意键返回..." 1151 | echo 1152 | ;; 1153 | 3) 1154 | CONFIG_PATH="/etc/sing-box/config.json" 1155 | sudo systemctl restart sing-box 1156 | sleep 2 1157 | if ! systemctl is-active --quiet sing-box; then 1158 | echo -e "\e[31m未能启动 sing-box 服务,请检查日志。\e[0m" 1159 | systemctl status sing-box --no-pager 1160 | exit 1 1161 | else 1162 | echo -e "\e[32msing-box已启动!\e[0m" 1163 | fi 1164 | get_ip() { 1165 | curl -s https://api.ipify.org || echo "127.0.0.1" 1166 | } 1167 | urlencode() { 1168 | local s="$1" ch 1169 | for ((i=0; i<${#s}; i++)); do 1170 | ch="${s:i:1}" 1171 | case "$ch" in 1172 | [a-zA-Z0-9.~_-]) printf '%s' "$ch" ;; 1173 | *) printf '%%%02X' "'$ch" ;; 1174 | esac 1175 | done 1176 | } 1177 | ip=$(get_ip) 1178 | vmess_uuid=$(grep -Pzo '(?s)"tag": "vmess".*?uuid":\s*"\K[^"]+' "$CONFIG_PATH" | tr -d '\0') 1179 | vmess_port=$(grep -Pzo '(?s)"tag": "vmess".*?listen_port":\s*\K[0-9]+' "$CONFIG_PATH" | tr -d '\0') 1180 | vmess_path=$(grep -Pzo '(?s)"tag": "vmess".*?path":\s*"\K[^"]+' "$CONFIG_PATH" | tr -d '\0') 1181 | vmess_host=$(grep -Pzo '(?s)"tag": "vmess".*?server_name":\s*"\K[^"]+' "$CONFIG_PATH" | tr -d '\0') 1182 | vmess_sni="$vmess_host" 1183 | vmess_json=$(cat <