├── install.sh ├── readme.md └── x-ui.sh /install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | red='\033[0;31m' 4 | green='\033[0;32m' 5 | blue='\033[0;34m' 6 | yellow='\033[0;33m' 7 | plain='\033[0m' 8 | 9 | cur_dir=$(pwd) 10 | 11 | # check root 12 | [[ $EUID -ne 0 ]] && echo -e "${red}Fatal error: ${plain} Please run this script with root privilege \n " && exit 1 13 | 14 | # Check OS and set release variable 15 | if [[ -f /etc/os-release ]]; then 16 | source /etc/os-release 17 | release=$ID 18 | elif [[ -f /usr/lib/os-release ]]; then 19 | source /usr/lib/os-release 20 | release=$ID 21 | else 22 | echo "Failed to check the system OS, please contact the author!" >&2 23 | exit 1 24 | fi 25 | echo "The OS release is: $release" 26 | 27 | arch() { 28 | case "$(uname -m)" in 29 | x86_64 | x64 | amd64) echo 'amd64' ;; 30 | i*86 | x86) echo '386' ;; 31 | armv8* | armv8 | arm64 | aarch64) echo 'arm64' ;; 32 | armv7* | armv7 | arm) echo 'armv7' ;; 33 | armv6* | armv6) echo 'armv6' ;; 34 | armv5* | armv5) echo 'armv5' ;; 35 | s390x) echo 's390x' ;; 36 | *) echo -e "${green}Unsupported CPU architecture! ${plain}" && rm -f install.sh && exit 1 ;; 37 | esac 38 | } 39 | 40 | echo "Arch: $(arch)" 41 | 42 | check_glibc_version() { 43 | glibc_version=$(ldd --version | head -n1 | awk '{print $NF}') 44 | 45 | required_version="2.15" 46 | if [[ "$(printf '%s\n' "$required_version" "$glibc_version" | sort -V | head -n1)" != "$required_version" ]]; then 47 | echo -e "${red}GLIBC version $glibc_version is too old! Required: 2.15 or higher${plain}" 48 | echo "Please upgrade to a newer version of your operating system to get a higher GLIBC version." 49 | exit 1 50 | fi 51 | echo "GLIBC version: $glibc_version (meets requirement of 2.15+)" 52 | } 53 | check_glibc_version 54 | 55 | install_base() { 56 | case "${release}" in 57 | ubuntu | debian | armbian) 58 | apt-get update && apt-get install -y -q wget curl tar tzdata 59 | ;; 60 | centos | almalinux | rocky | ol) 61 | yum -y update && yum install -y -q wget curl tar tzdata 62 | ;; 63 | fedora | amzn | virtuozzo) 64 | dnf -y update && dnf install -y -q wget curl tar tzdata 65 | ;; 66 | arch | manjaro | parch) 67 | pacman -Syu && pacman -Syu --noconfirm wget curl tar tzdata 68 | ;; 69 | opensuse-tumbleweed) 70 | zypper refresh && zypper -q install -y wget curl tar timezone 71 | ;; 72 | *) 73 | apt-get update && apt install -y -q wget curl tar tzdata 74 | ;; 75 | esac 76 | } 77 | 78 | gen_random_string() { 79 | local length="$1" 80 | local random_string=$(LC_ALL=C tr -dc 'a-zA-Z0-9' &2 34 | exit 1 35 | fi 36 | echo "The OS release is: $release" 37 | 38 | os_version="" 39 | os_version=$(grep "^VERSION_ID" /etc/os-release | cut -d '=' -f2 | tr -d '"' | tr -d '.') 40 | 41 | # Declare Variables 42 | log_folder="${XUI_LOG_FOLDER:=/var/log}" 43 | iplimit_log_path="${log_folder}/3xipl.log" 44 | iplimit_banned_log_path="${log_folder}/3xipl-banned.log" 45 | 46 | confirm() { 47 | if [[ $# > 1 ]]; then 48 | echo && read -rp "$1 [Default $2]: " temp 49 | if [[ "${temp}" == "" ]]; then 50 | temp=$2 51 | fi 52 | else 53 | read -rp "$1 [y/n]: " temp 54 | fi 55 | if [[ "${temp}" == "y" || "${temp}" == "Y" ]]; then 56 | return 0 57 | else 58 | return 1 59 | fi 60 | } 61 | 62 | confirm_restart() { 63 | confirm "Restart the panel, Attention: Restarting the panel will also restart xray" "y" 64 | if [[ $? == 0 ]]; then 65 | restart 66 | else 67 | show_menu 68 | fi 69 | } 70 | 71 | before_show_menu() { 72 | echo && echo -n -e "${yellow}Press enter to return to the main menu: ${plain}" && read temp 73 | show_menu 74 | } 75 | 76 | install() { 77 | bash <(curl -Ls https://gh-proxy.com/https://raw.githubusercontent.com/GH6324/3xui-cn/main/install.sh) 78 | if [[ $? == 0 ]]; then 79 | if [[ $# == 0 ]]; then 80 | start 81 | else 82 | start 0 83 | fi 84 | fi 85 | } 86 | 87 | update() { 88 | confirm "This function will forcefully reinstall the latest version, and the data will not be lost. Do you want to continue?" "y" 89 | if [[ $? != 0 ]]; then 90 | LOGE "Cancelled" 91 | if [[ $# == 0 ]]; then 92 | before_show_menu 93 | fi 94 | return 0 95 | fi 96 | bash <(curl -Ls https://gh-proxy.com/https://raw.githubusercontent.com/GH6324/3xui-cn/main/install.sh) 97 | if [[ $? == 0 ]]; then 98 | LOGI "Update is complete, Panel has automatically restarted " 99 | before_show_menu 100 | fi 101 | } 102 | 103 | update_menu() { 104 | echo -e "${yellow}Updating Menu${plain}" 105 | confirm "This function will update the menu to the latest changes." "y" 106 | if [[ $? != 0 ]]; then 107 | LOGE "Cancelled" 108 | if [[ $# == 0 ]]; then 109 | before_show_menu 110 | fi 111 | return 0 112 | fi 113 | 114 | wget -O /usr/bin/x-ui https://gh-proxy.com/https://raw.githubusercontent.com/GH6324/3xui-cn/main/x-ui.sh 115 | chmod +x /usr/local/x-ui/x-ui.sh 116 | chmod +x /usr/bin/x-ui 117 | 118 | if [[ $? == 0 ]]; then 119 | echo -e "${green}Update successful. The panel has automatically restarted.${plain}" 120 | exit 0 121 | else 122 | echo -e "${red}Failed to update the menu.${plain}" 123 | return 1 124 | fi 125 | } 126 | 127 | legacy_version() { 128 | echo "Enter the panel version (like 2.4.0):" 129 | read tag_version 130 | 131 | if [ -z "$tag_version" ]; then 132 | echo "Panel version cannot be empty. Exiting." 133 | exit 1 134 | fi 135 | # Use the entered panel version in the download link 136 | install_command="bash <(curl -Ls "https://gh-proxy.com/https://raw.githubusercontent.com/GH6324/3xui-cn/v$tag_version/install.sh") v$tag_version" 137 | 138 | echo "Downloading and installing panel version $tag_version..." 139 | eval $install_command 140 | } 141 | 142 | # Function to handle the deletion of the script file 143 | delete_script() { 144 | rm "$0" # Remove the script file itself 145 | exit 1 146 | } 147 | 148 | uninstall() { 149 | confirm "Are you sure you want to uninstall the panel? xray will also uninstalled!" "n" 150 | if [[ $? != 0 ]]; then 151 | if [[ $# == 0 ]]; then 152 | show_menu 153 | fi 154 | return 0 155 | fi 156 | systemctl stop x-ui 157 | systemctl disable x-ui 158 | rm /etc/systemd/system/x-ui.service -f 159 | systemctl daemon-reload 160 | systemctl reset-failed 161 | rm /etc/x-ui/ -rf 162 | rm /usr/local/x-ui/ -rf 163 | 164 | echo "" 165 | echo -e "Uninstalled Successfully.\n" 166 | echo "If you need to install this panel again, you can use below command:" 167 | echo -e "${green}bash <(curl -Ls https://gh-proxy.com/https://raw.githubusercontent.com/GH6324/3xui-cn/master/install.sh)${plain}" 168 | echo "" 169 | # Trap the SIGTERM signal 170 | trap delete_script SIGTERM 171 | delete_script 172 | } 173 | 174 | reset_user() { 175 | confirm "Are you sure to reset the username and password of the panel?" "n" 176 | if [[ $? != 0 ]]; then 177 | if [[ $# == 0 ]]; then 178 | show_menu 179 | fi 180 | return 0 181 | fi 182 | read -rp "Please set the login username [default is a random username]: " config_account 183 | [[ -z $config_account ]] && config_account=$(date +%s%N | md5sum | cut -c 1-8) 184 | read -rp "Please set the login password [default is a random password]: " config_password 185 | [[ -z $config_password ]] && config_password=$(date +%s%N | md5sum | cut -c 1-8) 186 | /usr/local/x-ui/x-ui setting -username ${config_account} -password ${config_password} >/dev/null 2>&1 187 | /usr/local/x-ui/x-ui setting -remove_secret >/dev/null 2>&1 188 | echo -e "Panel login username has been reset to: ${green} ${config_account} ${plain}" 189 | echo -e "Panel login password has been reset to: ${green} ${config_password} ${plain}" 190 | echo -e "${yellow} Panel login secret token disabled ${plain}" 191 | echo -e "${green} Please use the new login username and password to access the X-UI panel. Also remember them! ${plain}" 192 | confirm_restart 193 | } 194 | 195 | gen_random_string() { 196 | local length="$1" 197 | local random_string=$(LC_ALL=C tr -dc 'a-zA-Z0-9' /dev/null 2>&1 214 | 215 | echo -e "Web base path has been reset to: ${green}${config_webBasePath}${plain}" 216 | echo -e "${green}Please use the new web base path to access the panel.${plain}" 217 | restart 218 | } 219 | 220 | reset_config() { 221 | confirm "Are you sure you want to reset all panel settings, Account data will not be lost, Username and password will not change" "n" 222 | if [[ $? != 0 ]]; then 223 | if [[ $# == 0 ]]; then 224 | show_menu 225 | fi 226 | return 0 227 | fi 228 | /usr/local/x-ui/x-ui setting -reset 229 | echo -e "All panel settings have been reset to default." 230 | restart 231 | } 232 | 233 | check_config() { 234 | local info=$(/usr/local/x-ui/x-ui setting -show true) 235 | if [[ $? != 0 ]]; then 236 | LOGE "get current settings error, please check logs" 237 | show_menu 238 | return 239 | fi 240 | LOGI "${info}" 241 | 242 | local existing_webBasePath=$(echo "$info" | grep -Eo 'webBasePath: .+' | awk '{print $2}') 243 | local existing_port=$(echo "$info" | grep -Eo 'port: .+' | awk '{print $2}') 244 | local existing_cert=$(/usr/local/x-ui/x-ui setting -getCert true | grep -Eo 'cert: .+' | awk '{print $2}') 245 | local server_ip=$(curl -s https://api.ipify.org) 246 | 247 | if [[ -n "$existing_cert" ]]; then 248 | local domain=$(basename "$(dirname "$existing_cert")") 249 | 250 | if [[ "$domain" =~ ^[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]; then 251 | echo -e "${green}Access URL: https://${domain}:${existing_port}${existing_webBasePath}${plain}" 252 | else 253 | echo -e "${green}Access URL: https://${server_ip}:${existing_port}${existing_webBasePath}${plain}" 254 | fi 255 | else 256 | echo -e "${green}Access URL: http://${server_ip}:${existing_port}${existing_webBasePath}${plain}" 257 | fi 258 | } 259 | 260 | set_port() { 261 | echo && echo -n -e "Enter port number[1-65535]: " && read port 262 | if [[ -z "${port}" ]]; then 263 | LOGD "Cancelled" 264 | before_show_menu 265 | else 266 | /usr/local/x-ui/x-ui setting -port ${port} 267 | echo -e "The port is set, Please restart the panel now, and use the new port ${green}${port}${plain} to access web panel" 268 | confirm_restart 269 | fi 270 | } 271 | 272 | start() { 273 | check_status 274 | if [[ $? == 0 ]]; then 275 | echo "" 276 | LOGI "Panel is running, No need to start again, If you need to restart, please select restart" 277 | else 278 | systemctl start x-ui 279 | sleep 2 280 | check_status 281 | if [[ $? == 0 ]]; then 282 | LOGI "x-ui Started Successfully" 283 | else 284 | LOGE "panel Failed to start, Probably because it takes longer than two seconds to start, Please check the log information later" 285 | fi 286 | fi 287 | 288 | if [[ $# == 0 ]]; then 289 | before_show_menu 290 | fi 291 | } 292 | 293 | stop() { 294 | check_status 295 | if [[ $? == 1 ]]; then 296 | echo "" 297 | LOGI "Panel stopped, No need to stop again!" 298 | else 299 | systemctl stop x-ui 300 | sleep 2 301 | check_status 302 | if [[ $? == 1 ]]; then 303 | LOGI "x-ui and xray stopped successfully" 304 | else 305 | LOGE "Panel stop failed, Probably because the stop time exceeds two seconds, Please check the log information later" 306 | fi 307 | fi 308 | 309 | if [[ $# == 0 ]]; then 310 | before_show_menu 311 | fi 312 | } 313 | 314 | restart() { 315 | systemctl restart x-ui 316 | sleep 2 317 | check_status 318 | if [[ $? == 0 ]]; then 319 | LOGI "x-ui and xray Restarted successfully" 320 | else 321 | LOGE "Panel restart failed, Probably because it takes longer than two seconds to start, Please check the log information later" 322 | fi 323 | if [[ $# == 0 ]]; then 324 | before_show_menu 325 | fi 326 | } 327 | 328 | status() { 329 | systemctl status x-ui -l 330 | if [[ $# == 0 ]]; then 331 | before_show_menu 332 | fi 333 | } 334 | 335 | enable() { 336 | systemctl enable x-ui 337 | if [[ $? == 0 ]]; then 338 | LOGI "x-ui Set to boot automatically on startup successfully" 339 | else 340 | LOGE "x-ui Failed to set Autostart" 341 | fi 342 | 343 | if [[ $# == 0 ]]; then 344 | before_show_menu 345 | fi 346 | } 347 | 348 | disable() { 349 | systemctl disable x-ui 350 | if [[ $? == 0 ]]; then 351 | LOGI "x-ui Autostart Cancelled successfully" 352 | else 353 | LOGE "x-ui Failed to cancel autostart" 354 | fi 355 | 356 | if [[ $# == 0 ]]; then 357 | before_show_menu 358 | fi 359 | } 360 | 361 | show_log() { 362 | echo -e "${green}\t1.${plain} Debug Log" 363 | echo -e "${green}\t2.${plain} Clear All logs" 364 | echo -e "${green}\t0.${plain} Back to Main Menu" 365 | read -rp "Choose an option: " choice 366 | 367 | case "$choice" in 368 | 0) 369 | show_menu 370 | ;; 371 | 1) 372 | journalctl -u x-ui -e --no-pager -f -p debug 373 | if [[ $# == 0 ]]; then 374 | before_show_menu 375 | fi 376 | ;; 377 | 2) 378 | sudo journalctl --rotate 379 | sudo journalctl --vacuum-time=1s 380 | echo "All Logs cleared." 381 | restart 382 | ;; 383 | *) 384 | echo -e "${red}Invalid option. Please select a valid number.${plain}\n" 385 | show_log 386 | ;; 387 | esac 388 | } 389 | 390 | show_banlog() { 391 | local system_log="/var/log/fail2ban.log" 392 | 393 | echo -e "${green}Checking ban logs...${plain}\n" 394 | 395 | if ! systemctl is-active --quiet fail2ban; then 396 | echo -e "${red}Fail2ban service is not running!${plain}\n" 397 | return 1 398 | fi 399 | 400 | if [[ -f "$system_log" ]]; then 401 | echo -e "${green}Recent system ban activities from fail2ban.log:${plain}" 402 | grep "3x-ipl" "$system_log" | grep -E "Ban|Unban" | tail -n 10 || echo -e "${yellow}No recent system ban activities found${plain}" 403 | echo "" 404 | fi 405 | 406 | if [[ -f "${iplimit_banned_log_path}" ]]; then 407 | echo -e "${green}3X-IPL ban log entries:${plain}" 408 | if [[ -s "${iplimit_banned_log_path}" ]]; then 409 | grep -v "INIT" "${iplimit_banned_log_path}" | tail -n 10 || echo -e "${yellow}No ban entries found${plain}" 410 | else 411 | echo -e "${yellow}Ban log file is empty${plain}" 412 | fi 413 | else 414 | echo -e "${red}Ban log file not found at: ${iplimit_banned_log_path}${plain}" 415 | fi 416 | 417 | echo -e "\n${green}Current jail status:${plain}" 418 | fail2ban-client status 3x-ipl || echo -e "${yellow}Unable to get jail status${plain}" 419 | } 420 | 421 | bbr_menu() { 422 | echo -e "${green}\t1.${plain} Enable BBR" 423 | echo -e "${green}\t2.${plain} Disable BBR" 424 | echo -e "${green}\t0.${plain} Back to Main Menu" 425 | read -rp "Choose an option: " choice 426 | case "$choice" in 427 | 0) 428 | show_menu 429 | ;; 430 | 1) 431 | enable_bbr 432 | bbr_menu 433 | ;; 434 | 2) 435 | disable_bbr 436 | bbr_menu 437 | ;; 438 | *) 439 | echo -e "${red}Invalid option. Please select a valid number.${plain}\n" 440 | bbr_menu 441 | ;; 442 | esac 443 | } 444 | 445 | disable_bbr() { 446 | 447 | if ! grep -q "net.core.default_qdisc=fq" /etc/sysctl.conf || ! grep -q "net.ipv4.tcp_congestion_control=bbr" /etc/sysctl.conf; then 448 | echo -e "${yellow}BBR is not currently enabled.${plain}" 449 | before_show_menu 450 | fi 451 | 452 | # Replace BBR with CUBIC configurations 453 | sed -i 's/net.core.default_qdisc=fq/net.core.default_qdisc=pfifo_fast/' /etc/sysctl.conf 454 | sed -i 's/net.ipv4.tcp_congestion_control=bbr/net.ipv4.tcp_congestion_control=cubic/' /etc/sysctl.conf 455 | 456 | # Apply changes 457 | sysctl -p 458 | 459 | # Verify that BBR is replaced with CUBIC 460 | if [[ $(sysctl net.ipv4.tcp_congestion_control | awk '{print $3}') == "cubic" ]]; then 461 | echo -e "${green}BBR has been replaced with CUBIC successfully.${plain}" 462 | else 463 | echo -e "${red}Failed to replace BBR with CUBIC. Please check your system configuration.${plain}" 464 | fi 465 | } 466 | 467 | enable_bbr() { 468 | if grep -q "net.core.default_qdisc=fq" /etc/sysctl.conf && grep -q "net.ipv4.tcp_congestion_control=bbr" /etc/sysctl.conf; then 469 | echo -e "${green}BBR is already enabled!${plain}" 470 | before_show_menu 471 | fi 472 | 473 | # Check the OS and install necessary packages 474 | case "${release}" in 475 | ubuntu | debian | armbian) 476 | apt-get update && apt-get install -yqq --no-install-recommends ca-certificates 477 | ;; 478 | centos | almalinux | rocky | ol) 479 | yum -y update && yum -y install ca-certificates 480 | ;; 481 | fedora | amzn | virtuozzo) 482 | dnf -y update && dnf -y install ca-certificates 483 | ;; 484 | arch | manjaro | parch) 485 | pacman -Sy --noconfirm ca-certificates 486 | ;; 487 | *) 488 | echo -e "${red}Unsupported operating system. Please check the script and install the necessary packages manually.${plain}\n" 489 | exit 1 490 | ;; 491 | esac 492 | 493 | # Enable BBR 494 | echo "net.core.default_qdisc=fq" | tee -a /etc/sysctl.conf 495 | echo "net.ipv4.tcp_congestion_control=bbr" | tee -a /etc/sysctl.conf 496 | 497 | # Apply changes 498 | sysctl -p 499 | 500 | # Verify that BBR is enabled 501 | if [[ $(sysctl net.ipv4.tcp_congestion_control | awk '{print $3}') == "bbr" ]]; then 502 | echo -e "${green}BBR has been enabled successfully.${plain}" 503 | else 504 | echo -e "${red}Failed to enable BBR. Please check your system configuration.${plain}" 505 | fi 506 | } 507 | 508 | update_shell() { 509 | wget -O /usr/bin/x-ui -N https://gh-proxy.com/https://github.com/GH6324/3xui-cn/raw/main/x-ui.sh 510 | if [[ $? != 0 ]]; then 511 | echo "" 512 | LOGE "Failed to download script, Please check whether the machine can connect Github" 513 | before_show_menu 514 | else 515 | chmod +x /usr/bin/x-ui 516 | LOGI "Upgrade script succeeded, Please rerun the script" 517 | before_show_menu 518 | fi 519 | } 520 | 521 | # 0: running, 1: not running, 2: not installed 522 | check_status() { 523 | if [[ ! -f /etc/systemd/system/x-ui.service ]]; then 524 | return 2 525 | fi 526 | temp=$(systemctl status x-ui | grep Active | awk '{print $3}' | cut -d "(" -f2 | cut -d ")" -f1) 527 | if [[ "${temp}" == "running" ]]; then 528 | return 0 529 | else 530 | return 1 531 | fi 532 | } 533 | 534 | check_enabled() { 535 | temp=$(systemctl is-enabled x-ui) 536 | if [[ "${temp}" == "enabled" ]]; then 537 | return 0 538 | else 539 | return 1 540 | fi 541 | } 542 | 543 | check_uninstall() { 544 | check_status 545 | if [[ $? != 2 ]]; then 546 | echo "" 547 | LOGE "Panel installed, Please do not reinstall" 548 | if [[ $# == 0 ]]; then 549 | before_show_menu 550 | fi 551 | return 1 552 | else 553 | return 0 554 | fi 555 | } 556 | 557 | check_install() { 558 | check_status 559 | if [[ $? == 2 ]]; then 560 | echo "" 561 | LOGE "Please install the panel first" 562 | if [[ $# == 0 ]]; then 563 | before_show_menu 564 | fi 565 | return 1 566 | else 567 | return 0 568 | fi 569 | } 570 | 571 | show_status() { 572 | check_status 573 | case $? in 574 | 0) 575 | echo -e "Panel state: ${green}Running${plain}" 576 | show_enable_status 577 | ;; 578 | 1) 579 | echo -e "Panel state: ${yellow}Not Running${plain}" 580 | show_enable_status 581 | ;; 582 | 2) 583 | echo -e "Panel state: ${red}Not Installed${plain}" 584 | ;; 585 | esac 586 | show_xray_status 587 | } 588 | 589 | show_enable_status() { 590 | check_enabled 591 | if [[ $? == 0 ]]; then 592 | echo -e "Start automatically: ${green}Yes${plain}" 593 | else 594 | echo -e "Start automatically: ${red}No${plain}" 595 | fi 596 | } 597 | 598 | check_xray_status() { 599 | count=$(ps -ef | grep "xray-linux" | grep -v "grep" | wc -l) 600 | if [[ count -ne 0 ]]; then 601 | return 0 602 | else 603 | return 1 604 | fi 605 | } 606 | 607 | show_xray_status() { 608 | check_xray_status 609 | if [[ $? == 0 ]]; then 610 | echo -e "xray state: ${green}Running${plain}" 611 | else 612 | echo -e "xray state: ${red}Not Running${plain}" 613 | fi 614 | } 615 | 616 | firewall_menu() { 617 | echo -e "${green}\t1.${plain} ${green}Install${plain} Firewall" 618 | echo -e "${green}\t2.${plain} Port List [numbered]" 619 | echo -e "${green}\t3.${plain} ${green}Open${plain} Ports" 620 | echo -e "${green}\t4.${plain} ${red}Delete${plain} Ports from List" 621 | echo -e "${green}\t5.${plain} ${green}Enable${plain} Firewall" 622 | echo -e "${green}\t6.${plain} ${red}Disable${plain} Firewall" 623 | echo -e "${green}\t7.${plain} Firewall Status" 624 | echo -e "${green}\t0.${plain} Back to Main Menu" 625 | read -rp "Choose an option: " choice 626 | case "$choice" in 627 | 0) 628 | show_menu 629 | ;; 630 | 1) 631 | install_firewall 632 | firewall_menu 633 | ;; 634 | 2) 635 | ufw status numbered 636 | firewall_menu 637 | ;; 638 | 3) 639 | open_ports 640 | firewall_menu 641 | ;; 642 | 4) 643 | delete_ports 644 | firewall_menu 645 | ;; 646 | 5) 647 | ufw enable 648 | firewall_menu 649 | ;; 650 | 6) 651 | ufw disable 652 | firewall_menu 653 | ;; 654 | 7) 655 | ufw status verbose 656 | firewall_menu 657 | ;; 658 | *) 659 | echo -e "${red}Invalid option. Please select a valid number.${plain}\n" 660 | firewall_menu 661 | ;; 662 | esac 663 | } 664 | 665 | install_firewall() { 666 | if ! command -v ufw &>/dev/null; then 667 | echo "ufw firewall is not installed. Installing now..." 668 | apt-get update 669 | apt-get install -y ufw 670 | else 671 | echo "ufw firewall is already installed" 672 | fi 673 | 674 | # Check if the firewall is inactive 675 | if ufw status | grep -q "Status: active"; then 676 | echo "Firewall is already active" 677 | else 678 | echo "Activating firewall..." 679 | # Open the necessary ports 680 | ufw allow ssh 681 | ufw allow http 682 | ufw allow https 683 | ufw allow 2053/tcp #webPort 684 | ufw allow 2096/tcp #subport 685 | 686 | # Enable the firewall 687 | ufw --force enable 688 | fi 689 | } 690 | 691 | open_ports() { 692 | # Prompt the user to enter the ports they want to open 693 | read -rp "Enter the ports you want to open (e.g. 80,443,2053 or range 400-500): " ports 694 | 695 | # Check if the input is valid 696 | if ! [[ $ports =~ ^([0-9]+|[0-9]+-[0-9]+)(,([0-9]+|[0-9]+-[0-9]+))*$ ]]; then 697 | echo "Error: Invalid input. Please enter a comma-separated list of ports or a range of ports (e.g. 80,443,2053 or 400-500)." >&2 698 | exit 1 699 | fi 700 | 701 | # Open the specified ports using ufw 702 | IFS=',' read -ra PORT_LIST <<<"$ports" 703 | for port in "${PORT_LIST[@]}"; do 704 | if [[ $port == *-* ]]; then 705 | # Split the range into start and end ports 706 | start_port=$(echo $port | cut -d'-' -f1) 707 | end_port=$(echo $port | cut -d'-' -f2) 708 | # Open the port range 709 | ufw allow $start_port:$end_port/tcp 710 | ufw allow $start_port:$end_port/udp 711 | else 712 | # Open the single port 713 | ufw allow "$port" 714 | fi 715 | done 716 | 717 | # Confirm that the ports are opened 718 | echo "Opened the specified ports:" 719 | for port in "${PORT_LIST[@]}"; do 720 | if [[ $port == *-* ]]; then 721 | start_port=$(echo $port | cut -d'-' -f1) 722 | end_port=$(echo $port | cut -d'-' -f2) 723 | # Check if the port range has been successfully opened 724 | (ufw status | grep -q "$start_port:$end_port") && echo "$start_port-$end_port" 725 | else 726 | # Check if the individual port has been successfully opened 727 | (ufw status | grep -q "$port") && echo "$port" 728 | fi 729 | done 730 | } 731 | 732 | delete_ports() { 733 | # Display current rules with numbers 734 | echo "Current UFW rules:" 735 | ufw status numbered 736 | 737 | # Ask the user how they want to delete rules 738 | echo "Do you want to delete rules by:" 739 | echo "1) Rule numbers" 740 | echo "2) Ports" 741 | read -rp "Enter your choice (1 or 2): " choice 742 | 743 | if [[ $choice -eq 1 ]]; then 744 | # Deleting by rule numbers 745 | read -rp "Enter the rule numbers you want to delete (1, 2, etc.): " rule_numbers 746 | 747 | # Validate the input 748 | if ! [[ $rule_numbers =~ ^([0-9]+)(,[0-9]+)*$ ]]; then 749 | echo "Error: Invalid input. Please enter a comma-separated list of rule numbers." >&2 750 | exit 1 751 | fi 752 | 753 | # Split numbers into an array 754 | IFS=',' read -ra RULE_NUMBERS <<<"$rule_numbers" 755 | for rule_number in "${RULE_NUMBERS[@]}"; do 756 | # Delete the rule by number 757 | ufw delete "$rule_number" || echo "Failed to delete rule number $rule_number" 758 | done 759 | 760 | echo "Selected rules have been deleted." 761 | 762 | elif [[ $choice -eq 2 ]]; then 763 | # Deleting by ports 764 | read -rp "Enter the ports you want to delete (e.g. 80,443,2053 or range 400-500): " ports 765 | 766 | # Validate the input 767 | if ! [[ $ports =~ ^([0-9]+|[0-9]+-[0-9]+)(,([0-9]+|[0-9]+-[0-9]+))*$ ]]; then 768 | echo "Error: Invalid input. Please enter a comma-separated list of ports or a range of ports (e.g. 80,443,2053 or 400-500)." >&2 769 | exit 1 770 | fi 771 | 772 | # Split ports into an array 773 | IFS=',' read -ra PORT_LIST <<<"$ports" 774 | for port in "${PORT_LIST[@]}"; do 775 | if [[ $port == *-* ]]; then 776 | # Split the port range 777 | start_port=$(echo $port | cut -d'-' -f1) 778 | end_port=$(echo $port | cut -d'-' -f2) 779 | # Delete the port range 780 | ufw delete allow $start_port:$end_port/tcp 781 | ufw delete allow $start_port:$end_port/udp 782 | else 783 | # Delete a single port 784 | ufw delete allow "$port" 785 | fi 786 | done 787 | 788 | # Confirmation of deletion 789 | echo "Deleted the specified ports:" 790 | for port in "${PORT_LIST[@]}"; do 791 | if [[ $port == *-* ]]; then 792 | start_port=$(echo $port | cut -d'-' -f1) 793 | end_port=$(echo $port | cut -d'-' -f2) 794 | # Check if the port range has been deleted 795 | (ufw status | grep -q "$start_port:$end_port") || echo "$start_port-$end_port" 796 | else 797 | # Check if the individual port has been deleted 798 | (ufw status | grep -q "$port") || echo "$port" 799 | fi 800 | done 801 | else 802 | echo "${red}Error:${plain} Invalid choice. Please enter 1 or 2." >&2 803 | exit 1 804 | fi 805 | } 806 | 807 | update_geo() { 808 | echo -e "${green}\t1.${plain} Loyalsoldier (geoip.dat, geosite.dat)" 809 | echo -e "${green}\t2.${plain} chocolate4u (geoip_IR.dat, geosite_IR.dat)" 810 | echo -e "${green}\t3.${plain} runetfreedom (geoip_RU.dat, geosite_RU.dat)" 811 | echo -e "${green}\t0.${plain} Back to Main Menu" 812 | read -rp "Choose an option: " choice 813 | 814 | cd /usr/local/x-ui/bin 815 | 816 | case "$choice" in 817 | 0) 818 | show_menu 819 | ;; 820 | 1) 821 | systemctl stop x-ui 822 | rm -f geoip.dat geosite.dat 823 | wget -N https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat 824 | wget -N https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat 825 | echo -e "${green}Loyalsoldier datasets have been updated successfully!${plain}" 826 | restart 827 | ;; 828 | 2) 829 | systemctl stop x-ui 830 | rm -f geoip_IR.dat geosite_IR.dat 831 | wget -O geoip_IR.dat -N https://github.com/chocolate4u/Iran-v2ray-rules/releases/latest/download/geoip.dat 832 | wget -O geosite_IR.dat -N https://github.com/chocolate4u/Iran-v2ray-rules/releases/latest/download/geosite.dat 833 | echo -e "${green}chocolate4u datasets have been updated successfully!${plain}" 834 | restart 835 | ;; 836 | 3) 837 | systemctl stop x-ui 838 | rm -f geoip_RU.dat geosite_RU.dat 839 | wget -O geoip_RU.dat -N https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/geoip.dat 840 | wget -O geosite_RU.dat -N https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/geosite.dat 841 | echo -e "${green}runetfreedom datasets have been updated successfully!${plain}" 842 | restart 843 | ;; 844 | *) 845 | echo -e "${red}Invalid option. Please select a valid number.${plain}\n" 846 | update_geo 847 | ;; 848 | esac 849 | 850 | before_show_menu 851 | } 852 | 853 | install_acme() { 854 | # Check if acme.sh is already installed 855 | if command -v ~/.acme.sh/acme.sh &>/dev/null; then 856 | LOGI "acme.sh is already installed." 857 | return 0 858 | fi 859 | 860 | LOGI "Installing acme.sh..." 861 | cd ~ || return 1 # Ensure you can change to the home directory 862 | 863 | curl -s https://get.acme.sh | sh 864 | if [ $? -ne 0 ]; then 865 | LOGE "Installation of acme.sh failed." 866 | return 1 867 | else 868 | LOGI "Installation of acme.sh succeeded." 869 | fi 870 | 871 | return 0 872 | } 873 | 874 | ssl_cert_issue_main() { 875 | echo -e "${green}\t1.${plain} Get SSL" 876 | echo -e "${green}\t2.${plain} Revoke" 877 | echo -e "${green}\t3.${plain} Force Renew" 878 | echo -e "${green}\t4.${plain} Show Existing Domains" 879 | echo -e "${green}\t5.${plain} Set Cert paths for the panel" 880 | echo -e "${green}\t0.${plain} Back to Main Menu" 881 | 882 | read -rp "Choose an option: " choice 883 | case "$choice" in 884 | 0) 885 | show_menu 886 | ;; 887 | 1) 888 | ssl_cert_issue 889 | ssl_cert_issue_main 890 | ;; 891 | 2) 892 | local domains=$(find /root/cert/ -mindepth 1 -maxdepth 1 -type d -exec basename {} \;) 893 | if [ -z "$domains" ]; then 894 | echo "No certificates found to revoke." 895 | else 896 | echo "Existing domains:" 897 | echo "$domains" 898 | read -rp "Please enter a domain from the list to revoke the certificate: " domain 899 | if echo "$domains" | grep -qw "$domain"; then 900 | ~/.acme.sh/acme.sh --revoke -d ${domain} 901 | LOGI "Certificate revoked for domain: $domain" 902 | else 903 | echo "Invalid domain entered." 904 | fi 905 | fi 906 | ssl_cert_issue_main 907 | ;; 908 | 3) 909 | local domains=$(find /root/cert/ -mindepth 1 -maxdepth 1 -type d -exec basename {} \;) 910 | if [ -z "$domains" ]; then 911 | echo "No certificates found to renew." 912 | else 913 | echo "Existing domains:" 914 | echo "$domains" 915 | read -rp "Please enter a domain from the list to renew the SSL certificate: " domain 916 | if echo "$domains" | grep -qw "$domain"; then 917 | ~/.acme.sh/acme.sh --renew -d ${domain} --force 918 | LOGI "Certificate forcefully renewed for domain: $domain" 919 | else 920 | echo "Invalid domain entered." 921 | fi 922 | fi 923 | ssl_cert_issue_main 924 | ;; 925 | 4) 926 | local domains=$(find /root/cert/ -mindepth 1 -maxdepth 1 -type d -exec basename {} \;) 927 | if [ -z "$domains" ]; then 928 | echo "No certificates found." 929 | else 930 | echo "Existing domains and their paths:" 931 | for domain in $domains; do 932 | local cert_path="/root/cert/${domain}/fullchain.pem" 933 | local key_path="/root/cert/${domain}/privkey.pem" 934 | if [[ -f "${cert_path}" && -f "${key_path}" ]]; then 935 | echo -e "Domain: ${domain}" 936 | echo -e "\tCertificate Path: ${cert_path}" 937 | echo -e "\tPrivate Key Path: ${key_path}" 938 | else 939 | echo -e "Domain: ${domain} - Certificate or Key missing." 940 | fi 941 | done 942 | fi 943 | ssl_cert_issue_main 944 | ;; 945 | 5) 946 | local domains=$(find /root/cert/ -mindepth 1 -maxdepth 1 -type d -exec basename {} \;) 947 | if [ -z "$domains" ]; then 948 | echo "No certificates found." 949 | else 950 | echo "Available domains:" 951 | echo "$domains" 952 | read -rp "Please choose a domain to set the panel paths: " domain 953 | 954 | if echo "$domains" | grep -qw "$domain"; then 955 | local webCertFile="/root/cert/${domain}/fullchain.pem" 956 | local webKeyFile="/root/cert/${domain}/privkey.pem" 957 | 958 | if [[ -f "${webCertFile}" && -f "${webKeyFile}" ]]; then 959 | /usr/local/x-ui/x-ui cert -webCert "$webCertFile" -webCertKey "$webKeyFile" 960 | echo "Panel paths set for domain: $domain" 961 | echo " - Certificate File: $webCertFile" 962 | echo " - Private Key File: $webKeyFile" 963 | restart 964 | else 965 | echo "Certificate or private key not found for domain: $domain." 966 | fi 967 | else 968 | echo "Invalid domain entered." 969 | fi 970 | fi 971 | ssl_cert_issue_main 972 | ;; 973 | 974 | *) 975 | echo -e "${red}Invalid option. Please select a valid number.${plain}\n" 976 | ssl_cert_issue_main 977 | ;; 978 | esac 979 | } 980 | 981 | ssl_cert_issue() { 982 | local existing_webBasePath=$(/usr/local/x-ui/x-ui setting -show true | grep -Eo 'webBasePath: .+' | awk '{print $2}') 983 | local existing_port=$(/usr/local/x-ui/x-ui setting -show true | grep -Eo 'port: .+' | awk '{print $2}') 984 | # check for acme.sh first 985 | if ! command -v ~/.acme.sh/acme.sh &>/dev/null; then 986 | echo "acme.sh could not be found. we will install it" 987 | install_acme 988 | if [ $? -ne 0 ]; then 989 | LOGE "install acme failed, please check logs" 990 | exit 1 991 | fi 992 | fi 993 | 994 | # install socat second 995 | case "${release}" in 996 | ubuntu | debian | armbian) 997 | apt update && apt install socat -y 998 | ;; 999 | centos | almalinux | rocky | ol) 1000 | yum -y update && yum -y install socat 1001 | ;; 1002 | fedora | amzn | virtuozzo) 1003 | dnf -y update && dnf -y install socat 1004 | ;; 1005 | arch | manjaro | parch) 1006 | pacman -Sy --noconfirm socat 1007 | ;; 1008 | *) 1009 | echo -e "${red}Unsupported operating system. Please check the script and install the necessary packages manually.${plain}\n" 1010 | exit 1 1011 | ;; 1012 | esac 1013 | if [ $? -ne 0 ]; then 1014 | LOGE "install socat failed, please check logs" 1015 | exit 1 1016 | else 1017 | LOGI "install socat succeed..." 1018 | fi 1019 | 1020 | # get the domain here, and we need to verify it 1021 | local domain="" 1022 | read -rp "Please enter your domain name: " domain 1023 | LOGD "Your domain is: ${domain}, checking it..." 1024 | 1025 | # check if there already exists a certificate 1026 | local currentCert=$(~/.acme.sh/acme.sh --list | tail -1 | awk '{print $1}') 1027 | if [ "${currentCert}" == "${domain}" ]; then 1028 | local certInfo=$(~/.acme.sh/acme.sh --list) 1029 | LOGE "System already has certificates for this domain. Cannot issue again. Current certificate details:" 1030 | LOGI "$certInfo" 1031 | exit 1 1032 | else 1033 | LOGI "Your domain is ready for issuing certificates now..." 1034 | fi 1035 | 1036 | # create a directory for the certificate 1037 | certPath="/root/cert/${domain}" 1038 | if [ ! -d "$certPath" ]; then 1039 | mkdir -p "$certPath" 1040 | else 1041 | rm -rf "$certPath" 1042 | mkdir -p "$certPath" 1043 | fi 1044 | 1045 | # get the port number for the standalone server 1046 | local WebPort=80 1047 | read -rp "Please choose which port to use (default is 80): " WebPort 1048 | if [[ ${WebPort} -gt 65535 || ${WebPort} -lt 1 ]]; then 1049 | LOGE "Your input ${WebPort} is invalid, will use default port 80." 1050 | WebPort=80 1051 | fi 1052 | LOGI "Will use port: ${WebPort} to issue certificates. Please make sure this port is open." 1053 | 1054 | # issue the certificate 1055 | ~/.acme.sh/acme.sh --set-default-ca --server letsencrypt 1056 | ~/.acme.sh/acme.sh --issue -d ${domain} --listen-v6 --standalone --httpport ${WebPort} --force 1057 | if [ $? -ne 0 ]; then 1058 | LOGE "Issuing certificate failed, please check logs." 1059 | rm -rf ~/.acme.sh/${domain} 1060 | exit 1 1061 | else 1062 | LOGE "Issuing certificate succeeded, installing certificates..." 1063 | fi 1064 | 1065 | reloadCmd="x-ui restart" 1066 | 1067 | LOGI "Default --reloadcmd for ACME is: ${yellow}x-ui restart" 1068 | LOGI "This command will run on every certificate issue and renew." 1069 | read -rp "Would you like to modify --reloadcmd for ACME? (y/n): " setReloadcmd 1070 | if [[ "$setReloadcmd" == "y" || "$setReloadcmd" == "Y" ]]; then 1071 | echo -e "\n${green}\t1.${plain} Preset: systemctl reload nginx ; x-ui restart" 1072 | echo -e "${green}\t2.${plain} Input your own command" 1073 | echo -e "${green}\t0.${plain} Keep default reloadcmd" 1074 | read -rp "Choose an option: " choice 1075 | case "$choice" in 1076 | 1) 1077 | LOGI "Reloadcmd is: systemctl reload nginx ; x-ui restart" 1078 | reloadCmd="systemctl reload nginx ; x-ui restart" 1079 | ;; 1080 | 2) 1081 | LOGD "It's recommended to put x-ui restart at the end, so it won't raise an error if other services fails" 1082 | read -rp "Please enter your reloadcmd (example: systemctl reload nginx ; x-ui restart): " reloadCmd 1083 | LOGI "Your reloadcmd is: ${reloadCmd}" 1084 | ;; 1085 | *) 1086 | LOGI "Keep default reloadcmd" 1087 | ;; 1088 | esac 1089 | fi 1090 | 1091 | # install the certificate 1092 | ~/.acme.sh/acme.sh --installcert -d ${domain} \ 1093 | --key-file /root/cert/${domain}/privkey.pem \ 1094 | --fullchain-file /root/cert/${domain}/fullchain.pem --reloadcmd "${reloadCmd}" 1095 | 1096 | if [ $? -ne 0 ]; then 1097 | LOGE "Installing certificate failed, exiting." 1098 | rm -rf ~/.acme.sh/${domain} 1099 | exit 1 1100 | else 1101 | LOGI "Installing certificate succeeded, enabling auto renew..." 1102 | fi 1103 | 1104 | # enable auto-renew 1105 | ~/.acme.sh/acme.sh --upgrade --auto-upgrade 1106 | if [ $? -ne 0 ]; then 1107 | LOGE "Auto renew failed, certificate details:" 1108 | ls -lah cert/* 1109 | chmod 755 $certPath/* 1110 | exit 1 1111 | else 1112 | LOGI "Auto renew succeeded, certificate details:" 1113 | ls -lah cert/* 1114 | chmod 755 $certPath/* 1115 | fi 1116 | 1117 | # Prompt user to set panel paths after successful certificate installation 1118 | read -rp "Would you like to set this certificate for the panel? (y/n): " setPanel 1119 | if [[ "$setPanel" == "y" || "$setPanel" == "Y" ]]; then 1120 | local webCertFile="/root/cert/${domain}/fullchain.pem" 1121 | local webKeyFile="/root/cert/${domain}/privkey.pem" 1122 | 1123 | if [[ -f "$webCertFile" && -f "$webKeyFile" ]]; then 1124 | /usr/local/x-ui/x-ui cert -webCert "$webCertFile" -webCertKey "$webKeyFile" 1125 | LOGI "Panel paths set for domain: $domain" 1126 | LOGI " - Certificate File: $webCertFile" 1127 | LOGI " - Private Key File: $webKeyFile" 1128 | echo -e "${green}Access URL: https://${domain}:${existing_port}${existing_webBasePath}${plain}" 1129 | restart 1130 | else 1131 | LOGE "Error: Certificate or private key file not found for domain: $domain." 1132 | fi 1133 | else 1134 | LOGI "Skipping panel path setting." 1135 | fi 1136 | } 1137 | 1138 | ssl_cert_issue_CF() { 1139 | local existing_webBasePath=$(/usr/local/x-ui/x-ui setting -show true | grep -Eo 'webBasePath: .+' | awk '{print $2}') 1140 | local existing_port=$(/usr/local/x-ui/x-ui setting -show true | grep -Eo 'port: .+' | awk '{print $2}') 1141 | LOGI "****** Instructions for Use ******" 1142 | LOGI "Follow the steps below to complete the process:" 1143 | LOGI "1. Cloudflare Registered E-mail." 1144 | LOGI "2. Cloudflare Global API Key." 1145 | LOGI "3. The Domain Name." 1146 | LOGI "4. Once the certificate is issued, you will be prompted to set the certificate for the panel (optional)." 1147 | LOGI "5. The script also supports automatic renewal of the SSL certificate after installation." 1148 | 1149 | confirm "Do you confirm the information and wish to proceed? [y/n]" "y" 1150 | 1151 | if [ $? -eq 0 ]; then 1152 | # Check for acme.sh first 1153 | if ! command -v ~/.acme.sh/acme.sh &>/dev/null; then 1154 | echo "acme.sh could not be found. We will install it." 1155 | install_acme 1156 | if [ $? -ne 0 ]; then 1157 | LOGE "Install acme failed, please check logs." 1158 | exit 1 1159 | fi 1160 | fi 1161 | 1162 | CF_Domain="" 1163 | 1164 | LOGD "Please set a domain name:" 1165 | read -rp "Input your domain here: " CF_Domain 1166 | LOGD "Your domain name is set to: ${CF_Domain}" 1167 | 1168 | # Set up Cloudflare API details 1169 | CF_GlobalKey="" 1170 | CF_AccountEmail="" 1171 | LOGD "Please set the API key:" 1172 | read -rp "Input your key here: " CF_GlobalKey 1173 | LOGD "Your API key is: ${CF_GlobalKey}" 1174 | 1175 | LOGD "Please set up registered email:" 1176 | read -rp "Input your email here: " CF_AccountEmail 1177 | LOGD "Your registered email address is: ${CF_AccountEmail}" 1178 | 1179 | # Set the default CA to Let's Encrypt 1180 | ~/.acme.sh/acme.sh --set-default-ca --server letsencrypt 1181 | if [ $? -ne 0 ]; then 1182 | LOGE "Default CA, Let'sEncrypt fail, script exiting..." 1183 | exit 1 1184 | fi 1185 | 1186 | export CF_Key="${CF_GlobalKey}" 1187 | export CF_Email="${CF_AccountEmail}" 1188 | 1189 | # Issue the certificate using Cloudflare DNS 1190 | ~/.acme.sh/acme.sh --issue --dns dns_cf -d ${CF_Domain} -d *.${CF_Domain} --log --force 1191 | if [ $? -ne 0 ]; then 1192 | LOGE "Certificate issuance failed, script exiting..." 1193 | exit 1 1194 | else 1195 | LOGI "Certificate issued successfully, Installing..." 1196 | fi 1197 | 1198 | # Install the certificate 1199 | certPath="/root/cert/${CF_Domain}" 1200 | if [ -d "$certPath" ]; then 1201 | rm -rf ${certPath} 1202 | fi 1203 | 1204 | mkdir -p ${certPath} 1205 | if [ $? -ne 0 ]; then 1206 | LOGE "Failed to create directory: ${certPath}" 1207 | exit 1 1208 | fi 1209 | 1210 | reloadCmd="x-ui restart" 1211 | 1212 | LOGI "Default --reloadcmd for ACME is: ${yellow}x-ui restart" 1213 | LOGI "This command will run on every certificate issue and renew." 1214 | read -rp "Would you like to modify --reloadcmd for ACME? (y/n): " setReloadcmd 1215 | if [[ "$setReloadcmd" == "y" || "$setReloadcmd" == "Y" ]]; then 1216 | echo -e "\n${green}\t1.${plain} Preset: systemctl reload nginx ; x-ui restart" 1217 | echo -e "${green}\t2.${plain} Input your own command" 1218 | echo -e "${green}\t0.${plain} Keep default reloadcmd" 1219 | read -rp "Choose an option: " choice 1220 | case "$choice" in 1221 | 1) 1222 | LOGI "Reloadcmd is: systemctl reload nginx ; x-ui restart" 1223 | reloadCmd="systemctl reload nginx ; x-ui restart" 1224 | ;; 1225 | 2) 1226 | LOGD "It's recommended to put x-ui restart at the end, so it won't raise an error if other services fails" 1227 | read -rp "Please enter your reloadcmd (example: systemctl reload nginx ; x-ui restart): " reloadCmd 1228 | LOGI "Your reloadcmd is: ${reloadCmd}" 1229 | ;; 1230 | *) 1231 | LOGI "Keep default reloadcmd" 1232 | ;; 1233 | esac 1234 | fi 1235 | ~/.acme.sh/acme.sh --installcert -d ${CF_Domain} -d *.${CF_Domain} \ 1236 | --key-file ${certPath}/privkey.pem \ 1237 | --fullchain-file ${certPath}/fullchain.pem --reloadcmd "${reloadCmd}" 1238 | 1239 | if [ $? -ne 0 ]; then 1240 | LOGE "Certificate installation failed, script exiting..." 1241 | exit 1 1242 | else 1243 | LOGI "Certificate installed successfully, Turning on automatic updates..." 1244 | fi 1245 | 1246 | # Enable auto-update 1247 | ~/.acme.sh/acme.sh --upgrade --auto-upgrade 1248 | if [ $? -ne 0 ]; then 1249 | LOGE "Auto update setup failed, script exiting..." 1250 | exit 1 1251 | else 1252 | LOGI "The certificate is installed and auto-renewal is turned on. Specific information is as follows:" 1253 | ls -lah ${certPath}/* 1254 | chmod 755 ${certPath}/* 1255 | fi 1256 | 1257 | # Prompt user to set panel paths after successful certificate installation 1258 | read -rp "Would you like to set this certificate for the panel? (y/n): " setPanel 1259 | if [[ "$setPanel" == "y" || "$setPanel" == "Y" ]]; then 1260 | local webCertFile="${certPath}/fullchain.pem" 1261 | local webKeyFile="${certPath}/privkey.pem" 1262 | 1263 | if [[ -f "$webCertFile" && -f "$webKeyFile" ]]; then 1264 | /usr/local/x-ui/x-ui cert -webCert "$webCertFile" -webCertKey "$webKeyFile" 1265 | LOGI "Panel paths set for domain: $CF_Domain" 1266 | LOGI " - Certificate File: $webCertFile" 1267 | LOGI " - Private Key File: $webKeyFile" 1268 | echo -e "${green}Access URL: https://${CF_Domain}:${existing_port}${existing_webBasePath}${plain}" 1269 | restart 1270 | else 1271 | LOGE "Error: Certificate or private key file not found for domain: $CF_Domain." 1272 | fi 1273 | else 1274 | LOGI "Skipping panel path setting." 1275 | fi 1276 | else 1277 | show_menu 1278 | fi 1279 | } 1280 | 1281 | run_speedtest() { 1282 | # Check if Speedtest is already installed 1283 | if ! command -v speedtest &>/dev/null; then 1284 | # If not installed, determine installation method 1285 | if command -v snap &>/dev/null; then 1286 | # Use snap to install Speedtest 1287 | echo "Installing Speedtest using snap..." 1288 | snap install speedtest 1289 | else 1290 | # Fallback to using package managers 1291 | local pkg_manager="" 1292 | local speedtest_install_script="" 1293 | 1294 | if command -v dnf &>/dev/null; then 1295 | pkg_manager="dnf" 1296 | speedtest_install_script="https://packagecloud.io/install/repositories/ookla/speedtest-cli/script.rpm.sh" 1297 | elif command -v yum &>/dev/null; then 1298 | pkg_manager="yum" 1299 | speedtest_install_script="https://packagecloud.io/install/repositories/ookla/speedtest-cli/script.rpm.sh" 1300 | elif command -v apt-get &>/dev/null; then 1301 | pkg_manager="apt-get" 1302 | speedtest_install_script="https://packagecloud.io/install/repositories/ookla/speedtest-cli/script.deb.sh" 1303 | elif command -v apt &>/dev/null; then 1304 | pkg_manager="apt" 1305 | speedtest_install_script="https://packagecloud.io/install/repositories/ookla/speedtest-cli/script.deb.sh" 1306 | fi 1307 | 1308 | if [[ -z $pkg_manager ]]; then 1309 | echo "Error: Package manager not found. You may need to install Speedtest manually." 1310 | return 1 1311 | else 1312 | echo "Installing Speedtest using $pkg_manager..." 1313 | curl -s $speedtest_install_script | bash 1314 | $pkg_manager install -y speedtest 1315 | fi 1316 | fi 1317 | fi 1318 | 1319 | speedtest 1320 | } 1321 | 1322 | create_iplimit_jails() { 1323 | # Use default bantime if not passed => 30 minutes 1324 | local bantime="${1:-30}" 1325 | 1326 | # Uncomment 'allowipv6 = auto' in fail2ban.conf 1327 | sed -i 's/#allowipv6 = auto/allowipv6 = auto/g' /etc/fail2ban/fail2ban.conf 1328 | 1329 | # On Debian 12+ fail2ban's default backend should be changed to systemd 1330 | if [[ "${release}" == "debian" && ${os_version} -ge 12 ]]; then 1331 | sed -i '0,/action =/s/backend = auto/backend = systemd/' /etc/fail2ban/jail.conf 1332 | fi 1333 | 1334 | cat << EOF > /etc/fail2ban/jail.d/3x-ipl.conf 1335 | [3x-ipl] 1336 | enabled=true 1337 | backend=auto 1338 | filter=3x-ipl 1339 | action=3x-ipl 1340 | logpath=${iplimit_log_path} 1341 | maxretry=2 1342 | findtime=32 1343 | bantime=${bantime}m 1344 | EOF 1345 | 1346 | cat << EOF > /etc/fail2ban/filter.d/3x-ipl.conf 1347 | [Definition] 1348 | datepattern = ^%%Y/%%m/%%d %%H:%%M:%%S 1349 | failregex = \[LIMIT_IP\]\s*Email\s*=\s*.+\s*\|\|\s*SRC\s*=\s* 1350 | ignoreregex = 1351 | EOF 1352 | 1353 | cat << EOF > /etc/fail2ban/action.d/3x-ipl.conf 1354 | [INCLUDES] 1355 | before = iptables-allports.conf 1356 | 1357 | [Definition] 1358 | actionstart = -N f2b- 1359 | -A f2b- -j 1360 | -I -p -j f2b- 1361 | 1362 | actionstop = -D -p -j f2b- 1363 | 1364 | -X f2b- 1365 | 1366 | actioncheck = -n -L | grep -q 'f2b-[ \t]' 1367 | 1368 | actionban = -I f2b- 1 -s -j 1369 | echo "\$(date +"%%Y/%%m/%%d %%H:%%M:%%S") BAN [Email] = [IP] = banned for seconds." >> ${iplimit_banned_log_path} 1370 | 1371 | actionunban = -D f2b- -s -j 1372 | echo "\$(date +"%%Y/%%m/%%d %%H:%%M:%%S") UNBAN [Email] = [IP] = unbanned." >> ${iplimit_banned_log_path} 1373 | 1374 | [Init] 1375 | name = default 1376 | protocol = tcp 1377 | chain = INPUT 1378 | EOF 1379 | 1380 | echo -e "${green}Ip Limit jail files created with a bantime of ${bantime} minutes.${plain}" 1381 | } 1382 | 1383 | iplimit_remove_conflicts() { 1384 | local jail_files=( 1385 | /etc/fail2ban/jail.conf 1386 | /etc/fail2ban/jail.local 1387 | ) 1388 | 1389 | for file in "${jail_files[@]}"; do 1390 | # Check for [3x-ipl] config in jail file then remove it 1391 | if test -f "${file}" && grep -qw '3x-ipl' ${file}; then 1392 | sed -i "/\[3x-ipl\]/,/^$/d" ${file} 1393 | echo -e "${yellow}Removing conflicts of [3x-ipl] in jail (${file})!${plain}\n" 1394 | fi 1395 | done 1396 | } 1397 | 1398 | ip_validation() { 1399 | ipv6_regex="^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$" 1400 | ipv4_regex="^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]?|0)\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]?|0)$" 1401 | } 1402 | 1403 | iplimit_main() { 1404 | echo -e "\n${green}\t1.${plain} Install Fail2ban and configure IP Limit" 1405 | echo -e "${green}\t2.${plain} Change Ban Duration" 1406 | echo -e "${green}\t3.${plain} Unban Everyone" 1407 | echo -e "${green}\t4.${plain} Ban Logs" 1408 | echo -e "${green}\t5.${plain} Ban an IP Address" 1409 | echo -e "${green}\t6.${plain} Unban an IP Address" 1410 | echo -e "${green}\t7.${plain} Real-Time Logs" 1411 | echo -e "${green}\t8.${plain} Service Status" 1412 | echo -e "${green}\t9.${plain} Service Restart" 1413 | echo -e "${green}\t10.${plain} Uninstall Fail2ban and IP Limit" 1414 | echo -e "${green}\t0.${plain} Back to Main Menu" 1415 | read -rp "Choose an option: " choice 1416 | case "$choice" in 1417 | 0) 1418 | show_menu 1419 | ;; 1420 | 1) 1421 | confirm "Proceed with installation of Fail2ban & IP Limit?" "y" 1422 | if [[ $? == 0 ]]; then 1423 | install_iplimit 1424 | else 1425 | iplimit_main 1426 | fi 1427 | ;; 1428 | 2) 1429 | read -rp "Please enter new Ban Duration in Minutes [default 30]: " NUM 1430 | if [[ $NUM =~ ^[0-9]+$ ]]; then 1431 | create_iplimit_jails ${NUM} 1432 | systemctl restart fail2ban 1433 | else 1434 | echo -e "${red}${NUM} is not a number! Please, try again.${plain}" 1435 | fi 1436 | iplimit_main 1437 | ;; 1438 | 3) 1439 | confirm "Proceed with Unbanning everyone from IP Limit jail?" "y" 1440 | if [[ $? == 0 ]]; then 1441 | fail2ban-client reload --restart --unban 3x-ipl 1442 | truncate -s 0 "${iplimit_banned_log_path}" 1443 | echo -e "${green}All users Unbanned successfully.${plain}" 1444 | iplimit_main 1445 | else 1446 | echo -e "${yellow}Cancelled.${plain}" 1447 | fi 1448 | iplimit_main 1449 | ;; 1450 | 4) 1451 | show_banlog 1452 | iplimit_main 1453 | ;; 1454 | 5) 1455 | read -rp "Enter the IP address you want to ban: " ban_ip 1456 | ip_validation 1457 | if [[ $ban_ip =~ $ipv4_regex || $ban_ip =~ $ipv6_regex ]]; then 1458 | fail2ban-client set 3x-ipl banip "$ban_ip" 1459 | echo -e "${green}IP Address ${ban_ip} has been banned successfully.${plain}" 1460 | else 1461 | echo -e "${red}Invalid IP address format! Please try again.${plain}" 1462 | fi 1463 | iplimit_main 1464 | ;; 1465 | 6) 1466 | read -rp "Enter the IP address you want to unban: " unban_ip 1467 | ip_validation 1468 | if [[ $unban_ip =~ $ipv4_regex || $unban_ip =~ $ipv6_regex ]]; then 1469 | fail2ban-client set 3x-ipl unbanip "$unban_ip" 1470 | echo -e "${green}IP Address ${unban_ip} has been unbanned successfully.${plain}" 1471 | else 1472 | echo -e "${red}Invalid IP address format! Please try again.${plain}" 1473 | fi 1474 | iplimit_main 1475 | ;; 1476 | 7) 1477 | tail -f /var/log/fail2ban.log 1478 | iplimit_main 1479 | ;; 1480 | 8) 1481 | service fail2ban status 1482 | iplimit_main 1483 | ;; 1484 | 9) 1485 | systemctl restart fail2ban 1486 | iplimit_main 1487 | ;; 1488 | 10) 1489 | remove_iplimit 1490 | iplimit_main 1491 | ;; 1492 | *) 1493 | echo -e "${red}Invalid option. Please select a valid number.${plain}\n" 1494 | iplimit_main 1495 | ;; 1496 | esac 1497 | } 1498 | 1499 | install_iplimit() { 1500 | if ! command -v fail2ban-client &>/dev/null; then 1501 | echo -e "${green}Fail2ban is not installed. Installing now...!${plain}\n" 1502 | 1503 | # Check the OS and install necessary packages 1504 | case "${release}" in 1505 | ubuntu) 1506 | if [[ "${os_version}" -ge 24 ]]; then 1507 | apt update && apt install python3-pip -y 1508 | python3 -m pip install pyasynchat --break-system-packages 1509 | fi 1510 | apt update && apt install fail2ban -y 1511 | ;; 1512 | debian | armbian) 1513 | apt update && apt install fail2ban -y 1514 | ;; 1515 | centos | almalinux | rocky | ol) 1516 | yum update -y && yum install epel-release -y 1517 | yum -y install fail2ban 1518 | ;; 1519 | fedora | amzn | virtuozzo) 1520 | dnf -y update && dnf -y install fail2ban 1521 | ;; 1522 | arch | manjaro | parch) 1523 | pacman -Syu --noconfirm fail2ban 1524 | ;; 1525 | *) 1526 | echo -e "${red}Unsupported operating system. Please check the script and install the necessary packages manually.${plain}\n" 1527 | exit 1 1528 | ;; 1529 | esac 1530 | 1531 | if ! command -v fail2ban-client &>/dev/null; then 1532 | echo -e "${red}Fail2ban installation failed.${plain}\n" 1533 | exit 1 1534 | fi 1535 | 1536 | echo -e "${green}Fail2ban installed successfully!${plain}\n" 1537 | else 1538 | echo -e "${yellow}Fail2ban is already installed.${plain}\n" 1539 | fi 1540 | 1541 | echo -e "${green}Configuring IP Limit...${plain}\n" 1542 | 1543 | # make sure there's no conflict for jail files 1544 | iplimit_remove_conflicts 1545 | 1546 | # Check if log file exists 1547 | if ! test -f "${iplimit_banned_log_path}"; then 1548 | touch ${iplimit_banned_log_path} 1549 | fi 1550 | 1551 | # Check if service log file exists so fail2ban won't return error 1552 | if ! test -f "${iplimit_log_path}"; then 1553 | touch ${iplimit_log_path} 1554 | fi 1555 | 1556 | # Create the iplimit jail files 1557 | # we didn't pass the bantime here to use the default value 1558 | create_iplimit_jails 1559 | 1560 | # Launching fail2ban 1561 | if ! systemctl is-active --quiet fail2ban; then 1562 | systemctl start fail2ban 1563 | else 1564 | systemctl restart fail2ban 1565 | fi 1566 | systemctl enable fail2ban 1567 | 1568 | echo -e "${green}IP Limit installed and configured successfully!${plain}\n" 1569 | before_show_menu 1570 | } 1571 | 1572 | remove_iplimit() { 1573 | echo -e "${green}\t1.${plain} Only remove IP Limit configurations" 1574 | echo -e "${green}\t2.${plain} Uninstall Fail2ban and IP Limit" 1575 | echo -e "${green}\t0.${plain} Back to Main Menu" 1576 | read -rp "Choose an option: " num 1577 | case "$num" in 1578 | 1) 1579 | rm -f /etc/fail2ban/filter.d/3x-ipl.conf 1580 | rm -f /etc/fail2ban/action.d/3x-ipl.conf 1581 | rm -f /etc/fail2ban/jail.d/3x-ipl.conf 1582 | systemctl restart fail2ban 1583 | echo -e "${green}IP Limit removed successfully!${plain}\n" 1584 | before_show_menu 1585 | ;; 1586 | 2) 1587 | rm -rf /etc/fail2ban 1588 | systemctl stop fail2ban 1589 | case "${release}" in 1590 | ubuntu | debian | armbian) 1591 | apt-get remove -y fail2ban 1592 | apt-get purge -y fail2ban -y 1593 | apt-get autoremove -y 1594 | ;; 1595 | centos | almalinux | rocky | ol) 1596 | yum remove fail2ban -y 1597 | yum autoremove -y 1598 | ;; 1599 | fedora | amzn | virtuozzo) 1600 | dnf remove fail2ban -y 1601 | dnf autoremove -y 1602 | ;; 1603 | arch | manjaro | parch) 1604 | pacman -Rns --noconfirm fail2ban 1605 | ;; 1606 | *) 1607 | echo -e "${red}Unsupported operating system. Please uninstall Fail2ban manually.${plain}\n" 1608 | exit 1 1609 | ;; 1610 | esac 1611 | echo -e "${green}Fail2ban and IP Limit removed successfully!${plain}\n" 1612 | before_show_menu 1613 | ;; 1614 | 0) 1615 | show_menu 1616 | ;; 1617 | *) 1618 | echo -e "${red}Invalid option. Please select a valid number.${plain}\n" 1619 | remove_iplimit 1620 | ;; 1621 | esac 1622 | } 1623 | 1624 | SSH_port_forwarding() { 1625 | local server_ip=$(curl -s https://api.ipify.org) 1626 | local existing_webBasePath=$(/usr/local/x-ui/x-ui setting -show true | grep -Eo 'webBasePath: .+' | awk '{print $2}') 1627 | local existing_port=$(/usr/local/x-ui/x-ui setting -show true | grep -Eo 'port: .+' | awk '{print $2}') 1628 | local existing_listenIP=$(/usr/local/x-ui/x-ui setting -getListen true | grep -Eo 'listenIP: .+' | awk '{print $2}') 1629 | local existing_cert=$(/usr/local/x-ui/x-ui setting -getCert true | grep -Eo 'cert: .+' | awk '{print $2}') 1630 | local existing_key=$(/usr/local/x-ui/x-ui setting -getCert true | grep -Eo 'key: .+' | awk '{print $2}') 1631 | 1632 | local config_listenIP="" 1633 | local listen_choice="" 1634 | 1635 | if [[ -n "$existing_cert" && -n "$existing_key" ]]; then 1636 | echo -e "${green}Panel is secure with SSL.${plain}" 1637 | before_show_menu 1638 | fi 1639 | if [[ -z "$existing_cert" && -z "$existing_key" && (-z "$existing_listenIP" || "$existing_listenIP" == "0.0.0.0") ]]; then 1640 | echo -e "\n${red}Warning: No Cert and Key found! The panel is not secure.${plain}" 1641 | echo "Please obtain a certificate or set up SSH port forwarding." 1642 | fi 1643 | 1644 | if [[ -n "$existing_listenIP" && "$existing_listenIP" != "0.0.0.0" && (-z "$existing_cert" && -z "$existing_key") ]]; then 1645 | echo -e "\n${green}Current SSH Port Forwarding Configuration:${plain}" 1646 | echo -e "Standard SSH command:" 1647 | echo -e "${yellow}ssh -L 2222:${existing_listenIP}:${existing_port} root@${server_ip}${plain}" 1648 | echo -e "\nIf using SSH key:" 1649 | echo -e "${yellow}ssh -i -L 2222:${existing_listenIP}:${existing_port} root@${server_ip}${plain}" 1650 | echo -e "\nAfter connecting, access the panel at:" 1651 | echo -e "${yellow}http://localhost:2222${existing_webBasePath}${plain}" 1652 | fi 1653 | 1654 | echo -e "\nChoose an option:" 1655 | echo -e "${green}1.${plain} Set listen IP" 1656 | echo -e "${green}2.${plain} Clear listen IP" 1657 | echo -e "${green}0.${plain} Back to Main Menu" 1658 | read -rp "Choose an option: " num 1659 | 1660 | case "$num" in 1661 | 1) 1662 | if [[ -z "$existing_listenIP" || "$existing_listenIP" == "0.0.0.0" ]]; then 1663 | echo -e "\nNo listenIP configured. Choose an option:" 1664 | echo -e "1. Use default IP (127.0.0.1)" 1665 | echo -e "2. Set a custom IP" 1666 | read -rp "Select an option (1 or 2): " listen_choice 1667 | 1668 | config_listenIP="127.0.0.1" 1669 | [[ "$listen_choice" == "2" ]] && read -rp "Enter custom IP to listen on: " config_listenIP 1670 | 1671 | /usr/local/x-ui/x-ui setting -listenIP "${config_listenIP}" >/dev/null 2>&1 1672 | echo -e "${green}listen IP has been set to ${config_listenIP}.${plain}" 1673 | echo -e "\n${green}SSH Port Forwarding Configuration:${plain}" 1674 | echo -e "Standard SSH command:" 1675 | echo -e "${yellow}ssh -L 2222:${config_listenIP}:${existing_port} root@${server_ip}${plain}" 1676 | echo -e "\nIf using SSH key:" 1677 | echo -e "${yellow}ssh -i -L 2222:${config_listenIP}:${existing_port} root@${server_ip}${plain}" 1678 | echo -e "\nAfter connecting, access the panel at:" 1679 | echo -e "${yellow}http://localhost:2222${existing_webBasePath}${plain}" 1680 | restart 1681 | else 1682 | config_listenIP="${existing_listenIP}" 1683 | echo -e "${green}Current listen IP is already set to ${config_listenIP}.${plain}" 1684 | fi 1685 | ;; 1686 | 2) 1687 | /usr/local/x-ui/x-ui setting -listenIP 0.0.0.0 >/dev/null 2>&1 1688 | echo -e "${green}Listen IP has been cleared.${plain}" 1689 | restart 1690 | ;; 1691 | 0) 1692 | show_menu 1693 | ;; 1694 | *) 1695 | echo -e "${red}Invalid option. Please select a valid number.${plain}\n" 1696 | SSH_port_forwarding 1697 | ;; 1698 | esac 1699 | } 1700 | 1701 | show_usage() { 1702 | echo -e "┌───────────────────────────────────────────────────────┐ 1703 | │ ${blue}x-ui control menu usages (subcommands):${plain} │ 1704 | │ │ 1705 | │ ${blue}x-ui${plain} - Admin Management Script │ 1706 | │ ${blue}x-ui start${plain} - Start │ 1707 | │ ${blue}x-ui stop${plain} - Stop │ 1708 | │ ${blue}x-ui restart${plain} - Restart │ 1709 | │ ${blue}x-ui status${plain} - Current Status │ 1710 | │ ${blue}x-ui settings${plain} - Current Settings │ 1711 | │ ${blue}x-ui enable${plain} - Enable Autostart on OS Startup │ 1712 | │ ${blue}x-ui disable${plain} - Disable Autostart on OS Startup │ 1713 | │ ${blue}x-ui log${plain} - Check logs │ 1714 | │ ${blue}x-ui banlog${plain} - Check Fail2ban ban logs │ 1715 | │ ${blue}x-ui update${plain} - Update │ 1716 | │ ${blue}x-ui legacy${plain} - legacy version │ 1717 | │ ${blue}x-ui install${plain} - Install │ 1718 | │ ${blue}x-ui uninstall${plain} - Uninstall │ 1719 | └───────────────────────────────────────────────────────┘" 1720 | } 1721 | 1722 | show_menu() { 1723 | echo -e " 1724 | ╔────────────────────────────────────────────────╗ 1725 | │ ${green}3X-UI Panel Management Script${plain} │ 1726 | │ ${green}0.${plain} Exit Script │ 1727 | │────────────────────────────────────────────────│ 1728 | │ ${green}1.${plain} Install │ 1729 | │ ${green}2.${plain} Update │ 1730 | │ ${green}3.${plain} Update Menu │ 1731 | │ ${green}4.${plain} Legacy Version │ 1732 | │ ${green}5.${plain} Uninstall │ 1733 | │────────────────────────────────────────────────│ 1734 | │ ${green}6.${plain} Reset Username & Password & Secret Token │ 1735 | │ ${green}7.${plain} Reset Web Base Path │ 1736 | │ ${green}8.${plain} Reset Settings │ 1737 | │ ${green}9.${plain} Change Port │ 1738 | │ ${green}10.${plain} View Current Settings │ 1739 | │────────────────────────────────────────────────│ 1740 | │ ${green}11.${plain} Start │ 1741 | │ ${green}12.${plain} Stop │ 1742 | │ ${green}13.${plain} Restart │ 1743 | │ ${green}14.${plain} Check Status │ 1744 | │ ${green}15.${plain} Logs Management │ 1745 | │────────────────────────────────────────────────│ 1746 | │ ${green}16.${plain} Enable Autostart │ 1747 | │ ${green}17.${plain} Disable Autostart │ 1748 | │────────────────────────────────────────────────│ 1749 | │ ${green}18.${plain} SSL Certificate Management │ 1750 | │ ${green}19.${plain} Cloudflare SSL Certificate │ 1751 | │ ${green}20.${plain} IP Limit Management │ 1752 | │ ${green}21.${plain} Firewall Management │ 1753 | │ ${green}22.${plain} SSH Port Forwarding Management │ 1754 | │────────────────────────────────────────────────│ 1755 | │ ${green}23.${plain} Enable BBR │ 1756 | │ ${green}24.${plain} Update Geo Files │ 1757 | │ ${green}25.${plain} Speedtest by Ookla │ 1758 | ╚────────────────────────────────────────────────╝ 1759 | " 1760 | show_status 1761 | echo && read -rp "Please enter your selection [0-25]: " num 1762 | 1763 | case "${num}" in 1764 | 0) 1765 | exit 0 1766 | ;; 1767 | 1) 1768 | check_uninstall && install 1769 | ;; 1770 | 2) 1771 | check_install && update 1772 | ;; 1773 | 3) 1774 | check_install && update_menu 1775 | ;; 1776 | 4) 1777 | check_install && legacy_version 1778 | ;; 1779 | 5) 1780 | check_install && uninstall 1781 | ;; 1782 | 6) 1783 | check_install && reset_user 1784 | ;; 1785 | 7) 1786 | check_install && reset_webbasepath 1787 | ;; 1788 | 8) 1789 | check_install && reset_config 1790 | ;; 1791 | 9) 1792 | check_install && set_port 1793 | ;; 1794 | 10) 1795 | check_install && check_config 1796 | ;; 1797 | 11) 1798 | check_install && start 1799 | ;; 1800 | 12) 1801 | check_install && stop 1802 | ;; 1803 | 13) 1804 | check_install && restart 1805 | ;; 1806 | 14) 1807 | check_install && status 1808 | ;; 1809 | 15) 1810 | check_install && show_log 1811 | ;; 1812 | 16) 1813 | check_install && enable 1814 | ;; 1815 | 17) 1816 | check_install && disable 1817 | ;; 1818 | 18) 1819 | ssl_cert_issue_main 1820 | ;; 1821 | 19) 1822 | ssl_cert_issue_CF 1823 | ;; 1824 | 20) 1825 | iplimit_main 1826 | ;; 1827 | 21) 1828 | firewall_menu 1829 | ;; 1830 | 22) 1831 | SSH_port_forwarding 1832 | ;; 1833 | 23) 1834 | bbr_menu 1835 | ;; 1836 | 24) 1837 | update_geo 1838 | ;; 1839 | 25) 1840 | run_speedtest 1841 | ;; 1842 | *) 1843 | LOGE "Please enter the correct number [0-25]" 1844 | ;; 1845 | esac 1846 | } 1847 | 1848 | if [[ $# > 0 ]]; then 1849 | case $1 in 1850 | "start") 1851 | check_install 0 && start 0 1852 | ;; 1853 | "stop") 1854 | check_install 0 && stop 0 1855 | ;; 1856 | "restart") 1857 | check_install 0 && restart 0 1858 | ;; 1859 | "status") 1860 | check_install 0 && status 0 1861 | ;; 1862 | "settings") 1863 | check_install 0 && check_config 0 1864 | ;; 1865 | "enable") 1866 | check_install 0 && enable 0 1867 | ;; 1868 | "disable") 1869 | check_install 0 && disable 0 1870 | ;; 1871 | "log") 1872 | check_install 0 && show_log 0 1873 | ;; 1874 | "banlog") 1875 | check_install 0 && show_banlog 0 1876 | ;; 1877 | "update") 1878 | check_install 0 && update 0 1879 | ;; 1880 | "legacy") 1881 | check_install 0 && legacy_version 0 1882 | ;; 1883 | "install") 1884 | check_uninstall 0 && install 0 1885 | ;; 1886 | "uninstall") 1887 | check_install 0 && uninstall 0 1888 | ;; 1889 | *) show_usage ;; 1890 | esac 1891 | else 1892 | show_menu 1893 | fi 1894 | --------------------------------------------------------------------------------