From 8968c9f043ad33d6fd5f79c6006c9b289cb8f933 Mon Sep 17 00:00:00 2001 From: sinian-liu <86273555+sinian-liu@users.noreply.github.com> Date: Thu, 8 Jan 2026 00:30:33 +0800 Subject: [PATCH] Update x-ui.sh --- x-ui.sh | 954 +++++++++++++++++++++++++------------------------------- 1 file changed, 429 insertions(+), 525 deletions(-) diff --git a/x-ui.sh b/x-ui.sh index 47d45582..2f44916b 100644 --- a/x-ui.sh +++ b/x-ui.sh @@ -1,28 +1,25 @@ #!/bin/bash -export LANG=zh_CN.UTF-8 -export LC_ALL=zh_CN.UTF-8 - red='\033[0;31m' green='\033[0;32m' blue='\033[0;34m' yellow='\033[0;33m' plain='\033[0m' -#Add some basic function here +# 基本函数 function LOGD() { - echo -e "${yellow}[DEG] $* ${plain}" + echo -e "${yellow}[调试] $* ${plain}" } function LOGE() { - echo -e "${red}[ERR] $* ${plain}" + echo -e "${red}[错误] $* ${plain}" } function LOGI() { - echo -e "${green}[INF] $* ${plain}" + echo -e "${green}[信息] $* ${plain}" } -# Simple helpers for domain/IP validation +# 简单的 IP/域名验证函数 is_ipv4() { [[ "$1" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]] && return 0 || return 1 } @@ -36,10 +33,10 @@ is_domain() { [[ "$1" =~ ^([A-Za-z0-9](-*[A-Za-z0-9])*\.)+[A-Za-z]{2,}$ ]] && return 0 || return 1 } -# check root -[[ $EUID -ne 0 ]] && LOGE "ERROR: You must be root to run this script! \n" && exit 1 +# 检查 root 权限 +[[ $EUID -ne 0 ]] && LOGE "错误:必须使用 root 权限运行此脚本!\n" && exit 1 -# Check OS and set release variable +# 检查操作系统 if [[ -f /etc/os-release ]]; then source /etc/os-release release=$ID @@ -47,15 +44,15 @@ elif [[ -f /usr/lib/os-release ]]; then source /usr/lib/os-release release=$ID else - echo "Failed to check the system OS, please contact the author!" >&2 + echo "无法检测操作系统,请联系作者!" >&2 exit 1 fi -echo "The OS release is: $release" +echo "操作系统: $release" os_version="" os_version=$(grep "^VERSION_ID" /etc/os-release | cut -d '=' -f2 | tr -d '"' | tr -d '.') -# Declare Variables +# 变量声明 xui_folder="${XUI_MAIN_FOLDER:=/usr/local/x-ui}" xui_service="${XUI_SERVICE:=/etc/systemd/system}" log_folder="${XUI_LOG_FOLDER:=/var/log/x-ui}" @@ -65,7 +62,7 @@ iplimit_banned_log_path="${log_folder}/3xipl-banned.log" confirm() { if [[ $# > 1 ]]; then - echo && read -rp "$1 [Default $2]: " temp + echo && read -rp "$1 [默认 $2]: " temp if [[ "${temp}" == "" ]]; then temp=$2 fi @@ -80,7 +77,7 @@ confirm() { } confirm_restart() { - confirm "Restart the panel, Attention: Restarting the panel will also restart xray" "y" + confirm "重启面板,注意:重启面板也会重启 xray" "y" if [[ $? == 0 ]]; then restart else @@ -89,7 +86,7 @@ confirm_restart() { } before_show_menu() { - echo && echo -n -e "${yellow}Press enter to return to the main menu: ${plain}" && read -r temp + echo && echo -n -e "${yellow}按回车键返回主菜单: ${plain}" && read -r temp show_menu } @@ -105,9 +102,9 @@ install() { } update() { - confirm "This function will update all x-ui components to the latest version, and the data will not be lost. Do you want to continue?" "y" + confirm "此功能将更新所有 x-ui 组件到最新版本,数据不会丢失。是否继续?" "y" if [[ $? != 0 ]]; then - LOGE "Cancelled" + LOGE "已取消" if [[ $# == 0 ]]; then before_show_menu fi @@ -115,16 +112,16 @@ update() { fi bash <(curl -Ls https://raw.githubusercontent.com/MHSanaei/3x-ui/main/update.sh) if [[ $? == 0 ]]; then - LOGI "Update is complete, Panel has automatically restarted " + LOGI "更新完成,面板已自动重启" before_show_menu fi } update_menu() { - echo -e "${yellow}Updating Menu${plain}" - confirm "This function will update the menu to the latest changes." "y" + echo -e "${yellow}更新菜单脚本${plain}" + confirm "此功能将更新菜单到最新版本。" "y" if [[ $? != 0 ]]; then - LOGE "Cancelled" + LOGE "已取消" if [[ $# == 0 ]]; then before_show_menu fi @@ -136,37 +133,35 @@ update_menu() { chmod +x /usr/bin/x-ui if [[ $? == 0 ]]; then - echo -e "${green}Update successful. The panel has automatically restarted.${plain}" + echo -e "${green}更新成功,面板已自动重启。${plain}" exit 0 else - echo -e "${red}Failed to update the menu.${plain}" + echo -e "${red}更新菜单失败。${plain}" return 1 fi } legacy_version() { - echo -n "Enter the panel version (like 2.4.0):" + echo -n "输入面板版本(例如 2.4.0):" read -r tag_version if [ -z "$tag_version" ]; then - echo "Panel version cannot be empty. Exiting." + echo "面板版本不能为空。退出。" exit 1 fi - # Use the entered panel version in the download link install_command="bash <(curl -Ls "https://raw.githubusercontent.com/mhsanaei/3x-ui/v$tag_version/install.sh") v$tag_version" - echo "Downloading and installing panel version $tag_version..." + echo "正在下载安装面板版本 $tag_version..." eval $install_command } -# Function to handle the deletion of the script file delete_script() { - rm "$0" # Remove the script file itself + rm "$0" exit 1 } uninstall() { - confirm "Are you sure you want to uninstall the panel? xray will also uninstalled!" "n" + confirm "确定要卸载面板吗?xray 也会被卸载!" "n" if [[ $? != 0 ]]; then if [[ $# == 0 ]]; then show_menu @@ -190,17 +185,16 @@ uninstall() { rm ${xui_folder}/ -rf echo "" - echo -e "Uninstalled Successfully.\n" - echo "If you need to install this panel again, you can use below command:" + echo -e "卸载成功。\n" + echo "如需重新安装此面板,可以使用以下命令:" echo -e "${green}bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)${plain}" echo "" - # Trap the SIGTERM signal trap delete_script SIGTERM delete_script } reset_user() { - confirm "Are you sure to reset the username and password of the panel?" "n" + confirm "确定要重置面板的用户名和密码吗?" "n" if [[ $? != 0 ]]; then if [[ $# == 0 ]]; then show_menu @@ -208,22 +202,22 @@ reset_user() { return 0 fi - read -rp "Please set the login username [default is a random username]: " config_account + read -rp "请设置登录用户名 [默认随机生成]: " config_account [[ -z $config_account ]] && config_account=$(gen_random_string 10) - read -rp "Please set the login password [default is a random password]: " config_password + read -rp "请设置登录密码 [默认随机生成]: " config_password [[ -z $config_password ]] && config_password=$(gen_random_string 18) - read -rp "Do you want to disable currently configured two-factor authentication? (y/n): " twoFactorConfirm + read -rp "是否要禁用当前配置的两步验证?(y/n): " twoFactorConfirm if [[ $twoFactorConfirm != "y" && $twoFactorConfirm != "Y" ]]; then ${xui_folder}/x-ui setting -username ${config_account} -password ${config_password} -resetTwoFactor false >/dev/null 2>&1 else ${xui_folder}/x-ui setting -username ${config_account} -password ${config_password} -resetTwoFactor true >/dev/null 2>&1 - echo -e "Two factor authentication has been disabled." + echo -e "两步验证已禁用。" fi - echo -e "Panel login username has been reset to: ${green} ${config_account} ${plain}" - echo -e "Panel login password has been reset to: ${green} ${config_password} ${plain}" - echo -e "${green} Please use the new login username and password to access the X-UI panel. Also remember them! ${plain}" + echo -e "面板登录用户名已重置为: ${green} ${config_account} ${plain}" + echo -e "面板登录密码已重置为: ${green} ${config_password} ${plain}" + echo -e "${green}请使用新的用户名和密码访问 X-UI 面板。请务必记住它们!${plain}" confirm_restart } @@ -234,26 +228,25 @@ gen_random_string() { } reset_webbasepath() { - echo -e "${yellow}Resetting Web Base Path${plain}" + echo -e "${yellow}重置 Web 访问路径${plain}" - read -rp "Are you sure you want to reset the web base path? (y/n): " confirm + read -rp "确定要重置 Web 访问路径吗?(y/n): " confirm if [[ $confirm != "y" && $confirm != "Y" ]]; then - echo -e "${yellow}Operation canceled.${plain}" + echo -e "${yellow}操作取消。${plain}" return fi config_webBasePath=$(gen_random_string 18) - # Apply the new web base path setting ${xui_folder}/x-ui setting -webBasePath "${config_webBasePath}" >/dev/null 2>&1 - echo -e "Web base path has been reset to: ${green}${config_webBasePath}${plain}" - echo -e "${green}Please use the new web base path to access the panel.${plain}" + echo -e "Web 访问路径已重置为: ${green}${config_webBasePath}${plain}" + echo -e "${green}请使用新的 Web 访问路径访问面板。${plain}" restart } reset_config() { - confirm "Are you sure you want to reset all panel settings, Account data will not be lost, Username and password will not change" "n" + confirm "确定要重置所有面板设置吗?账户数据不会丢失,用户名和密码不会改变" "n" if [[ $? != 0 ]]; then if [[ $# == 0 ]]; then show_menu @@ -261,14 +254,14 @@ reset_config() { return 0 fi ${xui_folder}/x-ui setting -reset - echo -e "All panel settings have been reset to default." + echo -e "所有面板设置已重置为默认值。" restart } check_config() { local info=$(${xui_folder}/x-ui setting -show true) if [[ $? != 0 ]]; then - LOGE "get current settings error, please check logs" + LOGE "获取当前设置出错,请检查日志" show_menu return fi @@ -286,42 +279,41 @@ check_config() { local domain=$(basename "$(dirname "$existing_cert")") if [[ "$domain" =~ ^[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]; then - echo -e "${green}Access URL: https://${domain}:${existing_port}${existing_webBasePath}${plain}" + echo -e "${green}访问地址: https://${domain}:${existing_port}${existing_webBasePath}${plain}" else - echo -e "${green}Access URL: https://${server_ip}:${existing_port}${existing_webBasePath}${plain}" + echo -e "${green}访问地址: https://${server_ip}:${existing_port}${existing_webBasePath}${plain}" fi else - echo -e "${red}⚠ WARNING: No SSL certificate configured!${plain}" - echo -e "${yellow}You can get a Let's Encrypt certificate for your IP address (valid ~6 days, auto-renews).${plain}" - read -rp "Generate SSL certificate for IP now? [y/N]: " gen_ssl + echo -e "${red}⚠ 警告:未配置 SSL 证书!${plain}" + echo -e "${yellow}可以为您的 IP 地址获取 Let's Encrypt 证书(有效约6天,自动续期)。${plain}" + read -rp "现在为 IP 生成 SSL 证书吗?[y/N]: " gen_ssl if [[ "$gen_ssl" == "y" || "$gen_ssl" == "Y" ]]; then stop >/dev/null 2>&1 ssl_cert_issue_for_ip if [[ $? -eq 0 ]]; then - echo -e "${green}Access URL: https://${server_ip}:${existing_port}${existing_webBasePath}${plain}" - # ssl_cert_issue_for_ip already restarts the panel, but ensure it's running + echo -e "${green}访问地址: https://${server_ip}:${existing_port}${existing_webBasePath}${plain}" start >/dev/null 2>&1 else - LOGE "IP certificate setup failed." - echo -e "${yellow}You can try again via option 18 (SSL Certificate Management).${plain}" + LOGE "IP 证书设置失败。" + echo -e "${yellow}可以通过选项 18 (SSL 证书管理) 重试。${plain}" start >/dev/null 2>&1 fi else - echo -e "${yellow}Access URL: http://${server_ip}:${existing_port}${existing_webBasePath}${plain}" - echo -e "${yellow}For security, please configure SSL certificate using option 18 (SSL Certificate Management)${plain}" + echo -e "${yellow}访问地址: http://${server_ip}:${existing_port}${existing_webBasePath}${plain}" + echo -e "${yellow}为了安全,请使用选项 18 (SSL 证书管理) 配置 SSL 证书${plain}" fi fi } set_port() { - echo -n "Enter port number[1-65535]: " + echo -n "输入端口号[1-65535]: " read -r port if [[ -z "${port}" ]]; then - LOGD "Cancelled" + LOGD "已取消" before_show_menu else ${xui_folder}/x-ui setting -port ${port} - echo -e "The port is set, Please restart the panel now, and use the new port ${green}${port}${plain} to access web panel" + echo -e "端口已设置,请立即重启面板,并使用新端口 ${green}${port}${plain} 访问 Web 面板" confirm_restart fi } @@ -330,7 +322,7 @@ start() { check_status if [[ $? == 0 ]]; then echo "" - LOGI "Panel is running, No need to start again, If you need to restart, please select restart" + LOGI "面板已在运行,无需再次启动,如需重启请选择重启" else if [[ $release == "alpine" ]]; then rc-service x-ui start @@ -340,9 +332,9 @@ start() { sleep 2 check_status if [[ $? == 0 ]]; then - LOGI "x-ui Started Successfully" + LOGI "x-ui 启动成功" else - LOGE "panel Failed to start, Probably because it takes longer than two seconds to start, Please check the log information later" + LOGE "面板启动失败,可能因为启动时间超过两秒,请稍后检查日志信息" fi fi @@ -355,7 +347,7 @@ stop() { check_status if [[ $? == 1 ]]; then echo "" - LOGI "Panel stopped, No need to stop again!" + LOGI "面板已停止,无需再次停止!" else if [[ $release == "alpine" ]]; then rc-service x-ui stop @@ -365,9 +357,9 @@ stop() { sleep 2 check_status if [[ $? == 1 ]]; then - LOGI "x-ui and xray stopped successfully" + LOGI "x-ui 和 xray 停止成功" else - LOGE "Panel stop failed, Probably because the stop time exceeds two seconds, Please check the log information later" + LOGE "面板停止失败,可能因为停止时间超过两秒,请稍后检查日志信息" fi fi @@ -385,9 +377,9 @@ restart() { sleep 2 check_status if [[ $? == 0 ]]; then - LOGI "x-ui and xray Restarted successfully" + LOGI "x-ui 和 xray 重启成功" else - LOGE "Panel restart failed, Probably because it takes longer than two seconds to start, Please check the log information later" + LOGE "面板重启失败,可能因为启动时间超过两秒,请稍后检查日志信息" fi if [[ $# == 0 ]]; then before_show_menu @@ -412,9 +404,9 @@ enable() { systemctl enable x-ui fi if [[ $? == 0 ]]; then - LOGI "x-ui Set to boot automatically on startup successfully" + LOGI "x-ui 开机自启设置成功" else - LOGE "x-ui Failed to set Autostart" + LOGE "x-ui 开机自启设置失败" fi if [[ $# == 0 ]]; then @@ -429,9 +421,9 @@ disable() { systemctl disable x-ui fi if [[ $? == 0 ]]; then - LOGI "x-ui Autostart Cancelled successfully" + LOGI "x-ui 开机自启取消成功" else - LOGE "x-ui Failed to cancel autostart" + LOGE "x-ui 取消开机自启失败" fi if [[ $# == 0 ]]; then @@ -441,9 +433,9 @@ disable() { show_log() { if [[ $release == "alpine" ]]; then - echo -e "${green}\t1.${plain} Debug Log" - echo -e "${green}\t0.${plain} Back to Main Menu" - read -rp "Choose an option: " choice + echo -e "${green}\t1.${plain} 调试日志" + echo -e "${green}\t0.${plain} 返回主菜单" + read -rp "选择选项: " choice case "$choice" in 0) @@ -456,15 +448,15 @@ show_log() { fi ;; *) - echo -e "${red}Invalid option. Please select a valid number.${plain}\n" + echo -e "${red}无效选项,请选择有效数字。${plain}\n" show_log ;; esac else - echo -e "${green}\t1.${plain} Debug Log" - echo -e "${green}\t2.${plain} Clear All logs" - echo -e "${green}\t0.${plain} Back to Main Menu" - read -rp "Choose an option: " choice + echo -e "${green}\t1.${plain} 调试日志" + echo -e "${green}\t2.${plain} 清除所有日志" + echo -e "${green}\t0.${plain} 返回主菜单" + read -rp "选择选项: " choice case "$choice" in 0) @@ -479,11 +471,11 @@ show_log() { 2) sudo journalctl --rotate sudo journalctl --vacuum-time=1s - echo "All Logs cleared." + echo "所有日志已清除。" restart ;; *) - echo -e "${red}Invalid option. Please select a valid number.${plain}\n" + echo -e "${red}无效选项,请选择有效数字。${plain}\n" show_log ;; esac @@ -491,10 +483,10 @@ show_log() { } bbr_menu() { - echo -e "${green}\t1.${plain} Enable BBR" - echo -e "${green}\t2.${plain} Disable BBR" - echo -e "${green}\t0.${plain} Back to Main Menu" - read -rp "Choose an option: " choice + echo -e "${green}\t1.${plain} 启用 BBR" + echo -e "${green}\t2.${plain} 禁用 BBR" + echo -e "${green}\t0.${plain} 返回主菜单" + read -rp "选择选项: " choice case "$choice" in 0) show_menu @@ -508,41 +500,36 @@ bbr_menu() { bbr_menu ;; *) - echo -e "${red}Invalid option. Please select a valid number.${plain}\n" + echo -e "${red}无效选项,请选择有效数字。${plain}\n" bbr_menu ;; esac } disable_bbr() { - if ! grep -q "net.core.default_qdisc=fq" /etc/sysctl.conf || ! grep -q "net.ipv4.tcp_congestion_control=bbr" /etc/sysctl.conf; then - echo -e "${yellow}BBR is not currently enabled.${plain}" + echo -e "${yellow}BBR 当前未启用。${plain}" before_show_menu fi - # Replace BBR with CUBIC configurations sed -i 's/net.core.default_qdisc=fq/net.core.default_qdisc=pfifo_fast/' /etc/sysctl.conf sed -i 's/net.ipv4.tcp_congestion_control=bbr/net.ipv4.tcp_congestion_control=cubic/' /etc/sysctl.conf - # Apply changes sysctl -p - # Verify that BBR is replaced with CUBIC if [[ $(sysctl net.ipv4.tcp_congestion_control | awk '{print $3}') == "cubic" ]]; then - echo -e "${green}BBR has been replaced with CUBIC successfully.${plain}" + echo -e "${green}BBR 已成功替换为 CUBIC。${plain}" else - echo -e "${red}Failed to replace BBR with CUBIC. Please check your system configuration.${plain}" + echo -e "${red}替换 BBR 为 CUBIC 失败。请检查系统配置。${plain}" fi } enable_bbr() { if grep -q "net.core.default_qdisc=fq" /etc/sysctl.conf && grep -q "net.ipv4.tcp_congestion_control=bbr" /etc/sysctl.conf; then - echo -e "${green}BBR is already enabled!${plain}" + echo -e "${green}BBR 已经启用!${plain}" before_show_menu fi - # Check the OS and install necessary packages case "${release}" in ubuntu | debian | armbian) apt-get update && apt-get install -yqq --no-install-recommends ca-certificates @@ -560,30 +547,27 @@ enable_bbr() { arch | manjaro | parch) pacman -Sy --noconfirm ca-certificates ;; - opensuse-tumbleweed | opensuse-leap) + opensuse-tumbleweed | opensuse-leap) zypper refresh && zypper -q install -y ca-certificates ;; alpine) apk add ca-certificates ;; *) - echo -e "${red}Unsupported operating system. Please check the script and install the necessary packages manually.${plain}\n" + echo -e "${red}不支持的操作系统。请手动检查脚本并安装必要包。${plain}\n" exit 1 ;; esac - # Enable BBR echo "net.core.default_qdisc=fq" | tee -a /etc/sysctl.conf echo "net.ipv4.tcp_congestion_control=bbr" | tee -a /etc/sysctl.conf - # Apply changes sysctl -p - # Verify that BBR is enabled if [[ $(sysctl net.ipv4.tcp_congestion_control | awk '{print $3}') == "bbr" ]]; then - echo -e "${green}BBR has been enabled successfully.${plain}" + echo -e "${green}BBR 启用成功。${plain}" else - echo -e "${red}Failed to enable BBR. Please check your system configuration.${plain}" + echo -e "${red}启用 BBR 失败。请检查系统配置。${plain}" fi } @@ -591,16 +575,15 @@ update_shell() { curl -fLRo /usr/bin/x-ui -z /usr/bin/x-ui https://github.com/MHSanaei/3x-ui/raw/main/x-ui.sh if [[ $? != 0 ]]; then echo "" - LOGE "Failed to download script, Please check whether the machine can connect Github" + LOGE "下载脚本失败,请检查机器是否能连接 GitHub" before_show_menu else chmod +x /usr/bin/x-ui - LOGI "Upgrade script succeeded, Please rerun the script" + LOGI "升级脚本成功,请重新运行脚本" before_show_menu fi } -# 0: running, 1: not running, 2: not installed check_status() { if [[ $release == "alpine" ]]; then if [[ ! -f /etc/init.d/x-ui ]]; then @@ -645,7 +628,7 @@ check_uninstall() { check_status if [[ $? != 2 ]]; then echo "" - LOGE "Panel installed, Please do not reinstall" + LOGE "面板已安装,请勿重新安装" if [[ $# == 0 ]]; then before_show_menu fi @@ -659,7 +642,7 @@ check_install() { check_status if [[ $? == 2 ]]; then echo "" - LOGE "Please install the panel first" + LOGE "请先安装面板" if [[ $# == 0 ]]; then before_show_menu fi @@ -673,15 +656,15 @@ show_status() { check_status case $? in 0) - echo -e "Panel state: ${green}Running${plain}" + echo -e "面板状态: ${green}运行中${plain}" show_enable_status ;; 1) - echo -e "Panel state: ${yellow}Not Running${plain}" + echo -e "面板状态: ${yellow}未运行${plain}" show_enable_status ;; 2) - echo -e "Panel state: ${red}Not Installed${plain}" + echo -e "面板状态: ${red}未安装${plain}" ;; esac show_xray_status @@ -690,9 +673,9 @@ show_status() { show_enable_status() { check_enabled if [[ $? == 0 ]]; then - echo -e "Start automatically: ${green}Yes${plain}" + echo -e "开机自启: ${green}是${plain}" else - echo -e "Start automatically: ${red}No${plain}" + echo -e "开机自启: ${red}否${plain}" fi } @@ -708,22 +691,22 @@ check_xray_status() { show_xray_status() { check_xray_status if [[ $? == 0 ]]; then - echo -e "xray state: ${green}Running${plain}" + echo -e "xray 状态: ${green}运行中${plain}" else - echo -e "xray state: ${red}Not Running${plain}" + echo -e "xray 状态: ${red}未运行${plain}" fi } firewall_menu() { - echo -e "${green}\t1.${plain} ${green}Install${plain} Firewall" - echo -e "${green}\t2.${plain} Port List [numbered]" - echo -e "${green}\t3.${plain} ${green}Open${plain} Ports" - echo -e "${green}\t4.${plain} ${red}Delete${plain} Ports from List" - echo -e "${green}\t5.${plain} ${green}Enable${plain} Firewall" - echo -e "${green}\t6.${plain} ${red}Disable${plain} Firewall" - echo -e "${green}\t7.${plain} Firewall Status" - echo -e "${green}\t0.${plain} Back to Main Menu" - read -rp "Choose an option: " choice + echo -e "${green}\t1.${plain} ${green}安装${plain} 防火墙" + echo -e "${green}\t2.${plain} 端口列表 [带编号]" + echo -e "${green}\t3.${plain} ${green}开放${plain} 端口" + echo -e "${green}\t4.${plain} ${red}删除${plain} 端口" + echo -e "${green}\t5.${plain} ${green}启用${plain} 防火墙" + echo -e "${green}\t6.${plain} ${red}禁用${plain} 防火墙" + echo -e "${green}\t7.${plain} 防火墙状态" + echo -e "${green}\t0.${plain} 返回主菜单" + read -rp "选择选项: " choice case "$choice" in 0) show_menu @@ -757,7 +740,7 @@ firewall_menu() { firewall_menu ;; *) - echo -e "${red}Invalid option. Please select a valid number.${plain}\n" + echo -e "${red}无效选项,请选择有效数字。${plain}\n" firewall_menu ;; esac @@ -765,142 +748,115 @@ firewall_menu() { install_firewall() { if ! command -v ufw &>/dev/null; then - echo "ufw firewall is not installed. Installing now..." + echo "ufw 防火墙未安装。正在安装..." apt-get update apt-get install -y ufw else - echo "ufw firewall is already installed" + echo "ufw 防火墙已安装" fi - # Check if the firewall is inactive if ufw status | grep -q "Status: active"; then - echo "Firewall is already active" + echo "防火墙已激活" else - echo "Activating firewall..." - # Open the necessary ports + echo "激活防火墙..." ufw allow ssh ufw allow http ufw allow https - ufw allow 2053/tcp #webPort - ufw allow 2096/tcp #subport + ufw allow 2053/tcp + ufw allow 2096/tcp - # Enable the firewall ufw --force enable fi } open_ports() { - # Prompt the user to enter the ports they want to open - read -rp "Enter the ports you want to open (e.g. 80,443,2053 or range 400-500): " ports + read -rp "输入要开放的端口(例如 80,443,2053 或范围 400-500): " ports - # Check if the input is valid if ! [[ $ports =~ ^([0-9]+|[0-9]+-[0-9]+)(,([0-9]+|[0-9]+-[0-9]+))*$ ]]; then - 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 + echo "错误:无效输入。请输入逗号分隔的端口列表或端口范围(例如 80,443,2053 或 400-500)。" >&2 exit 1 fi - # Open the specified ports using ufw IFS=',' read -ra PORT_LIST <<<"$ports" for port in "${PORT_LIST[@]}"; do if [[ $port == *-* ]]; then - # Split the range into start and end ports start_port=$(echo $port | cut -d'-' -f1) end_port=$(echo $port | cut -d'-' -f2) - # Open the port range ufw allow $start_port:$end_port/tcp ufw allow $start_port:$end_port/udp else - # Open the single port ufw allow "$port" fi done - # Confirm that the ports are opened - echo "Opened the specified ports:" + echo "已开放指定端口:" for port in "${PORT_LIST[@]}"; do if [[ $port == *-* ]]; then start_port=$(echo $port | cut -d'-' -f1) end_port=$(echo $port | cut -d'-' -f2) - # Check if the port range has been successfully opened (ufw status | grep -q "$start_port:$end_port") && echo "$start_port-$end_port" else - # Check if the individual port has been successfully opened (ufw status | grep -q "$port") && echo "$port" fi done } delete_ports() { - # Display current rules with numbers - echo "Current UFW rules:" + echo "当前 UFW 规则:" ufw status numbered - # Ask the user how they want to delete rules - echo "Do you want to delete rules by:" - echo "1) Rule numbers" - echo "2) Ports" - read -rp "Enter your choice (1 or 2): " choice + echo "您想如何删除规则:" + echo "1) 按规则编号" + echo "2) 按端口" + read -rp "输入选择 (1 或 2): " choice if [[ $choice -eq 1 ]]; then - # Deleting by rule numbers - read -rp "Enter the rule numbers you want to delete (1, 2, etc.): " rule_numbers + read -rp "输入要删除的规则编号 (1, 2 等): " rule_numbers - # Validate the input if ! [[ $rule_numbers =~ ^([0-9]+)(,[0-9]+)*$ ]]; then - echo "Error: Invalid input. Please enter a comma-separated list of rule numbers." >&2 + echo "错误:无效输入。请输入逗号分隔的规则编号列表。" >&2 exit 1 fi - # Split numbers into an array IFS=',' read -ra RULE_NUMBERS <<<"$rule_numbers" for rule_number in "${RULE_NUMBERS[@]}"; do - # Delete the rule by number - ufw delete "$rule_number" || echo "Failed to delete rule number $rule_number" + ufw delete "$rule_number" || echo "删除规则编号 $rule_number 失败" done - echo "Selected rules have been deleted." + echo "选定的规则已删除。" elif [[ $choice -eq 2 ]]; then - # Deleting by ports - read -rp "Enter the ports you want to delete (e.g. 80,443,2053 or range 400-500): " ports + read -rp "输入要删除的端口(例如 80,443,2053 或范围 400-500): " ports - # Validate the input if ! [[ $ports =~ ^([0-9]+|[0-9]+-[0-9]+)(,([0-9]+|[0-9]+-[0-9]+))*$ ]]; then - 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 + echo "错误:无效输入。请输入逗号分隔的端口列表或端口范围(例如 80,443,2053 或 400-500)。" >&2 exit 1 fi - # Split ports into an array IFS=',' read -ra PORT_LIST <<<"$ports" for port in "${PORT_LIST[@]}"; do if [[ $port == *-* ]]; then - # Split the port range start_port=$(echo $port | cut -d'-' -f1) end_port=$(echo $port | cut -d'-' -f2) - # Delete the port range ufw delete allow $start_port:$end_port/tcp ufw delete allow $start_port:$end_port/udp else - # Delete a single port ufw delete allow "$port" fi done - # Confirmation of deletion - echo "Deleted the specified ports:" + echo "已删除指定端口:" for port in "${PORT_LIST[@]}"; do if [[ $port == *-* ]]; then start_port=$(echo $port | cut -d'-' -f1) end_port=$(echo $port | cut -d'-' -f2) - # Check if the port range has been deleted (ufw status | grep -q "$start_port:$end_port") || echo "$start_port-$end_port" else - # Check if the individual port has been deleted (ufw status | grep -q "$port") || echo "$port" fi done else - echo "${red}Error:${plain} Invalid choice. Please enter 1 or 2." >&2 + echo "${red}错误:${plain} 无效选择。请输入 1 或 2。" >&2 exit 1 fi } @@ -930,9 +886,9 @@ update_geo() { echo -e "${green}\t1.${plain} Loyalsoldier (geoip.dat, geosite.dat)" echo -e "${green}\t2.${plain} chocolate4u (geoip_IR.dat, geosite_IR.dat)" echo -e "${green}\t3.${plain} runetfreedom (geoip_RU.dat, geosite_RU.dat)" - echo -e "${green}\t4.${plain} All" - echo -e "${green}\t0.${plain} Back to Main Menu" - read -rp "Choose an option: " choice + echo -e "${green}\t4.${plain} 全部" + echo -e "${green}\t0.${plain} 返回主菜单" + read -rp "选择选项: " choice cd ${xui_folder}/bin @@ -942,26 +898,26 @@ update_geo() { ;; 1) update_main_geofiles - echo -e "${green}Loyalsoldier datasets have been updated successfully!${plain}" + echo -e "${green}Loyalsoldier 数据集更新成功!${plain}" restart ;; 2) update_ir_geofiles - echo -e "${green}chocolate4u datasets have been updated successfully!${plain}" + echo -e "${green}chocolate4u 数据集更新成功!${plain}" restart ;; 3) update_ru_geofiles - echo -e "${green}runetfreedom datasets have been updated successfully!${plain}" + echo -e "${green}runetfreedom 数据集更新成功!${plain}" restart ;; 4) update_all_geofiles - echo -e "${green}All geo files have been updated successfully!${plain}" + echo -e "${green}所有地理文件更新成功!${plain}" restart ;; *) - echo -e "${red}Invalid option. Please select a valid number.${plain}\n" + echo -e "${red}无效选项,请选择有效数字。${plain}\n" update_geo ;; esac @@ -970,36 +926,35 @@ update_geo() { } install_acme() { - # Check if acme.sh is already installed if command -v ~/.acme.sh/acme.sh &>/dev/null; then - LOGI "acme.sh is already installed." + LOGI "acme.sh 已安装。" return 0 fi - LOGI "Installing acme.sh..." - cd ~ || return 1 # Ensure you can change to the home directory + LOGI "正在安装 acme.sh..." + cd ~ || return 1 curl -s https://get.acme.sh | sh if [ $? -ne 0 ]; then - LOGE "Installation of acme.sh failed." + LOGE "acme.sh 安装失败。" return 1 else - LOGI "Installation of acme.sh succeeded." + LOGI "acme.sh 安装成功。" fi return 0 } ssl_cert_issue_main() { - echo -e "${green}\t1.${plain} Get SSL (Domain)" - echo -e "${green}\t2.${plain} Revoke" - echo -e "${green}\t3.${plain} Force Renew" - echo -e "${green}\t4.${plain} Show Existing Domains" - echo -e "${green}\t5.${plain} Set Cert paths for the panel" - echo -e "${green}\t6.${plain} Get SSL for IP Address (6-day cert, auto-renews)" - echo -e "${green}\t0.${plain} Back to Main Menu" + echo -e "${green}\t1.${plain} 获取 SSL 证书(域名)" + echo -e "${green}\t2.${plain} 吊销证书" + echo -e "${green}\t3.${plain} 强制续期" + echo -e "${green}\t4.${plain} 显示现有域名" + echo -e "${green}\t5.${plain} 为面板设置证书路径" + echo -e "${green}\t6.${plain} 为 IP 地址获取 SSL 证书(6天证书,自动续期)" + echo -e "${green}\t0.${plain} 返回主菜单" - read -rp "Choose an option: " choice + read -rp "选择选项: " choice case "$choice" in 0) show_menu @@ -1011,16 +966,16 @@ ssl_cert_issue_main() { 2) local domains=$(find /root/cert/ -mindepth 1 -maxdepth 1 -type d -exec basename {} \;) if [ -z "$domains" ]; then - echo "No certificates found to revoke." + echo "未找到可吊销的证书。" else - echo "Existing domains:" + echo "现有域名:" echo "$domains" - read -rp "Please enter a domain from the list to revoke the certificate: " domain + read -rp "请从列表输入域名以吊销证书: " domain if echo "$domains" | grep -qw "$domain"; then ~/.acme.sh/acme.sh --revoke -d ${domain} - LOGI "Certificate revoked for domain: $domain" + LOGI "证书已吊销,域名: $domain" else - echo "Invalid domain entered." + echo "输入的域名无效。" fi fi ssl_cert_issue_main @@ -1028,16 +983,16 @@ ssl_cert_issue_main() { 3) local domains=$(find /root/cert/ -mindepth 1 -maxdepth 1 -type d -exec basename {} \;) if [ -z "$domains" ]; then - echo "No certificates found to renew." + echo "未找到可续期的证书。" else - echo "Existing domains:" + echo "现有域名:" echo "$domains" - read -rp "Please enter a domain from the list to renew the SSL certificate: " domain + read -rp "请从列表输入域名以续期 SSL 证书: " domain if echo "$domains" | grep -qw "$domain"; then ~/.acme.sh/acme.sh --renew -d ${domain} --force - LOGI "Certificate forcefully renewed for domain: $domain" + LOGI "证书强制续期成功,域名: $domain" else - echo "Invalid domain entered." + echo "输入的域名无效。" fi fi ssl_cert_issue_main @@ -1045,18 +1000,18 @@ ssl_cert_issue_main() { 4) local domains=$(find /root/cert/ -mindepth 1 -maxdepth 1 -type d -exec basename {} \;) if [ -z "$domains" ]; then - echo "No certificates found." + echo "未找到证书。" else - echo "Existing domains and their paths:" + echo "现有域名及其路径:" for domain in $domains; do local cert_path="/root/cert/${domain}/fullchain.pem" local key_path="/root/cert/${domain}/privkey.pem" if [[ -f "${cert_path}" && -f "${key_path}" ]]; then - echo -e "Domain: ${domain}" - echo -e "\tCertificate Path: ${cert_path}" - echo -e "\tPrivate Key Path: ${key_path}" + echo -e "域名: ${domain}" + echo -e "\t证书路径: ${cert_path}" + echo -e "\t私钥路径: ${key_path}" else - echo -e "Domain: ${domain} - Certificate or Key missing." + echo -e "域名: ${domain} - 证书或密钥缺失。" fi done fi @@ -1065,11 +1020,11 @@ ssl_cert_issue_main() { 5) local domains=$(find /root/cert/ -mindepth 1 -maxdepth 1 -type d -exec basename {} \;) if [ -z "$domains" ]; then - echo "No certificates found." + echo "未找到证书。" else - echo "Available domains:" + echo "可用域名:" echo "$domains" - read -rp "Please choose a domain to set the panel paths: " domain + read -rp "请选择域名设置面板路径: " domain if echo "$domains" | grep -qw "$domain"; then local webCertFile="/root/cert/${domain}/fullchain.pem" @@ -1077,25 +1032,25 @@ ssl_cert_issue_main() { if [[ -f "${webCertFile}" && -f "${webKeyFile}" ]]; then ${xui_folder}/x-ui cert -webCert "$webCertFile" -webCertKey "$webKeyFile" - echo "Panel paths set for domain: $domain" - echo " - Certificate File: $webCertFile" - echo " - Private Key File: $webKeyFile" + echo "面板路径已设置,域名: $domain" + echo " - 证书文件: $webCertFile" + echo " - 私钥文件: $webKeyFile" restart else - echo "Certificate or private key not found for domain: $domain." + echo "未找到域名的证书或私钥: $domain." fi else - echo "Invalid domain entered." + echo "输入的域名无效。" fi fi ssl_cert_issue_main ;; 6) - echo -e "${yellow}Let's Encrypt SSL Certificate for IP Address${plain}" - echo -e "This will obtain a certificate for your server's IP using the shortlived profile." - echo -e "${yellow}Certificate valid for ~6 days, auto-renews via acme.sh cron job.${plain}" - echo -e "${yellow}Port 80 must be open and accessible from the internet.${plain}" - confirm "Do you want to proceed?" "y" + echo -e "${yellow}Let's Encrypt SSL 证书(IP 地址)${plain}" + echo -e "这将为您的服务器 IP 获取证书(使用短期配置文件)。" + echo -e "${yellow}证书有效期约6天,通过 acme.sh 定时任务自动续期。${plain}" + echo -e "${yellow}端口 80 必须开放且可从互联网访问。${plain}" + confirm "是否继续?" "y" if [[ $? == 0 ]]; then ssl_cert_issue_for_ip fi @@ -1103,48 +1058,44 @@ ssl_cert_issue_main() { ;; *) - echo -e "${red}Invalid option. Please select a valid number.${plain}\n" + echo -e "${red}无效选项,请选择有效数字。${plain}\n" ssl_cert_issue_main ;; esac } ssl_cert_issue_for_ip() { - LOGI "Starting automatic SSL certificate generation for server IP..." - LOGI "Using Let's Encrypt shortlived profile (~6 days validity, auto-renews)" + LOGI "开始为服务器 IP 自动生成 SSL 证书..." + LOGI "使用 Let's Encrypt 短期配置文件(约6天有效期,自动续期)" local existing_webBasePath=$(${xui_folder}/x-ui setting -show true | grep -Eo 'webBasePath: .+' | awk '{print $2}') local existing_port=$(${xui_folder}/x-ui setting -show true | grep -Eo 'port: .+' | awk '{print $2}') - # Get server IP local server_ip=$(curl -s --max-time 3 https://api.ipify.org) if [ -z "$server_ip" ]; then server_ip=$(curl -s --max-time 3 https://4.ident.me) fi if [ -z "$server_ip" ]; then - LOGE "Failed to get server IP address" + LOGE "获取服务器 IP 地址失败" return 1 fi - LOGI "Server IP detected: ${server_ip}" + LOGI "检测到服务器 IP: ${server_ip}" - # Ask for optional IPv6 local ipv6_addr="" - read -rp "Do you have an IPv6 address to include? (leave empty to skip): " ipv6_addr - ipv6_addr="${ipv6_addr// /}" # Trim whitespace + read -rp "是否有 IPv6 地址要包含?(留空跳过): " ipv6_addr + ipv6_addr="${ipv6_addr// /}" - # check for acme.sh first if ! command -v ~/.acme.sh/acme.sh &>/dev/null; then - LOGI "acme.sh not found, installing..." + LOGI "未找到 acme.sh,正在安装..." install_acme if [ $? -ne 0 ]; then - LOGE "Failed to install acme.sh" + LOGE "安装 acme.sh 失败" return 1 fi fi - # install socat case "${release}" in ubuntu | debian | armbian) apt-get update >/dev/null 2>&1 && apt-get install socat -y >/dev/null 2>&1 @@ -1169,30 +1120,25 @@ ssl_cert_issue_for_ip() { apk add socat curl openssl >/dev/null 2>&1 ;; *) - LOGW "Unsupported OS for automatic socat installation" + LOGW "不支持自动安装 socat 的操作系统" ;; esac - # Create certificate directory certPath="/root/cert/ip" mkdir -p "$certPath" - # Build domain arguments local domain_args="-d ${server_ip}" if [[ -n "$ipv6_addr" ]] && is_ipv6 "$ipv6_addr"; then domain_args="${domain_args} -d ${ipv6_addr}" - LOGI "Including IPv6 address: ${ipv6_addr}" + LOGI "包含 IPv6 地址: ${ipv6_addr}" fi - # Use port 80 for certificate issuance local WebPort=80 - LOGI "Using port ${WebPort} to issue certificate for IP: ${server_ip}" - LOGI "Make sure port ${WebPort} is open and not in use..." + LOGI "使用端口 ${WebPort} 为 IP 签发证书: ${server_ip}" + LOGI "请确保端口 ${WebPort} 已开放且未被占用..." - # Reload command - restarts panel after renewal local reloadCmd="systemctl restart x-ui 2>/dev/null || rc-service x-ui restart 2>/dev/null" - # issue the certificate for IP with shortlived profile ~/.acme.sh/acme.sh --set-default-ca --server letsencrypt ~/.acme.sh/acme.sh --issue \ ${domain_args} \ @@ -1204,58 +1150,50 @@ ssl_cert_issue_for_ip() { --force if [ $? -ne 0 ]; then - LOGE "Failed to issue certificate for IP: ${server_ip}" - LOGE "Make sure port ${WebPort} is open and the server is accessible from the internet" - # Cleanup acme.sh data for both IPv4 and IPv6 if specified + LOGE "为 IP 签发证书失败: ${server_ip}" + LOGE "请确保端口 ${WebPort} 已开放且服务器可从互联网访问" rm -rf ~/.acme.sh/${server_ip} 2>/dev/null [[ -n "$ipv6_addr" ]] && rm -rf ~/.acme.sh/${ipv6_addr} 2>/dev/null rm -rf ${certPath} 2>/dev/null return 1 else - LOGI "Certificate issued successfully for IP: ${server_ip}" + LOGI "证书签发成功,IP: ${server_ip}" fi - # Install the certificate - # Note: acme.sh may report "Reload error" and exit non-zero if reloadcmd fails, - # but the cert files are still installed. We check for files instead of exit code. ~/.acme.sh/acme.sh --installcert -d ${server_ip} \ --key-file "${certPath}/privkey.pem" \ --fullchain-file "${certPath}/fullchain.pem" \ --reloadcmd "${reloadCmd}" 2>&1 || true - # Verify certificate files exist (don't rely on exit code - reloadcmd failure causes non-zero) if [[ ! -f "${certPath}/fullchain.pem" || ! -f "${certPath}/privkey.pem" ]]; then - LOGE "Certificate files not found after installation" - # Cleanup acme.sh data for both IPv4 and IPv6 if specified + LOGE "安装后未找到证书文件" rm -rf ~/.acme.sh/${server_ip} 2>/dev/null [[ -n "$ipv6_addr" ]] && rm -rf ~/.acme.sh/${ipv6_addr} 2>/dev/null rm -rf ${certPath} 2>/dev/null return 1 fi - LOGI "Certificate files installed successfully" + LOGI "证书文件安装成功" - # enable auto-renew ~/.acme.sh/acme.sh --upgrade --auto-upgrade >/dev/null 2>&1 chmod 600 $certPath/privkey.pem 2>/dev/null chmod 644 $certPath/fullchain.pem 2>/dev/null - # Set certificate paths for the panel local webCertFile="${certPath}/fullchain.pem" local webKeyFile="${certPath}/privkey.pem" if [[ -f "$webCertFile" && -f "$webKeyFile" ]]; then ${xui_folder}/x-ui cert -webCert "$webCertFile" -webCertKey "$webKeyFile" - LOGI "Certificate configured for panel" - LOGI " - Certificate File: $webCertFile" - LOGI " - Private Key File: $webKeyFile" - LOGI " - Validity: ~6 days (auto-renews via acme.sh cron)" - echo -e "${green}Access URL: https://${server_ip}:${existing_port}${existing_webBasePath}${plain}" - LOGI "Panel will restart to apply SSL certificate..." + LOGI "证书已为面板配置" + LOGI " - 证书文件: $webCertFile" + LOGI " - 私钥文件: $webKeyFile" + LOGI " - 有效期: 约6天(通过 acme.sh 定时任务自动续期)" + echo -e "${green}访问地址: https://${server_ip}:${existing_port}${existing_webBasePath}${plain}" + LOGI "面板将重启以应用 SSL 证书..." restart return 0 else - LOGE "Certificate files not found after installation" + LOGE "安装后未找到证书文件" return 1 fi } @@ -1263,17 +1201,15 @@ ssl_cert_issue_for_ip() { ssl_cert_issue() { local existing_webBasePath=$(${xui_folder}/x-ui setting -show true | grep -Eo 'webBasePath: .+' | awk '{print $2}') local existing_port=$(${xui_folder}/x-ui setting -show true | grep -Eo 'port: .+' | awk '{print $2}') - # check for acme.sh first if ! command -v ~/.acme.sh/acme.sh &>/dev/null; then - echo "acme.sh could not be found. we will install it" + echo "未找到 acme.sh,正在安装" install_acme if [ $? -ne 0 ]; then - LOGE "install acme failed, please check logs" + LOGE "安装 acme 失败,请检查日志" exit 1 fi fi - # install socat case "${release}" in ubuntu | debian | armbian) apt-get update >/dev/null 2>&1 && apt-get install socat -y >/dev/null 2>&1 @@ -1298,48 +1234,45 @@ ssl_cert_issue() { apk add socat curl openssl >/dev/null 2>&1 ;; *) - LOGW "Unsupported OS for automatic socat installation" + LOGW "不支持自动安装 socat 的操作系统" ;; esac if [ $? -ne 0 ]; then - LOGE "install socat failed, please check logs" + LOGE "安装 socat 失败,请检查日志" exit 1 else - LOGI "install socat succeed..." + LOGI "安装 socat 成功..." fi - # get the domain here, and we need to verify it local domain="" while true; do - read -rp "Please enter your domain name: " domain - domain="${domain// /}" # Trim whitespace + read -rp "请输入您的域名: " domain + domain="${domain// /}" if [[ -z "$domain" ]]; then - LOGE "Domain name cannot be empty. Please try again." + LOGE "域名不能为空,请重试。" continue fi if ! is_domain "$domain"; then - LOGE "Invalid domain format: ${domain}. Please enter a valid domain name." + LOGE "域名格式无效: ${domain}。请输入有效的域名。" continue fi break done - LOGD "Your domain is: ${domain}, checking it..." + LOGD "您的域名是: ${domain}, 正在检查..." - # check if there already exists a certificate local currentCert=$(~/.acme.sh/acme.sh --list | tail -1 | awk '{print $1}') if [ "${currentCert}" == "${domain}" ]; then local certInfo=$(~/.acme.sh/acme.sh --list) - LOGE "System already has certificates for this domain. Cannot issue again. Current certificate details:" + LOGE "系统已存在此域名的证书。无法再次签发。当前证书详情:" LOGI "$certInfo" exit 1 else - LOGI "Your domain is ready for issuing certificates now..." + LOGI "您的域名已准备好签发证书..." fi - # create a directory for the certificate certPath="/root/cert/${domain}" if [ ! -d "$certPath" ]; then mkdir -p "$certPath" @@ -1348,195 +1281,185 @@ ssl_cert_issue() { mkdir -p "$certPath" fi - # get the port number for the standalone server local WebPort=80 - read -rp "Please choose which port to use (default is 80): " WebPort + read -rp "请选择使用的端口(默认 80): " WebPort if [[ ${WebPort} -gt 65535 || ${WebPort} -lt 1 ]]; then - LOGE "Your input ${WebPort} is invalid, will use default port 80." + LOGE "您的输入 ${WebPort} 无效,将使用默认端口 80。" WebPort=80 fi - LOGI "Will use port: ${WebPort} to issue certificates. Please make sure this port is open." + LOGI "将使用端口: ${WebPort} 签发证书。请确保此端口开放。" - # issue the certificate ~/.acme.sh/acme.sh --set-default-ca --server letsencrypt ~/.acme.sh/acme.sh --issue -d ${domain} --listen-v6 --standalone --httpport ${WebPort} --force if [ $? -ne 0 ]; then - LOGE "Issuing certificate failed, please check logs." + LOGE "签发证书失败,请检查日志。" rm -rf ~/.acme.sh/${domain} exit 1 else - LOGE "Issuing certificate succeeded, installing certificates..." + LOGE "签发证书成功,正在安装证书..." fi reloadCmd="x-ui restart" - LOGI "Default --reloadcmd for ACME is: ${yellow}x-ui restart" - LOGI "This command will run on every certificate issue and renew." - read -rp "Would you like to modify --reloadcmd for ACME? (y/n): " setReloadcmd + LOGI "默认的 --reloadcmd 为 ACME 是: ${yellow}x-ui restart" + LOGI "此命令将在每次证书签发和续期时运行。" + read -rp "是否要为 ACME 修改 --reloadcmd?(y/n): " setReloadcmd if [[ "$setReloadcmd" == "y" || "$setReloadcmd" == "Y" ]]; then - echo -e "\n${green}\t1.${plain} Preset: systemctl reload nginx ; x-ui restart" - echo -e "${green}\t2.${plain} Input your own command" - echo -e "${green}\t0.${plain} Keep default reloadcmd" - read -rp "Choose an option: " choice + echo -e "\n${green}\t1.${plain} 预设: systemctl reload nginx ; x-ui restart" + echo -e "${green}\t2.${plain} 输入自定义命令" + echo -e "${green}\t0.${plain} 保持默认 reloadcmd" + read -rp "选择选项: " choice case "$choice" in 1) - LOGI "Reloadcmd is: systemctl reload nginx ; x-ui restart" + LOGI "Reloadcmd 为: systemctl reload nginx ; x-ui restart" reloadCmd="systemctl reload nginx ; x-ui restart" ;; 2) - LOGD "It's recommended to put x-ui restart at the end, so it won't raise an error if other services fails" - read -rp "Please enter your reloadcmd (example: systemctl reload nginx ; x-ui restart): " reloadCmd - LOGI "Your reloadcmd is: ${reloadCmd}" + LOGD "建议将 x-ui restart 放在最后,这样即使其他服务失败也不会报错" + read -rp "请输入您的 reloadcmd(示例: systemctl reload nginx ; x-ui restart): " reloadCmd + LOGI "您的 reloadcmd 为: ${reloadCmd}" ;; *) - LOGI "Keep default reloadcmd" + LOGI "保持默认 reloadcmd" ;; esac fi - # install the certificate ~/.acme.sh/acme.sh --installcert -d ${domain} \ --key-file /root/cert/${domain}/privkey.pem \ --fullchain-file /root/cert/${domain}/fullchain.pem --reloadcmd "${reloadCmd}" if [ $? -ne 0 ]; then - LOGE "Installing certificate failed, exiting." + LOGE "安装证书失败,退出。" rm -rf ~/.acme.sh/${domain} exit 1 else - LOGI "Installing certificate succeeded, enabling auto renew..." + LOGI "安装证书成功,启用自动续期..." fi - # enable auto-renew ~/.acme.sh/acme.sh --upgrade --auto-upgrade if [ $? -ne 0 ]; then - LOGE "Auto renew failed, certificate details:" + LOGE "自动续期失败,证书详情:" ls -lah cert/* chmod 600 $certPath/privkey.pem chmod 644 $certPath/fullchain.pem exit 1 else - LOGI "Auto renew succeeded, certificate details:" + LOGI "自动续期成功,证书详情:" ls -lah cert/* chmod 600 $certPath/privkey.pem chmod 644 $certPath/fullchain.pem fi - # Prompt user to set panel paths after successful certificate installation - read -rp "Would you like to set this certificate for the panel? (y/n): " setPanel + read -rp "是否要将此证书设置为面板证书?(y/n): " setPanel if [[ "$setPanel" == "y" || "$setPanel" == "Y" ]]; then local webCertFile="/root/cert/${domain}/fullchain.pem" local webKeyFile="/root/cert/${domain}/privkey.pem" if [[ -f "$webCertFile" && -f "$webKeyFile" ]]; then ${xui_folder}/x-ui cert -webCert "$webCertFile" -webCertKey "$webKeyFile" - LOGI "Panel paths set for domain: $domain" - LOGI " - Certificate File: $webCertFile" - LOGI " - Private Key File: $webKeyFile" - echo -e "${green}Access URL: https://${domain}:${existing_port}${existing_webBasePath}${plain}" + LOGI "面板路径已设置,域名: $domain" + LOGI " - 证书文件: $webCertFile" + LOGI " - 私钥文件: $webKeyFile" + echo -e "${green}访问地址: https://${domain}:${existing_port}${existing_webBasePath}${plain}" restart else - LOGE "Error: Certificate or private key file not found for domain: $domain." + LOGE "错误: 未找到域名的证书或私钥文件: $domain." fi else - LOGI "Skipping panel path setting." + LOGI "跳过面板路径设置。" fi } ssl_cert_issue_CF() { local existing_webBasePath=$(${xui_folder}/x-ui setting -show true | grep -Eo 'webBasePath: .+' | awk '{print $2}') local existing_port=$(${xui_folder}/x-ui setting -show true | grep -Eo 'port: .+' | awk '{print $2}') - LOGI "****** Instructions for Use ******" - LOGI "Follow the steps below to complete the process:" - LOGI "1. Cloudflare Registered E-mail." - LOGI "2. Cloudflare Global API Key." - LOGI "3. The Domain Name." - LOGI "4. Once the certificate is issued, you will be prompted to set the certificate for the panel (optional)." - LOGI "5. The script also supports automatic renewal of the SSL certificate after installation." + LOGI "****** 使用说明 ******" + LOGI "请按照以下步骤完成操作:" + LOGI "1. Cloudflare 注册邮箱。" + LOGI "2. Cloudflare 全局 API 密钥。" + LOGI "3. 域名。" + LOGI "4. 证书签发后,您可以选择为面板设置证书(可选)。" + LOGI "5. 脚本还支持安装后自动续期 SSL 证书。" - confirm "Do you confirm the information and wish to proceed? [y/n]" "y" + confirm "确认信息并希望继续吗?[y/n]" "y" if [ $? -eq 0 ]; then - # Check for acme.sh first if ! command -v ~/.acme.sh/acme.sh &>/dev/null; then - echo "acme.sh could not be found. We will install it." + echo "未找到 acme.sh,正在安装。" install_acme if [ $? -ne 0 ]; then - LOGE "Install acme failed, please check logs." + LOGE "安装 acme 失败,请检查日志。" exit 1 fi fi CF_Domain="" - LOGD "Please set a domain name:" - read -rp "Input your domain here: " CF_Domain - LOGD "Your domain name is set to: ${CF_Domain}" + LOGD "请设置域名:" + read -rp "在此输入您的域名: " CF_Domain + LOGD "您的域名设置为: ${CF_Domain}" - # Set up Cloudflare API details CF_GlobalKey="" CF_AccountEmail="" - LOGD "Please set the API key:" - read -rp "Input your key here: " CF_GlobalKey - LOGD "Your API key is: ${CF_GlobalKey}" + LOGD "请设置 API 密钥:" + read -rp "在此输入您的密钥: " CF_GlobalKey + LOGD "您的 API 密钥为: ${CF_GlobalKey}" - LOGD "Please set up registered email:" - read -rp "Input your email here: " CF_AccountEmail - LOGD "Your registered email address is: ${CF_AccountEmail}" + LOGD "请设置注册邮箱:" + read -rp "在此输入您的邮箱: " CF_AccountEmail + LOGD "您的注册邮箱为: ${CF_AccountEmail}" - # Set the default CA to Let's Encrypt ~/.acme.sh/acme.sh --set-default-ca --server letsencrypt if [ $? -ne 0 ]; then - LOGE "Default CA, Let'sEncrypt fail, script exiting..." + LOGE "默认 CA Let'sEncrypt 失败,脚本退出..." exit 1 fi export CF_Key="${CF_GlobalKey}" export CF_Email="${CF_AccountEmail}" - # Issue the certificate using Cloudflare DNS ~/.acme.sh/acme.sh --issue --dns dns_cf -d ${CF_Domain} -d *.${CF_Domain} --log --force if [ $? -ne 0 ]; then - LOGE "Certificate issuance failed, script exiting..." + LOGE "证书签发失败,脚本退出..." exit 1 else - LOGI "Certificate issued successfully, Installing..." + LOGI "证书签发成功,正在安装..." fi - # Install the certificate - certPath="/root/cert/${CF_Domain}" + certPath="/root/cert/${CF_Domain}" if [ -d "$certPath" ]; then rm -rf ${certPath} fi mkdir -p ${certPath} if [ $? -ne 0 ]; then - LOGE "Failed to create directory: ${certPath}" + LOGE "创建目录失败: ${certPath}" exit 1 fi reloadCmd="x-ui restart" - LOGI "Default --reloadcmd for ACME is: ${yellow}x-ui restart" - LOGI "This command will run on every certificate issue and renew." - read -rp "Would you like to modify --reloadcmd for ACME? (y/n): " setReloadcmd + LOGI "默认的 --reloadcmd 为 ACME 是: ${yellow}x-ui restart" + LOGI "此命令将在每次证书签发和续期时运行。" + read -rp "是否要为 ACME 修改 --reloadcmd?(y/n): " setReloadcmd if [[ "$setReloadcmd" == "y" || "$setReloadcmd" == "Y" ]]; then - echo -e "\n${green}\t1.${plain} Preset: systemctl reload nginx ; x-ui restart" - echo -e "${green}\t2.${plain} Input your own command" - echo -e "${green}\t0.${plain} Keep default reloadcmd" - read -rp "Choose an option: " choice + echo -e "\n${green}\t1.${plain} 预设: systemctl reload nginx ; x-ui restart" + echo -e "${green}\t2.${plain} 输入自定义命令" + echo -e "${green}\t0.${plain} 保持默认 reloadcmd" + read -rp "选择选项: " choice case "$choice" in 1) - LOGI "Reloadcmd is: systemctl reload nginx ; x-ui restart" + LOGI "Reloadcmd 为: systemctl reload nginx ; x-ui restart" reloadCmd="systemctl reload nginx ; x-ui restart" ;; 2) - LOGD "It's recommended to put x-ui restart at the end, so it won't raise an error if other services fails" - read -rp "Please enter your reloadcmd (example: systemctl reload nginx ; x-ui restart): " reloadCmd - LOGI "Your reloadcmd is: ${reloadCmd}" + LOGD "建议将 x-ui restart 放在最后,这样即使其他服务失败也不会报错" + read -rp "请输入您的 reloadcmd(示例: systemctl reload nginx ; x-ui restart): " reloadCmd + LOGI "您的 reloadcmd 为: ${reloadCmd}" ;; *) - LOGI "Keep default reloadcmd" + LOGI "保持默认 reloadcmd" ;; esac fi @@ -1545,42 +1468,40 @@ ssl_cert_issue_CF() { --fullchain-file ${certPath}/fullchain.pem --reloadcmd "${reloadCmd}" if [ $? -ne 0 ]; then - LOGE "Certificate installation failed, script exiting..." + LOGE "证书安装失败,脚本退出..." exit 1 else - LOGI "Certificate installed successfully, Turning on automatic updates..." + LOGI "证书安装成功,开启自动更新..." fi - # Enable auto-update ~/.acme.sh/acme.sh --upgrade --auto-upgrade if [ $? -ne 0 ]; then - LOGE "Auto update setup failed, script exiting..." + LOGE "自动更新设置失败,脚本退出..." exit 1 else - LOGI "The certificate is installed and auto-renewal is turned on. Specific information is as follows:" + LOGI "证书安装完成且自动续期已开启。具体信息如下:" ls -lah ${certPath}/* chmod 600 ${certPath}/privkey.pem chmod 644 ${certPath}/fullchain.pem fi - # Prompt user to set panel paths after successful certificate installation - read -rp "Would you like to set this certificate for the panel? (y/n): " setPanel + read -rp "是否要将此证书设置为面板证书?(y/n): " setPanel if [[ "$setPanel" == "y" || "$setPanel" == "Y" ]]; then local webCertFile="${certPath}/fullchain.pem" local webKeyFile="${certPath}/privkey.pem" if [[ -f "$webCertFile" && -f "$webKeyFile" ]]; then ${xui_folder}/x-ui cert -webCert "$webCertFile" -webCertKey "$webKeyFile" - LOGI "Panel paths set for domain: $CF_Domain" - LOGI " - Certificate File: $webCertFile" - LOGI " - Private Key File: $webKeyFile" - echo -e "${green}Access URL: https://${CF_Domain}:${existing_port}${existing_webBasePath}${plain}" + LOGI "面板路径已设置,域名: $CF_Domain" + LOGI " - 证书文件: $webCertFile" + LOGI " - 私钥文件: $webKeyFile" + echo -e "${green}访问地址: https://${CF_Domain}:${existing_port}${existing_webBasePath}${plain}" restart else - LOGE "Error: Certificate or private key file not found for domain: $CF_Domain." + LOGE "错误: 未找到域名的证书或私钥文件: $CF_Domain." fi else - LOGI "Skipping panel path setting." + LOGI "跳过面板路径设置。" fi else show_menu @@ -1588,15 +1509,11 @@ ssl_cert_issue_CF() { } run_speedtest() { - # Check if Speedtest is already installed if ! command -v speedtest &>/dev/null; then - # If not installed, determine installation method if command -v snap &>/dev/null; then - # Use snap to install Speedtest - echo "Installing Speedtest using snap..." + echo "使用 snap 安装 Speedtest..." snap install speedtest else - # Fallback to using package managers local pkg_manager="" local speedtest_install_script="" @@ -1615,10 +1532,10 @@ run_speedtest() { fi if [[ -z $pkg_manager ]]; then - echo "Error: Package manager not found. You may need to install Speedtest manually." + echo "错误: 未找到包管理器。您可能需要手动安装 Speedtest。" return 1 else - echo "Installing Speedtest using $pkg_manager..." + echo "使用 $pkg_manager 安装 Speedtest..." curl -s $speedtest_install_script | bash $pkg_manager install -y speedtest fi @@ -1628,32 +1545,30 @@ run_speedtest() { speedtest } - - ip_validation() { 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]))$" 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)$" } iplimit_main() { - echo -e "\n${green}\t1.${plain} Install Fail2ban and configure IP Limit" - echo -e "${green}\t2.${plain} Change Ban Duration" - echo -e "${green}\t3.${plain} Unban Everyone" - echo -e "${green}\t4.${plain} Ban Logs" - echo -e "${green}\t5.${plain} Ban an IP Address" - echo -e "${green}\t6.${plain} Unban an IP Address" - echo -e "${green}\t7.${plain} Real-Time Logs" - echo -e "${green}\t8.${plain} Service Status" - echo -e "${green}\t9.${plain} Service Restart" - echo -e "${green}\t10.${plain} Uninstall Fail2ban and IP Limit" - echo -e "${green}\t0.${plain} Back to Main Menu" - read -rp "Choose an option: " choice + echo -e "\n${green}\t1.${plain} 安装 Fail2ban 并配置 IP 限制" + echo -e "${green}\t2.${plain} 修改封禁时长" + echo -e "${green}\t3.${plain} 解封所有人" + echo -e "${green}\t4.${plain} 封禁日志" + echo -e "${green}\t5.${plain} 封禁 IP 地址" + echo -e "${green}\t6.${plain} 解封 IP 地址" + echo -e "${green}\t7.${plain} 实时日志" + echo -e "${green}\t8.${plain} 服务状态" + echo -e "${green}\t9.${plain} 服务重启" + echo -e "${green}\t10.${plain} 卸载 Fail2ban 和 IP 限制" + echo -e "${green}\t0.${plain} 返回主菜单" + read -rp "选择选项: " choice case "$choice" in 0) show_menu ;; 1) - confirm "Proceed with installation of Fail2ban & IP Limit?" "y" + confirm "继续安装 Fail2ban & IP 限制?" "y" if [[ $? == 0 ]]; then install_iplimit else @@ -1661,7 +1576,7 @@ iplimit_main() { fi ;; 2) - read -rp "Please enter new Ban Duration in Minutes [default 30]: " NUM + read -rp "请输入新的封禁时长(分钟)[默认 30]: " NUM if [[ $NUM =~ ^[0-9]+$ ]]; then create_iplimit_jails ${NUM} if [[ $release == "alpine" ]]; then @@ -1670,19 +1585,19 @@ iplimit_main() { systemctl restart fail2ban fi else - echo -e "${red}${NUM} is not a number! Please, try again.${plain}" + echo -e "${red}${NUM} 不是数字!请重试。${plain}" fi iplimit_main ;; 3) - confirm "Proceed with Unbanning everyone from IP Limit jail?" "y" + confirm "继续解封 IP 限制监狱中的所有用户?" "y" if [[ $? == 0 ]]; then fail2ban-client reload --restart --unban 3x-ipl truncate -s 0 "${iplimit_banned_log_path}" - echo -e "${green}All users Unbanned successfully.${plain}" + echo -e "${green}所有用户解封成功。${plain}" iplimit_main else - echo -e "${yellow}Cancelled.${plain}" + echo -e "${yellow}已取消。${plain}" fi iplimit_main ;; @@ -1691,24 +1606,24 @@ iplimit_main() { iplimit_main ;; 5) - read -rp "Enter the IP address you want to ban: " ban_ip + read -rp "输入要封禁的 IP 地址: " ban_ip ip_validation if [[ $ban_ip =~ $ipv4_regex || $ban_ip =~ $ipv6_regex ]]; then fail2ban-client set 3x-ipl banip "$ban_ip" - echo -e "${green}IP Address ${ban_ip} has been banned successfully.${plain}" + echo -e "${green}IP 地址 ${ban_ip} 封禁成功。${plain}" else - echo -e "${red}Invalid IP address format! Please try again.${plain}" + echo -e "${red}IP 地址格式无效!请重试。${plain}" fi iplimit_main ;; 6) - read -rp "Enter the IP address you want to unban: " unban_ip + read -rp "输入要解封的 IP 地址: " unban_ip ip_validation if [[ $unban_ip =~ $ipv4_regex || $unban_ip =~ $ipv6_regex ]]; then fail2ban-client set 3x-ipl unbanip "$unban_ip" - echo -e "${green}IP Address ${unban_ip} has been unbanned successfully.${plain}" + echo -e "${green}IP 地址 ${unban_ip} 解封成功。${plain}" else - echo -e "${red}Invalid IP address format! Please try again.${plain}" + echo -e "${red}IP 地址格式无效!请重试。${plain}" fi iplimit_main ;; @@ -1733,7 +1648,7 @@ iplimit_main() { iplimit_main ;; *) - echo -e "${red}Invalid option. Please select a valid number.${plain}\n" + echo -e "${red}无效选项,请选择有效数字。${plain}\n" iplimit_main ;; esac @@ -1741,9 +1656,8 @@ iplimit_main() { install_iplimit() { if ! command -v fail2ban-client &>/dev/null; then - echo -e "${green}Fail2ban is not installed. Installing now...!${plain}\n" + echo -e "${green}Fail2ban 未安装。正在安装...!${plain}\n" - # Check the OS and install necessary packages case "${release}" in ubuntu) apt-get update @@ -1781,41 +1695,35 @@ install_iplimit() { apk add fail2ban ;; *) - echo -e "${red}Unsupported operating system. Please check the script and install the necessary packages manually.${plain}\n" + echo -e "${red}不支持的操作系统。请手动检查脚本并安装必要包。${plain}\n" exit 1 ;; esac if ! command -v fail2ban-client &>/dev/null; then - echo -e "${red}Fail2ban installation failed.${plain}\n" + echo -e "${red}Fail2ban 安装失败。${plain}\n" exit 1 fi - echo -e "${green}Fail2ban installed successfully!${plain}\n" + echo -e "${green}Fail2ban 安装成功!${plain}\n" else - echo -e "${yellow}Fail2ban is already installed.${plain}\n" + echo -e "${yellow}Fail2ban 已安装。${plain}\n" fi - echo -e "${green}Configuring IP Limit...${plain}\n" + echo -e "${green}正在配置 IP 限制...${plain}\n" - # make sure there's no conflict for jail files iplimit_remove_conflicts - # Check if log file exists if ! test -f "${iplimit_banned_log_path}"; then touch ${iplimit_banned_log_path} fi - # Check if service log file exists so fail2ban won't return error if ! test -f "${iplimit_log_path}"; then touch ${iplimit_log_path} fi - # Create the iplimit jail files - # we didn't pass the bantime here to use the default value create_iplimit_jails - # Launching fail2ban if [[ $release == "alpine" ]]; then if [[ $(rc-service fail2ban status | grep -F 'status: started' -c) == 0 ]]; then rc-service fail2ban start @@ -1832,15 +1740,15 @@ install_iplimit() { systemctl enable fail2ban fi - echo -e "${green}IP Limit installed and configured successfully!${plain}\n" + echo -e "${green}IP 限制安装和配置成功!${plain}\n" before_show_menu } remove_iplimit() { - echo -e "${green}\t1.${plain} Only remove IP Limit configurations" - echo -e "${green}\t2.${plain} Uninstall Fail2ban and IP Limit" - echo -e "${green}\t0.${plain} Back to Main Menu" - read -rp "Choose an option: " num + echo -e "${green}\t1.${plain} 仅移除 IP 限制配置" + echo -e "${green}\t2.${plain} 卸载 Fail2ban 和 IP 限制" + echo -e "${green}\t0.${plain} 返回主菜单" + read -rp "选择选项: " num case "$num" in 1) rm -f /etc/fail2ban/filter.d/3x-ipl.conf @@ -1851,7 +1759,7 @@ remove_iplimit() { else systemctl restart fail2ban fi - echo -e "${green}IP Limit removed successfully!${plain}\n" + echo -e "${green}IP 限制移除成功!${plain}\n" before_show_menu ;; 2) @@ -1887,18 +1795,18 @@ remove_iplimit() { apk del fail2ban ;; *) - echo -e "${red}Unsupported operating system. Please uninstall Fail2ban manually.${plain}\n" + echo -e "${red}不支持的操作系统。请手动卸载 Fail2ban。${plain}\n" exit 1 ;; esac - echo -e "${green}Fail2ban and IP Limit removed successfully!${plain}\n" + echo -e "${green}Fail2ban 和 IP 限制移除成功!${plain}\n" before_show_menu ;; 0) show_menu ;; *) - echo -e "${red}Invalid option. Please select a valid number.${plain}\n" + echo -e "${red}无效选项,请选择有效数字。${plain}\n" remove_iplimit ;; esac @@ -1907,49 +1815,46 @@ remove_iplimit() { show_banlog() { local system_log="/var/log/fail2ban.log" - echo -e "${green}Checking ban logs...${plain}\n" + echo -e "${green}正在检查封禁日志...${plain}\n" if [[ $release == "alpine" ]]; then if [[ $(rc-service fail2ban status | grep -F 'status: started' -c) == 0 ]]; then - echo -e "${red}Fail2ban service is not running!${plain}\n" + echo -e "${red}Fail2ban 服务未运行!${plain}\n" return 1 fi else if ! systemctl is-active --quiet fail2ban; then - echo -e "${red}Fail2ban service is not running!${plain}\n" + echo -e "${red}Fail2ban 服务未运行!${plain}\n" return 1 fi fi if [[ -f "$system_log" ]]; then - echo -e "${green}Recent system ban activities from fail2ban.log:${plain}" - grep "3x-ipl" "$system_log" | grep -E "Ban|Unban" | tail -n 10 || echo -e "${yellow}No recent system ban activities found${plain}" + echo -e "${green}最近系统封禁活动(来自 fail2ban.log):${plain}" + grep "3x-ipl" "$system_log" | grep -E "Ban|Unban" | tail -n 10 || echo -e "${yellow}未找到最近的系统封禁活动${plain}" echo "" fi if [[ -f "${iplimit_banned_log_path}" ]]; then - echo -e "${green}3X-IPL ban log entries:${plain}" + echo -e "${green}3X-IPL 封禁日志条目:${plain}" if [[ -s "${iplimit_banned_log_path}" ]]; then - grep -v "INIT" "${iplimit_banned_log_path}" | tail -n 10 || echo -e "${yellow}No ban entries found${plain}" + grep -v "INIT" "${iplimit_banned_log_path}" | tail -n 10 || echo -e "${yellow}未找到封禁条目${plain}" else - echo -e "${yellow}Ban log file is empty${plain}" + echo -e "${yellow}封禁日志文件为空${plain}" fi else - echo -e "${red}Ban log file not found at: ${iplimit_banned_log_path}${plain}" + echo -e "${red}封禁日志文件未找到: ${iplimit_banned_log_path}${plain}" fi - echo -e "\n${green}Current jail status:${plain}" - fail2ban-client status 3x-ipl || echo -e "${yellow}Unable to get jail status${plain}" + echo -e "\n${green}当前监狱状态:${plain}" + fail2ban-client status 3x-ipl || echo -e "${yellow}无法获取监狱状态${plain}" } create_iplimit_jails() { - # Use default bantime if not passed => 30 minutes local bantime="${1:-30}" - # Uncomment 'allowipv6 = auto' in fail2ban.conf sed -i 's/#allowipv6 = auto/allowipv6 = auto/g' /etc/fail2ban/fail2ban.conf - # On Debian 12+ fail2ban's default backend should be changed to systemd if [[ "${release}" == "debian" && ${os_version} -ge 12 ]]; then sed -i '0,/action =/s/backend = auto/backend = systemd/' /etc/fail2ban/jail.conf fi @@ -2000,7 +1905,7 @@ protocol = tcp chain = INPUT EOF - echo -e "${green}Ip Limit jail files created with a bantime of ${bantime} minutes.${plain}" + echo -e "${green}IP 限制监狱文件已创建,封禁时长 ${bantime} 分钟。${plain}" } iplimit_remove_conflicts() { @@ -2010,10 +1915,9 @@ iplimit_remove_conflicts() { ) for file in "${jail_files[@]}"; do - # Check for [3x-ipl] config in jail file then remove it if test -f "${file}" && grep -qw '3x-ipl' ${file}; then sed -i "/\[3x-ipl\]/,/^$/d" ${file} - echo -e "${yellow}Removing conflicts of [3x-ipl] in jail (${file})!${plain}\n" + echo -e "${yellow}移除监狱中的 [3x-ipl] 冲突 (${file})!${plain}\n" fi done } @@ -2021,11 +1925,11 @@ iplimit_remove_conflicts() { SSH_port_forwarding() { local URL_lists=( "https://api4.ipify.org" - "https://ipv4.icanhazip.com" - "https://v4.api.ipinfo.io/ip" - "https://ipv4.myexternalip.com/raw" - "https://4.ident.me" - "https://check-host.net/ip" + "https://ipv4.icanhazip.com" + "https://v4.api.ipinfo.io/ip" + "https://ipv4.myexternalip.com/raw" + "https://4.ident.me" + "https://check-host.net/ip" ) local server_ip="" for ip_address in "${URL_lists[@]}"; do @@ -2044,66 +1948,66 @@ SSH_port_forwarding() { local listen_choice="" if [[ -n "$existing_cert" && -n "$existing_key" ]]; then - echo -e "${green}Panel is secure with SSL.${plain}" + echo -e "${green}面板已通过 SSL 保护。${plain}" before_show_menu fi if [[ -z "$existing_cert" && -z "$existing_key" && (-z "$existing_listenIP" || "$existing_listenIP" == "0.0.0.0") ]]; then - echo -e "\n${red}Warning: No Cert and Key found! The panel is not secure.${plain}" - echo "Please obtain a certificate or set up SSH port forwarding." + echo -e "\n${red}警告:未找到证书和密钥!面板不安全。${plain}" + echo "请获取证书或设置 SSH 端口转发。" fi if [[ -n "$existing_listenIP" && "$existing_listenIP" != "0.0.0.0" && (-z "$existing_cert" && -z "$existing_key") ]]; then - echo -e "\n${green}Current SSH Port Forwarding Configuration:${plain}" - echo -e "Standard SSH command:" + echo -e "\n${green}当前 SSH 端口转发配置:${plain}" + echo -e "标准 SSH 命令:" echo -e "${yellow}ssh -L 2222:${existing_listenIP}:${existing_port} root@${server_ip}${plain}" - echo -e "\nIf using SSH key:" + echo -e "\n如果使用 SSH 密钥:" echo -e "${yellow}ssh -i -L 2222:${existing_listenIP}:${existing_port} root@${server_ip}${plain}" - echo -e "\nAfter connecting, access the panel at:" + echo -e "\n连接后,访问面板地址:" echo -e "${yellow}http://localhost:2222${existing_webBasePath}${plain}" fi - echo -e "\nChoose an option:" - echo -e "${green}1.${plain} Set listen IP" - echo -e "${green}2.${plain} Clear listen IP" - echo -e "${green}0.${plain} Back to Main Menu" - read -rp "Choose an option: " num + echo -e "\n选择选项:" + echo -e "${green}1.${plain} 设置监听 IP" + echo -e "${green}2.${plain} 清除监听 IP" + echo -e "${green}0.${plain} 返回主菜单" + read -rp "选择选项: " num case "$num" in 1) if [[ -z "$existing_listenIP" || "$existing_listenIP" == "0.0.0.0" ]]; then - echo -e "\nNo listenIP configured. Choose an option:" - echo -e "1. Use default IP (127.0.0.1)" - echo -e "2. Set a custom IP" - read -rp "Select an option (1 or 2): " listen_choice + echo -e "\n未配置监听 IP。选择选项:" + echo -e "1. 使用默认 IP (127.0.0.1)" + echo -e "2. 设置自定义 IP" + read -rp "选择选项 (1 或 2): " listen_choice config_listenIP="127.0.0.1" - [[ "$listen_choice" == "2" ]] && read -rp "Enter custom IP to listen on: " config_listenIP + [[ "$listen_choice" == "2" ]] && read -rp "输入要监听的 IP: " config_listenIP ${xui_folder}/x-ui setting -listenIP "${config_listenIP}" >/dev/null 2>&1 - echo -e "${green}listen IP has been set to ${config_listenIP}.${plain}" - echo -e "\n${green}SSH Port Forwarding Configuration:${plain}" - echo -e "Standard SSH command:" + echo -e "${green}监听 IP 已设置为 ${config_listenIP}。${plain}" + echo -e "\n${green}SSH 端口转发配置:${plain}" + echo -e "标准 SSH 命令:" echo -e "${yellow}ssh -L 2222:${config_listenIP}:${existing_port} root@${server_ip}${plain}" - echo -e "\nIf using SSH key:" + echo -e "\n如果使用 SSH 密钥:" echo -e "${yellow}ssh -i -L 2222:${config_listenIP}:${existing_port} root@${server_ip}${plain}" - echo -e "\nAfter connecting, access the panel at:" + echo -e "\n连接后,访问面板地址:" echo -e "${yellow}http://localhost:2222${existing_webBasePath}${plain}" restart else config_listenIP="${existing_listenIP}" - echo -e "${green}Current listen IP is already set to ${config_listenIP}.${plain}" + echo -e "${green}当前监听 IP 已设置为 ${config_listenIP}。${plain}" fi ;; 2) ${xui_folder}/x-ui setting -listenIP 0.0.0.0 >/dev/null 2>&1 - echo -e "${green}Listen IP has been cleared.${plain}" + echo -e "${green}监听 IP 已清除。${plain}" restart ;; 0) show_menu ;; *) - echo -e "${red}Invalid option. Please select a valid number.${plain}\n" + echo -e "${red}无效选项,请选择有效数字。${plain}\n" SSH_port_forwarding ;; esac @@ -2111,66 +2015,66 @@ SSH_port_forwarding() { show_usage() { echo -e "┌────────────────────────────────────────────────────────────────┐ -│ ${blue}x-ui control menu usages (subcommands):${plain} │ +│ ${blue}x-ui 控制菜单用法(子命令):${plain} │ │ │ -│ ${blue}x-ui${plain} - Admin Management Script │ -│ ${blue}x-ui start${plain} - Start │ -│ ${blue}x-ui stop${plain} - Stop │ -│ ${blue}x-ui restart${plain} - Restart │ -│ ${blue}x-ui status${plain} - Current Status │ -│ ${blue}x-ui settings${plain} - Current Settings │ -│ ${blue}x-ui enable${plain} - Enable Autostart on OS Startup │ -│ ${blue}x-ui disable${plain} - Disable Autostart on OS Startup │ -│ ${blue}x-ui log${plain} - Check logs │ -│ ${blue}x-ui banlog${plain} - Check Fail2ban ban logs │ -│ ${blue}x-ui update${plain} - Update │ -│ ${blue}x-ui update-all-geofiles${plain} - Update all geo files │ -│ ${blue}x-ui legacy${plain} - Legacy version │ -│ ${blue}x-ui install${plain} - Install │ -│ ${blue}x-ui uninstall${plain} - Uninstall │ +│ ${blue}x-ui${plain} - 管理脚本 │ +│ ${blue}x-ui start${plain} - 启动 │ +│ ${blue}x-ui stop${plain} - 停止 │ +│ ${blue}x-ui restart${plain} - 重启 │ +│ ${blue}x-ui status${plain} - 当前状态 │ +│ ${blue}x-ui settings${plain} - 当前设置 │ +│ ${blue}x-ui enable${plain} - 开机自启 │ +│ ${blue}x-ui disable${plain} - 取消开机自启 │ +│ ${blue}x-ui log${plain} - 查看日志 │ +│ ${blue}x-ui banlog${plain} - 查看 Fail2ban 封禁日志 │ +│ ${blue}x-ui update${plain} - 更新 │ +│ ${blue}x-ui update-all-geofiles${plain} - 更新所有地理文件 │ +│ ${blue}x-ui legacy${plain} - 旧版本 │ +│ ${blue}x-ui install${plain} - 安装 │ +│ ${blue}x-ui uninstall${plain} - 卸载 │ └────────────────────────────────────────────────────────────────┘" } show_menu() { echo -e " ╔────────────────────────────────────────────────╗ -│ ${green}3X-UI Panel Management Script${plain} │ -│ ${green}0.${plain} Exit Script │ +│ ${green}3X-UI 面板管理脚本(中文版)${plain} │ +│ ${green}0.${plain} 退出脚本 │ │────────────────────────────────────────────────│ -│ ${green}1.${plain} Install │ -│ ${green}2.${plain} Update │ -│ ${green}3.${plain} Update Menu │ -│ ${green}4.${plain} Legacy Version │ -│ ${green}5.${plain} Uninstall │ +│ ${green}1.${plain} 安装面板 │ +│ ${green}2.${plain} 更新面板 │ +│ ${green}3.${plain} 更新菜单脚本 │ +│ ${green}4.${plain} 安装旧版本 │ +│ ${green}5.${plain} 卸载面板 │ │────────────────────────────────────────────────│ -│ ${green}6.${plain} Reset Username & Password │ -│ ${green}7.${plain} Reset Web Base Path │ -│ ${green}8.${plain} Reset Settings │ -│ ${green}9.${plain} Change Port │ -│ ${green}10.${plain} View Current Settings │ +│ ${green}6.${plain} 重置用户名和密码 │ +│ ${green}7.${plain} 重置 Web 访问路径 │ +│ ${green}8.${plain} 重置面板设置 │ +│ ${green}9.${plain} 修改面板端口 │ +│ ${green}10.${plain} 查看当前设置 │ │────────────────────────────────────────────────│ -│ ${green}11.${plain} Start │ -│ ${green}12.${plain} Stop │ -│ ${green}13.${plain} Restart │ -│ ${green}14.${plain} Check Status │ -│ ${green}15.${plain} Logs Management │ +│ ${green}11.${plain} 启动面板 │ +│ ${green}12.${plain} 停止面板 │ +│ ${green}13.${plain} 重启面板 │ +│ ${green}14.${plain} 查看面板状态 │ +│ ${green}15.${plain} 日志管理 │ │────────────────────────────────────────────────│ -│ ${green}16.${plain} Enable Autostart │ -│ ${green}17.${plain} Disable Autostart │ +│ ${green}16.${plain} 设置开机自启 │ +│ ${green}17.${plain} 取消开机自启 │ │────────────────────────────────────────────────│ -│ ${green}18.${plain} SSL Certificate Management │ -│ ${green}19.${plain} Cloudflare SSL Certificate │ -│ ${green}20.${plain} IP Limit Management │ -│ ${green}21.${plain} Firewall Management │ -│ ${green}22.${plain} SSH Port Forwarding Management │ +│ ${green}18.${plain} SSL 证书管理 │ +│ ${green}19.${plain} Cloudflare SSL 证书 │ +│ ${green}20.${plain} IP 限制管理 │ +│ ${green}21.${plain} 防火墙管理 │ +│ ${green}22.${plain} SSH 端口转发管理 │ │────────────────────────────────────────────────│ -│ ${green}23.${plain} Enable BBR │ -│ ${green}24.${plain} Update Geo Files │ -│ ${green}25.${plain} Speedtest by Ookla │ +│ ${green}23.${plain} 启用 BBR │ +│ ${green}24.${plain} 更新 GEO 数据库 │ +│ ${green}25.${plain} 网络速度测试 │ ╚────────────────────────────────────────────────╝ " show_status - echo && read -rp "Please enter your selection [0-25]: " num + echo && read -rp "请输入您的选择 [0-25]: " num case "${num}" in 0) @@ -2252,7 +2156,7 @@ show_menu() { run_speedtest ;; *) - LOGE "Please enter the correct number [0-25]" + LOGE "请输入正确的数字 [0-25]" ;; esac }