diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 0dd4847d..44f0d2ba 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -25,7 +25,7 @@ jobs: with: images: | hsanaeii/3x-ui - ghcr.io/mhsanaei/3x-ui + ghcr.io/Sora39831/3x-ui tags: | type=ref,event=branch type=ref,event=tag diff --git a/README.ar_EG.md b/README.ar_EG.md index 01acad34..83a0b38d 100644 --- a/README.ar_EG.md +++ b/README.ar_EG.md @@ -7,13 +7,13 @@

-[![Release](https://img.shields.io/github/v/release/mhsanaei/3x-ui.svg)](https://github.com/MHSanaei/3x-ui/releases) -[![Build](https://img.shields.io/github/actions/workflow/status/mhsanaei/3x-ui/release.yml.svg)](https://github.com/MHSanaei/3x-ui/actions) -[![GO Version](https://img.shields.io/github/go-mod/go-version/mhsanaei/3x-ui.svg)](#) -[![Downloads](https://img.shields.io/github/downloads/mhsanaei/3x-ui/total.svg)](https://github.com/MHSanaei/3x-ui/releases/latest) +[![Release](https://img.shields.io/github/v/release/Sora39831/3x-ui.svg)](https://github.com/Sora39831/3x-ui/releases) +[![Build](https://img.shields.io/github/actions/workflow/status/Sora39831/3x-ui/release.yml.svg)](https://github.com/Sora39831/3x-ui/actions) +[![GO Version](https://img.shields.io/github/go-mod/go-version/Sora39831/3x-ui.svg)](#) +[![Downloads](https://img.shields.io/github/downloads/Sora39831/3x-ui/total.svg)](https://github.com/Sora39831/3x-ui/releases/latest) [![License](https://img.shields.io/badge/license-GPL%20V3-blue.svg?longCache=true)](https://www.gnu.org/licenses/gpl-3.0.en.html) -[![Go Reference](https://pkg.go.dev/badge/github.com/mhsanaei/3x-ui/v2.svg)](https://pkg.go.dev/github.com/mhsanaei/3x-ui/v2) -[![Go Report Card](https://goreportcard.com/badge/github.com/mhsanaei/3x-ui/v2)](https://goreportcard.com/report/github.com/mhsanaei/3x-ui/v2) +[![Go Reference](https://pkg.go.dev/badge/github.com/Sora39831/3x-ui/v2.svg)](https://pkg.go.dev/github.com/Sora39831/3x-ui/v2) +[![Go Report Card](https://goreportcard.com/badge/github.com/Sora39831/3x-ui/v2)](https://goreportcard.com/report/github.com/Sora39831/3x-ui/v2) **3X-UI** — لوحة تحكم متقدمة مفتوحة المصدر تعتمد على الويب مصممة لإدارة خادم Xray-core. توفر واجهة سهلة الاستخدام لتكوين ومراقبة بروتوكولات VPN والوكيل المختلفة. @@ -25,10 +25,10 @@ ## البدء السريع ``` -bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) +bash <(curl -Ls https://raw.githubusercontent.com/Sora39831/3x-ui/master/install.sh) ``` -للحصول على الوثائق الكاملة، يرجى زيارة [ويكي المشروع](https://github.com/MHSanaei/3x-ui/wiki). +للحصول على الوثائق الكاملة، يرجى زيارة [ويكي المشروع](https://github.com/Sora39831/3x-ui/wiki). ## شكر خاص إلى @@ -53,4 +53,4 @@ bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install. ## النجوم عبر الزمن -[![Stargazers over time](https://starchart.cc/MHSanaei/3x-ui.svg?variant=adaptive)](https://starchart.cc/MHSanaei/3x-ui) +[![Stargazers over time](https://starchart.cc/Sora39831/3x-ui.svg?variant=adaptive)](https://starchart.cc/Sora39831/3x-ui) diff --git a/README.es_ES.md b/README.es_ES.md index 63d6ce49..5958c0ed 100644 --- a/README.es_ES.md +++ b/README.es_ES.md @@ -7,13 +7,13 @@

-[![Release](https://img.shields.io/github/v/release/mhsanaei/3x-ui.svg)](https://github.com/MHSanaei/3x-ui/releases) -[![Build](https://img.shields.io/github/actions/workflow/status/mhsanaei/3x-ui/release.yml.svg)](https://github.com/MHSanaei/3x-ui/actions) -[![GO Version](https://img.shields.io/github/go-mod/go-version/mhsanaei/3x-ui.svg)](#) -[![Downloads](https://img.shields.io/github/downloads/mhsanaei/3x-ui/total.svg)](https://github.com/MHSanaei/3x-ui/releases/latest) +[![Release](https://img.shields.io/github/v/release/Sora39831/3x-ui.svg)](https://github.com/Sora39831/3x-ui/releases) +[![Build](https://img.shields.io/github/actions/workflow/status/Sora39831/3x-ui/release.yml.svg)](https://github.com/Sora39831/3x-ui/actions) +[![GO Version](https://img.shields.io/github/go-mod/go-version/Sora39831/3x-ui.svg)](#) +[![Downloads](https://img.shields.io/github/downloads/Sora39831/3x-ui/total.svg)](https://github.com/Sora39831/3x-ui/releases/latest) [![License](https://img.shields.io/badge/license-GPL%20V3-blue.svg?longCache=true)](https://www.gnu.org/licenses/gpl-3.0.en.html) -[![Go Reference](https://pkg.go.dev/badge/github.com/mhsanaei/3x-ui/v2.svg)](https://pkg.go.dev/github.com/mhsanaei/3x-ui/v2) -[![Go Report Card](https://goreportcard.com/badge/github.com/mhsanaei/3x-ui/v2)](https://goreportcard.com/report/github.com/mhsanaei/3x-ui/v2) +[![Go Reference](https://pkg.go.dev/badge/github.com/Sora39831/3x-ui/v2.svg)](https://pkg.go.dev/github.com/Sora39831/3x-ui/v2) +[![Go Report Card](https://goreportcard.com/badge/github.com/Sora39831/3x-ui/v2)](https://goreportcard.com/report/github.com/Sora39831/3x-ui/v2) **3X-UI** — panel de control avanzado basado en web de código abierto diseñado para gestionar el servidor Xray-core. Ofrece una interfaz fácil de usar para configurar y monitorear varios protocolos VPN y proxy. @@ -25,10 +25,10 @@ Como una versión mejorada del proyecto X-UI original, 3X-UI proporciona mayor e ## Inicio Rápido ``` -bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) +bash <(curl -Ls https://raw.githubusercontent.com/Sora39831/3x-ui/master/install.sh) ``` -Para documentación completa, visita la [Wiki del proyecto](https://github.com/MHSanaei/3x-ui/wiki). +Para documentación completa, visita la [Wiki del proyecto](https://github.com/Sora39831/3x-ui/wiki). ## Un Agradecimiento Especial a @@ -54,4 +54,4 @@ Para documentación completa, visita la [Wiki del proyecto](https://github.com/M ## Estrellas a lo Largo del Tiempo -[![Stargazers over time](https://starchart.cc/MHSanaei/3x-ui.svg?variant=adaptive)](https://starchart.cc/MHSanaei/3x-ui) +[![Stargazers over time](https://starchart.cc/Sora39831/3x-ui.svg?variant=adaptive)](https://starchart.cc/Sora39831/3x-ui) diff --git a/README.fa_IR.md b/README.fa_IR.md index 94165260..592165f1 100644 --- a/README.fa_IR.md +++ b/README.fa_IR.md @@ -7,13 +7,13 @@

-[![Release](https://img.shields.io/github/v/release/mhsanaei/3x-ui.svg)](https://github.com/MHSanaei/3x-ui/releases) -[![Build](https://img.shields.io/github/actions/workflow/status/mhsanaei/3x-ui/release.yml.svg)](https://github.com/MHSanaei/3x-ui/actions) -[![GO Version](https://img.shields.io/github/go-mod/go-version/mhsanaei/3x-ui.svg)](#) -[![Downloads](https://img.shields.io/github/downloads/mhsanaei/3x-ui/total.svg)](https://github.com/MHSanaei/3x-ui/releases/latest) +[![Release](https://img.shields.io/github/v/release/Sora39831/3x-ui.svg)](https://github.com/Sora39831/3x-ui/releases) +[![Build](https://img.shields.io/github/actions/workflow/status/Sora39831/3x-ui/release.yml.svg)](https://github.com/Sora39831/3x-ui/actions) +[![GO Version](https://img.shields.io/github/go-mod/go-version/Sora39831/3x-ui.svg)](#) +[![Downloads](https://img.shields.io/github/downloads/Sora39831/3x-ui/total.svg)](https://github.com/Sora39831/3x-ui/releases/latest) [![License](https://img.shields.io/badge/license-GPL%20V3-blue.svg?longCache=true)](https://www.gnu.org/licenses/gpl-3.0.en.html) -[![Go Reference](https://pkg.go.dev/badge/github.com/mhsanaei/3x-ui/v2.svg)](https://pkg.go.dev/github.com/mhsanaei/3x-ui/v2) -[![Go Report Card](https://goreportcard.com/badge/github.com/mhsanaei/3x-ui/v2)](https://goreportcard.com/report/github.com/mhsanaei/3x-ui/v2) +[![Go Reference](https://pkg.go.dev/badge/github.com/Sora39831/3x-ui/v2.svg)](https://pkg.go.dev/github.com/Sora39831/3x-ui/v2) +[![Go Report Card](https://goreportcard.com/badge/github.com/Sora39831/3x-ui/v2)](https://goreportcard.com/report/github.com/Sora39831/3x-ui/v2) **3X-UI** — یک پنل کنترل پیشرفته مبتنی بر وب با کد باز که برای مدیریت سرور Xray-core طراحی شده است. این پنل یک رابط کاربری آسان برای پیکربندی و نظارت بر پروتکل‌های مختلف VPN و پراکسی ارائه می‌دهد. @@ -25,10 +25,10 @@ ## شروع سریع ``` -bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) +bash <(curl -Ls https://raw.githubusercontent.com/Sora39831/3x-ui/master/install.sh) ``` -برای مستندات کامل، لطفاً به [ویکی پروژه](https://github.com/MHSanaei/3x-ui/wiki) مراجعه کنید. +برای مستندات کامل، لطفاً به [ویکی پروژه](https://github.com/Sora39831/3x-ui/wiki) مراجعه کنید. ## تشکر ویژه از @@ -54,4 +54,4 @@ bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install. ## ستاره‌ها در طول زمان -[![Stargazers over time](https://starchart.cc/MHSanaei/3x-ui.svg?variant=adaptive)](https://starchart.cc/MHSanaei/3x-ui) +[![Stargazers over time](https://starchart.cc/Sora39831/3x-ui.svg?variant=adaptive)](https://starchart.cc/Sora39831/3x-ui) diff --git a/README.md b/README.md index f00a2fb0..45e87ad4 100644 --- a/README.md +++ b/README.md @@ -7,13 +7,13 @@

-[![Release](https://img.shields.io/github/v/release/mhsanaei/3x-ui.svg)](https://github.com/MHSanaei/3x-ui/releases) -[![Build](https://img.shields.io/github/actions/workflow/status/mhsanaei/3x-ui/release.yml.svg)](https://github.com/MHSanaei/3x-ui/actions) -[![GO Version](https://img.shields.io/github/go-mod/go-version/mhsanaei/3x-ui.svg)](#) -[![Downloads](https://img.shields.io/github/downloads/mhsanaei/3x-ui/total.svg)](https://github.com/MHSanaei/3x-ui/releases/latest) +[![Release](https://img.shields.io/github/v/release/Sora39831/3x-ui.svg)](https://github.com/Sora39831/3x-ui/releases) +[![Build](https://img.shields.io/github/actions/workflow/status/Sora39831/3x-ui/release.yml.svg)](https://github.com/Sora39831/3x-ui/actions) +[![GO Version](https://img.shields.io/github/go-mod/go-version/Sora39831/3x-ui.svg)](#) +[![Downloads](https://img.shields.io/github/downloads/Sora39831/3x-ui/total.svg)](https://github.com/Sora39831/3x-ui/releases/latest) [![License](https://img.shields.io/badge/license-GPL%20V3-blue.svg?longCache=true)](https://www.gnu.org/licenses/gpl-3.0.en.html) -[![Go Reference](https://pkg.go.dev/badge/github.com/mhsanaei/3x-ui/v2.svg)](https://pkg.go.dev/github.com/mhsanaei/3x-ui/v2) -[![Go Report Card](https://goreportcard.com/badge/github.com/mhsanaei/3x-ui/v2)](https://goreportcard.com/report/github.com/mhsanaei/3x-ui/v2) +[![Go Reference](https://pkg.go.dev/badge/github.com/Sora39831/3x-ui/v2.svg)](https://pkg.go.dev/github.com/Sora39831/3x-ui/v2) +[![Go Report Card](https://goreportcard.com/badge/github.com/Sora39831/3x-ui/v2)](https://goreportcard.com/report/github.com/Sora39831/3x-ui/v2) **3X-UI** — advanced, open-source web-based control panel designed for managing Xray-core server. It offers a user-friendly interface for configuring and monitoring various VPN and proxy protocols. @@ -25,10 +25,10 @@ As an enhanced fork of the original X-UI project, 3X-UI provides improved stabil ## Quick Start ```bash -bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) +bash <(curl -Ls https://raw.githubusercontent.com/Sora39831/3x-ui/master/install.sh) ``` -For full documentation, please visit the [project Wiki](https://github.com/MHSanaei/3x-ui/wiki). +For full documentation, please visit the [project Wiki](https://github.com/Sora39831/3x-ui/wiki). ## A Special Thanks to @@ -54,4 +54,4 @@ For full documentation, please visit the [project Wiki](https://github.com/MHSan ## Stargazers over Time -[![Stargazers over time](https://starchart.cc/MHSanaei/3x-ui.svg?variant=adaptive)](https://starchart.cc/MHSanaei/3x-ui) +[![Stargazers over time](https://starchart.cc/Sora39831/3x-ui.svg?variant=adaptive)](https://starchart.cc/Sora39831/3x-ui) diff --git a/README.ru_RU.md b/README.ru_RU.md index 6623a801..e5772fab 100644 --- a/README.ru_RU.md +++ b/README.ru_RU.md @@ -7,13 +7,13 @@

-[![Release](https://img.shields.io/github/v/release/mhsanaei/3x-ui.svg)](https://github.com/MHSanaei/3x-ui/releases) -[![Build](https://img.shields.io/github/actions/workflow/status/mhsanaei/3x-ui/release.yml.svg)](https://github.com/MHSanaei/3x-ui/actions) -[![GO Version](https://img.shields.io/github/go-mod/go-version/mhsanaei/3x-ui.svg)](#) -[![Downloads](https://img.shields.io/github/downloads/mhsanaei/3x-ui/total.svg)](https://github.com/MHSanaei/3x-ui/releases/latest) +[![Release](https://img.shields.io/github/v/release/Sora39831/3x-ui.svg)](https://github.com/Sora39831/3x-ui/releases) +[![Build](https://img.shields.io/github/actions/workflow/status/Sora39831/3x-ui/release.yml.svg)](https://github.com/Sora39831/3x-ui/actions) +[![GO Version](https://img.shields.io/github/go-mod/go-version/Sora39831/3x-ui.svg)](#) +[![Downloads](https://img.shields.io/github/downloads/Sora39831/3x-ui/total.svg)](https://github.com/Sora39831/3x-ui/releases/latest) [![License](https://img.shields.io/badge/license-GPL%20V3-blue.svg?longCache=true)](https://www.gnu.org/licenses/gpl-3.0.en.html) -[![Go Reference](https://pkg.go.dev/badge/github.com/mhsanaei/3x-ui/v2.svg)](https://pkg.go.dev/github.com/mhsanaei/3x-ui/v2) -[![Go Report Card](https://goreportcard.com/badge/github.com/mhsanaei/3x-ui/v2)](https://goreportcard.com/report/github.com/mhsanaei/3x-ui/v2) +[![Go Reference](https://pkg.go.dev/badge/github.com/Sora39831/3x-ui/v2.svg)](https://pkg.go.dev/github.com/Sora39831/3x-ui/v2) +[![Go Report Card](https://goreportcard.com/badge/github.com/Sora39831/3x-ui/v2)](https://goreportcard.com/report/github.com/Sora39831/3x-ui/v2) **3X-UI** — продвинутая панель управления с открытым исходным кодом на основе веб-интерфейса, разработанная для управления сервером Xray-core. Предоставляет удобный интерфейс для настройки и мониторинга различных VPN и прокси-протоколов. @@ -25,10 +25,10 @@ ## Быстрый старт ``` -bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) +bash <(curl -Ls https://raw.githubusercontent.com/Sora39831/3x-ui/master/install.sh) ``` -Полную документацию смотрите в [вики проекта](https://github.com/MHSanaei/3x-ui/wiki). +Полную документацию смотрите в [вики проекта](https://github.com/Sora39831/3x-ui/wiki). ## Особая благодарность @@ -54,4 +54,4 @@ bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install. ## Звезды с течением времени -[![Stargazers over time](https://starchart.cc/MHSanaei/3x-ui.svg?variant=adaptive)](https://starchart.cc/MHSanaei/3x-ui) +[![Stargazers over time](https://starchart.cc/Sora39831/3x-ui.svg?variant=adaptive)](https://starchart.cc/Sora39831/3x-ui) diff --git a/README.zh_CN.md b/README.zh_CN.md index 6eb30ee0..32d63bb0 100644 --- a/README.zh_CN.md +++ b/README.zh_CN.md @@ -7,13 +7,13 @@

-[![Release](https://img.shields.io/github/v/release/mhsanaei/3x-ui.svg)](https://github.com/MHSanaei/3x-ui/releases) -[![Build](https://img.shields.io/github/actions/workflow/status/mhsanaei/3x-ui/release.yml.svg)](https://github.com/MHSanaei/3x-ui/actions) -[![GO Version](https://img.shields.io/github/go-mod/go-version/mhsanaei/3x-ui.svg)](#) -[![Downloads](https://img.shields.io/github/downloads/mhsanaei/3x-ui/total.svg)](https://github.com/MHSanaei/3x-ui/releases/latest) +[![Release](https://img.shields.io/github/v/release/Sora39831/3x-ui.svg)](https://github.com/Sora39831/3x-ui/releases) +[![Build](https://img.shields.io/github/actions/workflow/status/Sora39831/3x-ui/release.yml.svg)](https://github.com/Sora39831/3x-ui/actions) +[![GO Version](https://img.shields.io/github/go-mod/go-version/Sora39831/3x-ui.svg)](#) +[![Downloads](https://img.shields.io/github/downloads/Sora39831/3x-ui/total.svg)](https://github.com/Sora39831/3x-ui/releases/latest) [![License](https://img.shields.io/badge/license-GPL%20V3-blue.svg?longCache=true)](https://www.gnu.org/licenses/gpl-3.0.en.html) -[![Go Reference](https://pkg.go.dev/badge/github.com/mhsanaei/3x-ui/v2.svg)](https://pkg.go.dev/github.com/mhsanaei/3x-ui/v2) -[![Go Report Card](https://goreportcard.com/badge/github.com/mhsanaei/3x-ui/v2)](https://goreportcard.com/report/github.com/mhsanaei/3x-ui/v2) +[![Go Reference](https://pkg.go.dev/badge/github.com/Sora39831/3x-ui/v2.svg)](https://pkg.go.dev/github.com/Sora39831/3x-ui/v2) +[![Go Report Card](https://goreportcard.com/badge/github.com/Sora39831/3x-ui/v2)](https://goreportcard.com/report/github.com/Sora39831/3x-ui/v2) **3X-UI** — 一个基于网页的高级开源控制面板,专为管理 Xray-core 服务器而设计。它提供了用户友好的界面,用于配置和监控各种 VPN 和代理协议。 @@ -25,10 +25,10 @@ ## 快速开始 ``` -bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) +bash <(curl -Ls https://raw.githubusercontent.com/Sora39831/3x-ui/master/install.sh) ``` -完整文档请参阅 [项目Wiki](https://github.com/MHSanaei/3x-ui/wiki)。 +完整文档请参阅 [项目Wiki](https://github.com/Sora39831/3x-ui/wiki)。 ## 特别感谢 @@ -54,4 +54,4 @@ bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install. ## 随时间变化的星标数 -[![Stargazers over time](https://starchart.cc/MHSanaei/3x-ui.svg?variant=adaptive)](https://starchart.cc/MHSanaei/3x-ui) +[![Stargazers over time](https://starchart.cc/Sora39831/3x-ui.svg?variant=adaptive)](https://starchart.cc/Sora39831/3x-ui) diff --git a/install.sh b/install.sh index af6b8a51..bb0b4866 100644 --- a/install.sh +++ b/install.sh @@ -11,10 +11,10 @@ cur_dir=$(pwd) xui_folder="${XUI_MAIN_FOLDER:=/usr/local/x-ui}" xui_service="${XUI_SERVICE:=/etc/systemd/system}" -# check root -[[ $EUID -ne 0 ]] && echo -e "${red}Fatal error: ${plain} Please run this script with root privilege \n " && exit 1 +# 检查 root 权限 +[[ $EUID -ne 0 ]] && echo -e "${red}错误:${plain} 请使用 root 权限运行此脚本 \n " && exit 1 -# Check OS and set release variable +# 检查操作系统并设置发行版变量 if [[ -f /etc/os-release ]]; then source /etc/os-release release=$ID @@ -22,10 +22,10 @@ if [[ -f /etc/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" arch() { case "$(uname -m)" in @@ -36,13 +36,13 @@ arch() { armv6* | armv6) echo 'armv6' ;; armv5* | armv5) echo 'armv5' ;; s390x) echo 's390x' ;; - *) echo -e "${green}Unsupported CPU architecture! ${plain}" && rm -f install.sh && exit 1 ;; + *) echo -e "${green}不支持的 CPU 架构!${plain}" && rm -f install.sh && exit 1 ;; esac } -echo "Arch: $(arch)" +echo "架构:$(arch)" -# Simple helpers +# 基本辅助函数 is_ipv4() { [[ "$1" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]] && return 0 || return 1 } @@ -56,7 +56,7 @@ is_domain() { [[ "$1" =~ ^([A-Za-z0-9](-*[A-Za-z0-9])*\.)+(xn--[a-z0-9]{2,}|[A-Za-z]{2,})$ ]] && return 0 || return 1 } -# Port helpers +# 端口检测辅助函数 is_port_in_use() { local port="$1" if command -v ss >/dev/null 2>&1; then @@ -111,14 +111,14 @@ gen_random_string() { } install_acme() { - echo -e "${green}Installing acme.sh for SSL certificate management...${plain}" + echo -e "${green}正在安装 acme.sh 用于 SSL 证书管理...${plain}" cd ~ || return 1 curl -s https://get.acme.sh | sh >/dev/null 2>&1 if [ $? -ne 0 ]; then - echo -e "${red}Failed to install acme.sh${plain}" + echo -e "${red}安装 acme.sh 失败${plain}" return 1 else - echo -e "${green}acme.sh installed successfully${plain}" + echo -e "${green}acme.sh 安装成功${plain}" fi return 0 } @@ -128,153 +128,153 @@ setup_ssl_certificate() { local server_ip="$2" local existing_port="$3" local existing_webBasePath="$4" - - echo -e "${green}Setting up SSL certificate...${plain}" - - # Check if acme.sh is installed + + echo -e "${green}正在配置 SSL 证书...${plain}" + + # 检查 acme.sh 是否已安装 if ! command -v ~/.acme.sh/acme.sh &>/dev/null; then install_acme if [ $? -ne 0 ]; then - echo -e "${yellow}Failed to install acme.sh, skipping SSL setup${plain}" + echo -e "${yellow}安装 acme.sh 失败,跳过 SSL 配置${plain}" return 1 fi fi - - # Create certificate directory + + # 创建证书目录 local certPath="/root/cert/${domain}" mkdir -p "$certPath" - - # Issue certificate - echo -e "${green}Issuing SSL certificate for ${domain}...${plain}" - echo -e "${yellow}Note: Port 80 must be open and accessible from the internet${plain}" - + + # 签发证书 + echo -e "${green}正在为 ${domain} 签发 SSL 证书...${plain}" + echo -e "${yellow}注意:80 端口必须开放且可从外网访问${plain}" + ~/.acme.sh/acme.sh --set-default-ca --server letsencrypt --force >/dev/null 2>&1 ~/.acme.sh/acme.sh --issue -d ${domain} --listen-v6 --standalone --httpport 80 --force - + if [ $? -ne 0 ]; then - echo -e "${yellow}Failed to issue certificate for ${domain}${plain}" - echo -e "${yellow}Please ensure port 80 is open and try again later with: x-ui${plain}" + echo -e "${yellow}为 ${domain} 签发证书失败${plain}" + echo -e "${yellow}请确保 80 端口已开放,稍后可通过以下命令重试:x-ui${plain}" rm -rf ~/.acme.sh/${domain} 2>/dev/null rm -rf "$certPath" 2>/dev/null return 1 fi - - # Install certificate + + # 安装证书 ~/.acme.sh/acme.sh --installcert -d ${domain} \ --key-file /root/cert/${domain}/privkey.pem \ --fullchain-file /root/cert/${domain}/fullchain.pem \ --reloadcmd "systemctl restart x-ui" >/dev/null 2>&1 - + if [ $? -ne 0 ]; then - echo -e "${yellow}Failed to install certificate${plain}" + echo -e "${yellow}安装证书失败${plain}" return 1 fi - - # Enable auto-renew + + # 启用自动续期 ~/.acme.sh/acme.sh --upgrade --auto-upgrade >/dev/null 2>&1 - # Secure permissions: private key readable only by owner + # 安全权限:私钥仅所有者可读 chmod 600 $certPath/privkey.pem 2>/dev/null chmod 644 $certPath/fullchain.pem 2>/dev/null - - # Set certificate for panel + + # 为面板设置证书 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" >/dev/null 2>&1 - echo -e "${green}SSL certificate installed and configured successfully!${plain}" + echo -e "${green}SSL 证书安装并配置成功!${plain}" return 0 else - echo -e "${yellow}Certificate files not found${plain}" + echo -e "${yellow}未找到证书文件${plain}" return 1 fi } -# Issue Let's Encrypt IP certificate with shortlived profile (~6 days validity) -# Requires acme.sh and port 80 open for HTTP-01 challenge +# 签发 Let's Encrypt IP 证书(短期配置文件,约 6 天有效期) +# 需要 acme.sh 且 80 端口开放用于 HTTP-01 验证 setup_ip_certificate() { local ipv4="$1" - local ipv6="$2" # optional + local ipv6="$2" # 可选 - echo -e "${green}Setting up Let's Encrypt IP certificate (shortlived profile)...${plain}" - echo -e "${yellow}Note: IP certificates are valid for ~6 days and will auto-renew.${plain}" - echo -e "${yellow}Default listener is port 80. If you choose another port, ensure external port 80 forwards to it.${plain}" + echo -e "${green}正在配置 Let's Encrypt IP 证书(短期配置文件)...${plain}" + echo -e "${yellow}注意:IP 证书有效期约 6 天,将自动续期。${plain}" + echo -e "${yellow}默认监听 80 端口。如选择其他端口,请确保外部 80 端口转发到该端口。${plain}" - # Check for acme.sh + # 检查 acme.sh if ! command -v ~/.acme.sh/acme.sh &>/dev/null; then install_acme if [ $? -ne 0 ]; then - echo -e "${red}Failed to install acme.sh${plain}" + echo -e "${red}安装 acme.sh 失败${plain}" return 1 fi fi - # Validate IP address + # 验证 IP 地址 if [[ -z "$ipv4" ]]; then - echo -e "${red}IPv4 address is required${plain}" + echo -e "${red}需要提供 IPv4 地址${plain}" return 1 fi if ! is_ipv4 "$ipv4"; then - echo -e "${red}Invalid IPv4 address: $ipv4${plain}" + echo -e "${red}无效的 IPv4 地址:$ipv4${plain}" return 1 fi - # Create certificate directory + # 创建证书目录 local certDir="/root/cert/ip" mkdir -p "$certDir" - # Build domain arguments + # 构建域名参数 local domain_args="-d ${ipv4}" if [[ -n "$ipv6" ]] && is_ipv6 "$ipv6"; then domain_args="${domain_args} -d ${ipv6}" - echo -e "${green}Including IPv6 address: ${ipv6}${plain}" + echo -e "${green}包含 IPv6 地址:${ipv6}${plain}" fi - # Set reload command for auto-renewal (add || true so it doesn't fail during first install) + # 设置重载命令用于自动续期(添加 || true 以防首次安装时失败) local reloadCmd="systemctl restart x-ui 2>/dev/null || rc-service x-ui restart 2>/dev/null || true" - # Choose port for HTTP-01 listener (default 80, prompt override) + # 选择 HTTP-01 监听端口(默认 80,可自定义) local WebPort="" - read -rp "Port to use for ACME HTTP-01 listener (default 80): " WebPort + read -rp "用于 ACME HTTP-01 监听的端口(默认 80):" WebPort WebPort="${WebPort:-80}" if ! [[ "${WebPort}" =~ ^[0-9]+$ ]] || ((WebPort < 1 || WebPort > 65535)); then - echo -e "${red}Invalid port provided. Falling back to 80.${plain}" + echo -e "${red}无效端口,回退到 80。${plain}" WebPort=80 fi - echo -e "${green}Using port ${WebPort} for standalone validation.${plain}" + echo -e "${green}使用端口 ${WebPort} 进行独立验证。${plain}" if [[ "${WebPort}" -ne 80 ]]; then - echo -e "${yellow}Reminder: Let's Encrypt still connects on port 80; forward external port 80 to ${WebPort}.${plain}" + echo -e "${yellow}提醒:Let's Encrypt 仍然连接 80 端口;请将外部 80 端口转发到 ${WebPort}。${plain}" fi - # Ensure chosen port is available + # 确保所选端口可用 while true; do if is_port_in_use "${WebPort}"; then - echo -e "${yellow}Port ${WebPort} is in use.${plain}" + echo -e "${yellow}端口 ${WebPort} 已被占用。${plain}" local alt_port="" - read -rp "Enter another port for acme.sh standalone listener (leave empty to abort): " alt_port + read -rp "请输入另一个端口供 acme.sh 独立监听(留空取消):" alt_port alt_port="${alt_port// /}" if [[ -z "${alt_port}" ]]; then - echo -e "${red}Port ${WebPort} is busy; cannot proceed.${plain}" + echo -e "${red}端口 ${WebPort} 被占用,无法继续。${plain}" return 1 fi if ! [[ "${alt_port}" =~ ^[0-9]+$ ]] || ((alt_port < 1 || alt_port > 65535)); then - echo -e "${red}Invalid port provided.${plain}" + echo -e "${red}无效端口。${plain}" return 1 fi WebPort="${alt_port}" continue else - echo -e "${green}Port ${WebPort} is free and ready for standalone validation.${plain}" + echo -e "${green}端口 ${WebPort} 空闲,可以进行独立验证。${plain}" break fi done - # Issue certificate with shortlived profile - echo -e "${green}Issuing IP certificate for ${ipv4}...${plain}" + # 使用短期配置文件签发证书 + echo -e "${green}正在为 ${ipv4} 签发 IP 证书...${plain}" ~/.acme.sh/acme.sh --set-default-ca --server letsencrypt --force >/dev/null 2>&1 - + ~/.acme.sh/acme.sh --issue \ ${domain_args} \ --standalone \ @@ -285,114 +285,114 @@ setup_ip_certificate() { --force if [ $? -ne 0 ]; then - echo -e "${red}Failed to issue IP certificate${plain}" - echo -e "${yellow}Please ensure port ${WebPort} is reachable (or forwarded from external port 80)${plain}" - # Cleanup acme.sh data for both IPv4 and IPv6 if specified + echo -e "${red}签发 IP 证书失败${plain}" + echo -e "${yellow}请确保端口 ${WebPort} 可达(或从外部 80 端口转发)${plain}" + # 清理 acme.sh 数据(IPv4 和 IPv6) rm -rf ~/.acme.sh/${ipv4} 2>/dev/null [[ -n "$ipv6" ]] && rm -rf ~/.acme.sh/${ipv6} 2>/dev/null rm -rf ${certDir} 2>/dev/null return 1 fi - echo -e "${green}Certificate issued successfully, installing...${plain}" + echo -e "${green}证书签发成功,正在安装...${plain}" - # Install 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 可能在 reloadcmd 失败时报告 "Reload error" 并返回非零退出码, + # 但证书文件仍然已安装。我们通过检查文件而非退出码来判断。 ~/.acme.sh/acme.sh --installcert -d ${ipv4} \ --key-file "${certDir}/privkey.pem" \ --fullchain-file "${certDir}/fullchain.pem" \ --reloadcmd "${reloadCmd}" 2>&1 || true - # Verify certificate files exist (don't rely on exit code - reloadcmd failure causes non-zero) + # 验证证书文件存在(不依赖退出码 - reloadcmd 失败会导致非零) if [[ ! -f "${certDir}/fullchain.pem" || ! -f "${certDir}/privkey.pem" ]]; then - echo -e "${red}Certificate files not found after installation${plain}" - # Cleanup acme.sh data for both IPv4 and IPv6 if specified + echo -e "${red}安装后未找到证书文件${plain}" + # 清理 acme.sh 数据(IPv4 和 IPv6) rm -rf ~/.acme.sh/${ipv4} 2>/dev/null [[ -n "$ipv6" ]] && rm -rf ~/.acme.sh/${ipv6} 2>/dev/null rm -rf ${certDir} 2>/dev/null return 1 fi - - echo -e "${green}Certificate files installed successfully${plain}" - # Enable auto-upgrade for acme.sh (ensures cron job runs) + echo -e "${green}证书文件安装成功${plain}" + + # 启用 acme.sh 自动升级(确保 cron 任务运行) ~/.acme.sh/acme.sh --upgrade --auto-upgrade >/dev/null 2>&1 - # Secure permissions: private key readable only by owner + # 安全权限:私钥仅所有者可读 chmod 600 ${certDir}/privkey.pem 2>/dev/null chmod 644 ${certDir}/fullchain.pem 2>/dev/null - # Configure panel to use the certificate - echo -e "${green}Setting certificate paths for the panel...${plain}" + # 为面板配置证书路径 + echo -e "${green}正在为面板设置证书路径...${plain}" ${xui_folder}/x-ui cert -webCert "${certDir}/fullchain.pem" -webCertKey "${certDir}/privkey.pem" - + if [ $? -ne 0 ]; then - echo -e "${yellow}Warning: Could not set certificate paths automatically${plain}" - echo -e "${yellow}Certificate files are at:${plain}" - echo -e " Cert: ${certDir}/fullchain.pem" - echo -e " Key: ${certDir}/privkey.pem" + echo -e "${yellow}警告:无法自动设置证书路径${plain}" + echo -e "${yellow}证书文件位于:${plain}" + echo -e " 证书:${certDir}/fullchain.pem" + echo -e " 密钥:${certDir}/privkey.pem" else - echo -e "${green}Certificate paths configured successfully${plain}" + echo -e "${green}证书路径配置成功${plain}" fi - echo -e "${green}IP certificate installed and configured successfully!${plain}" - echo -e "${green}Certificate valid for ~6 days, auto-renews via acme.sh cron job.${plain}" - echo -e "${yellow}acme.sh will automatically renew and reload x-ui before expiry.${plain}" + echo -e "${green}IP 证书安装并配置成功!${plain}" + echo -e "${green}证书有效期约 6 天,通过 acme.sh cron 任务自动续期。${plain}" + echo -e "${yellow}acme.sh 将在证书到期前自动续期并重载 x-ui。${plain}" return 0 } -# Comprehensive manual SSL certificate issuance via acme.sh +# 综合手动 SSL 证书签发(通过 acme.sh) ssl_cert_issue() { local existing_webBasePath=$(${xui_folder}/x-ui setting -show true | grep 'webBasePath:' | awk -F': ' '{print $2}' | tr -d '[:space:]' | sed 's#^/##') local existing_port=$(${xui_folder}/x-ui setting -show true | grep 'port:' | awk -F': ' '{print $2}' | tr -d '[:space:]') - - # check for acme.sh first + + # 检查 acme.sh if ! command -v ~/.acme.sh/acme.sh &>/dev/null; then - echo "acme.sh could not be found. Installing now..." + echo "未找到 acme.sh,正在安装..." cd ~ || return 1 curl -s https://get.acme.sh | sh if [ $? -ne 0 ]; then - echo -e "${red}Failed to install acme.sh${plain}" + echo -e "${red}安装 acme.sh 失败${plain}" return 1 else - echo -e "${green}acme.sh installed successfully${plain}" + echo -e "${green}acme.sh 安装成功${plain}" fi 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 - echo -e "${red}Domain name cannot be empty. Please try again.${plain}" + echo -e "${red}域名不能为空,请重试。${plain}" continue fi - + if ! is_domain "$domain"; then - echo -e "${red}Invalid domain format: ${domain}. Please enter a valid domain name.${plain}" + echo -e "${red}无效的域名格式:${domain},请输入有效的域名。${plain}" continue fi - + break done - echo -e "${green}Your domain is: ${domain}, checking it...${plain}" + echo -e "${green}您的域名是:${domain},正在检查...${plain}" - # 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) - echo -e "${red}System already has certificates for this domain. Cannot issue again.${plain}" - echo -e "${yellow}Current certificate details:${plain}" + echo -e "${red}系统已有该域名的证书,无法重复签发。${plain}" + echo -e "${yellow}当前证书信息:${plain}" echo "$certInfo" return 1 else - echo -e "${green}Your domain is ready for issuing certificates now...${plain}" + echo -e "${green}您的域名已准备好签发证书...${plain}" fi - # create a directory for the certificate + # 创建证书目录 certPath="/root/cert/${domain}" if [ ! -d "$certPath" ]; then mkdir -p "$certPath" @@ -401,239 +401,237 @@ 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 - echo -e "${yellow}Your input ${WebPort} is invalid, will use default port 80.${plain}" + echo -e "${yellow}输入 ${WebPort} 无效,将使用默认端口 80。${plain}" WebPort=80 fi - echo -e "${green}Will use port: ${WebPort} to issue certificates. Please make sure this port is open.${plain}" + echo -e "${green}将使用端口:${WebPort} 签发证书。请确保此端口已开放。${plain}" - # Stop panel temporarily - echo -e "${yellow}Stopping panel temporarily...${plain}" + # 临时停止面板 + echo -e "${yellow}正在临时停止面板...${plain}" systemctl stop x-ui 2>/dev/null || rc-service x-ui stop 2>/dev/null - # issue the certificate + # 签发证书 ~/.acme.sh/acme.sh --set-default-ca --server letsencrypt --force ~/.acme.sh/acme.sh --issue -d ${domain} --listen-v6 --standalone --httpport ${WebPort} --force if [ $? -ne 0 ]; then - echo -e "${red}Issuing certificate failed, please check logs.${plain}" + echo -e "${red}签发证书失败,请查看日志。${plain}" rm -rf ~/.acme.sh/${domain} systemctl start x-ui 2>/dev/null || rc-service x-ui start 2>/dev/null return 1 else - echo -e "${green}Issuing certificate succeeded, installing certificates...${plain}" + echo -e "${green}证书签发成功,正在安装证书...${plain}" fi - # Setup reload command + # 设置重载命令 reloadCmd="systemctl restart x-ui || rc-service x-ui restart" - echo -e "${green}Default --reloadcmd for ACME is: ${yellow}systemctl restart x-ui || rc-service x-ui restart${plain}" - echo -e "${green}This command will run on every certificate issue and renew.${plain}" - read -rp "Would you like to modify --reloadcmd for ACME? (y/n): " setReloadcmd + echo -e "${green}ACME 默认 --reloadcmd 为:${yellow}systemctl restart x-ui || rc-service x-ui restart${plain}" + echo -e "${green}此命令将在每次签发和续期证书时运行。${plain}" + read -rp "是否要修改 ACME 的 --reloadcmd?(y/n):" setReloadcmd if [[ "$setReloadcmd" == "y" || "$setReloadcmd" == "Y" ]]; then - echo -e "\n${green}\t1.${plain} Preset: systemctl reload nginx ; systemctl restart x-ui" - 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 ; systemctl restart x-ui" + echo -e "${green}\t2.${plain} 输入自定义命令" + echo -e "${green}\t0.${plain} 保持默认 reloadcmd" + read -rp "请选择:" choice case "$choice" in 1) - echo -e "${green}Reloadcmd is: systemctl reload nginx ; systemctl restart x-ui${plain}" + echo -e "${green}Reloadcmd 设为:systemctl reload nginx ; systemctl restart x-ui${plain}" reloadCmd="systemctl reload nginx ; systemctl restart x-ui" ;; 2) - echo -e "${yellow}It's recommended to put x-ui restart at the end${plain}" - read -rp "Please enter your custom reloadcmd: " reloadCmd - echo -e "${green}Reloadcmd is: ${reloadCmd}${plain}" + echo -e "${yellow}建议将 x-ui restart 放在最后,这样即使其他服务失败也不会报错${plain}" + read -rp "请输入自定义的 reloadcmd:" reloadCmd + echo -e "${green}Reloadcmd 设为:${reloadCmd}${plain}" ;; *) - echo -e "${green}Keeping default reloadcmd${plain}" + echo -e "${green}保持默认 reloadcmd${plain}" ;; 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 - echo -e "${red}Installing certificate failed, exiting.${plain}" + echo -e "${red}安装证书失败,退出。${plain}" rm -rf ~/.acme.sh/${domain} systemctl start x-ui 2>/dev/null || rc-service x-ui start 2>/dev/null return 1 else - echo -e "${green}Installing certificate succeeded, enabling auto renew...${plain}" + echo -e "${green}安装证书成功,正在启用自动续期...${plain}" fi - # enable auto-renew + # 启用自动续期 ~/.acme.sh/acme.sh --upgrade --auto-upgrade if [ $? -ne 0 ]; then - echo -e "${yellow}Auto renew setup had issues, certificate details:${plain}" + echo -e "${yellow}自动续期设置有问题,证书详情:${plain}" ls -lah /root/cert/${domain}/ - # Secure permissions: private key readable only by owner chmod 600 $certPath/privkey.pem 2>/dev/null chmod 644 $certPath/fullchain.pem 2>/dev/null else - echo -e "${green}Auto renew succeeded, certificate details:${plain}" + echo -e "${green}自动续期设置成功,证书详情:${plain}" ls -lah /root/cert/${domain}/ - # Secure permissions: private key readable only by owner chmod 600 $certPath/privkey.pem 2>/dev/null chmod 644 $certPath/fullchain.pem 2>/dev/null fi - # start panel + # 启动面板 systemctl start x-ui 2>/dev/null || rc-service x-ui start 2>/dev/null - # 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" - echo -e "${green}Certificate paths set for the panel${plain}" - echo -e "${green}Certificate File: $webCertFile${plain}" - echo -e "${green}Private Key File: $webKeyFile${plain}" + echo -e "${green}面板证书路径已设置${plain}" + echo -e "${green}证书文件:$webCertFile${plain}" + echo -e "${green}私钥文件:$webKeyFile${plain}" echo "" - echo -e "${green}Access URL: https://${domain}:${existing_port}/${existing_webBasePath}${plain}" - echo -e "${yellow}Panel will restart to apply SSL certificate...${plain}" + echo -e "${green}访问地址:https://${domain}:${existing_port}/${existing_webBasePath}${plain}" + echo -e "${yellow}面板将重启以应用 SSL 证书...${plain}" systemctl restart x-ui 2>/dev/null || rc-service x-ui restart 2>/dev/null else - echo -e "${red}Error: Certificate or private key file not found for domain: $domain.${plain}" + echo -e "${red}错误:未找到域名 ${domain} 的证书或私钥文件。${plain}" fi else - echo -e "${yellow}Skipping panel path setting.${plain}" + echo -e "${yellow}跳过面板路径设置。${plain}" fi - + return 0 } -# Reusable interactive SSL setup (domain or IP) -# Sets global `SSL_HOST` to the chosen domain/IP for Access URL usage +# 可复用的交互式 SSL 设置(域名或 IP) +# 设置全局 `SSL_HOST` 以供访问地址使用 prompt_and_setup_ssl() { local panel_port="$1" - local web_base_path="$2" # expected without leading slash + local web_base_path="$2" # 预期不含前导斜杠 local server_ip="$3" local ssl_choice="" - echo -e "${yellow}Choose SSL certificate setup method:${plain}" - echo -e "${green}1.${plain} Let's Encrypt for Domain (90-day validity, auto-renews)" - echo -e "${green}2.${plain} Let's Encrypt for IP Address (6-day validity, auto-renews)" - echo -e "${green}3.${plain} Custom SSL Certificate (Path to existing files)" - echo -e "${blue}Note:${plain} Options 1 & 2 require port 80 open. Option 3 requires manual paths." - read -rp "Choose an option (default 2 for IP): " ssl_choice - ssl_choice="${ssl_choice// /}" # Trim whitespace - - # Default to 2 (IP cert) if input is empty or invalid (not 1 or 3) + echo -e "${yellow}选择 SSL 证书配置方式:${plain}" + echo -e "${green}1.${plain} Let's Encrypt 域名证书(90 天有效期,自动续期)" + echo -e "${green}2.${plain} Let's Encrypt IP 证书(6 天有效期,自动续期)" + echo -e "${green}3.${plain} 自定义 SSL 证书(指定已有文件路径)" + echo -e "${blue}注意:${plain} 选项 1 和 2 需要开放 80 端口。选项 3 需要手动指定路径。" + read -rp "请选择(默认 2 使用 IP):" ssl_choice + ssl_choice="${ssl_choice// /}" # 去除空格 + + # 如果输入为空或无效(非 1 或 3),默认为 2(IP 证书) if [[ "$ssl_choice" != "1" && "$ssl_choice" != "3" ]]; then ssl_choice="2" fi case "$ssl_choice" in 1) - # User chose Let's Encrypt domain option - echo -e "${green}Using Let's Encrypt for domain certificate...${plain}" + # 用户选择 Let's Encrypt 域名选项 + echo -e "${green}使用 Let's Encrypt 域名证书...${plain}" ssl_cert_issue - # Extract the domain that was used from the certificate + # 从证书中提取使用的域名 local cert_domain=$(~/.acme.sh/acme.sh --list 2>/dev/null | tail -1 | awk '{print $1}') if [[ -n "${cert_domain}" ]]; then SSL_HOST="${cert_domain}" - echo -e "${green}✓ SSL certificate configured successfully with domain: ${cert_domain}${plain}" + echo -e "${green}✓ SSL 证书配置成功,域名:${cert_domain}${plain}" else - echo -e "${yellow}SSL setup may have completed, but domain extraction failed${plain}" + echo -e "${yellow}SSL 配置可能已完成,但域名提取失败${plain}" SSL_HOST="${server_ip}" fi ;; 2) - # User chose Let's Encrypt IP certificate option - echo -e "${green}Using Let's Encrypt for IP certificate (shortlived profile)...${plain}" - - # Ask for optional IPv6 + # 用户选择 Let's Encrypt IP 证书选项 + echo -e "${green}使用 Let's Encrypt IP 证书(短期配置文件)...${plain}" + + # 询问可选的 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 - - # Stop panel if running (port 80 needed) + read -rp "是否包含 IPv6 地址?(留空跳过):" ipv6_addr + ipv6_addr="${ipv6_addr// /}" # 去除空格 + + # 停止面板(需要 80 端口) if [[ $release == "alpine" ]]; then rc-service x-ui stop >/dev/null 2>&1 else systemctl stop x-ui >/dev/null 2>&1 fi - + setup_ip_certificate "${server_ip}" "${ipv6_addr}" if [ $? -eq 0 ]; then SSL_HOST="${server_ip}" - echo -e "${green}✓ Let's Encrypt IP certificate configured successfully${plain}" + echo -e "${green}✓ Let's Encrypt IP 证书配置成功${plain}" else - echo -e "${red}✗ IP certificate setup failed. Please check port 80 is open.${plain}" + echo -e "${red}✗ IP 证书配置失败。请检查 80 端口是否已开放。${plain}" SSL_HOST="${server_ip}" fi ;; 3) - # User chose Custom Paths (User Provided) option - echo -e "${green}Using custom existing certificate...${plain}" + # 用户选择自定义路径(用户提供) + echo -e "${green}使用自定义已有证书...${plain}" local custom_cert="" local custom_key="" local custom_domain="" - # 3.1 Request Domain to compose Panel URL later - read -rp "Please enter domain name certificate issued for: " custom_domain - custom_domain="${custom_domain// /}" # Убираем пробелы + # 3.1 请求域名以组成面板 URL + read -rp "请输入证书对应的域名:" custom_domain + custom_domain="${custom_domain// /}" # 去除空格 - # 3.2 Loop for Certificate Path + # 3.2 证书路径循环 while true; do - read -rp "Input certificate path (keywords: .crt / fullchain): " custom_cert - # Strip quotes if present + read -rp "输入证书路径(关键字:.crt / fullchain):" custom_cert + # 去除引号 custom_cert=$(echo "$custom_cert" | tr -d '"' | tr -d "'") if [[ -f "$custom_cert" && -r "$custom_cert" && -s "$custom_cert" ]]; then break elif [[ ! -f "$custom_cert" ]]; then - echo -e "${red}Error: File does not exist! Try again.${plain}" + echo -e "${red}错误:文件不存在!请重试。${plain}" elif [[ ! -r "$custom_cert" ]]; then - echo -e "${red}Error: File exists but is not readable (check permissions)!${plain}" + echo -e "${red}错误:文件存在但不可读(请检查权限)!${plain}" else - echo -e "${red}Error: File is empty!${plain}" + echo -e "${red}错误:文件为空!${plain}" fi done - # 3.3 Loop for Private Key Path + # 3.3 私钥路径循环 while true; do - read -rp "Input private key path (keywords: .key / privatekey): " custom_key - # Strip quotes if present + read -rp "输入私钥路径(关键字:.key / privatekey):" custom_key + # 去除引号 custom_key=$(echo "$custom_key" | tr -d '"' | tr -d "'") if [[ -f "$custom_key" && -r "$custom_key" && -s "$custom_key" ]]; then break elif [[ ! -f "$custom_key" ]]; then - echo -e "${red}Error: File does not exist! Try again.${plain}" + echo -e "${red}错误:文件不存在!请重试。${plain}" elif [[ ! -r "$custom_key" ]]; then - echo -e "${red}Error: File exists but is not readable (check permissions)!${plain}" + echo -e "${red}错误:文件存在但不可读(请检查权限)!${plain}" else - echo -e "${red}Error: File is empty!${plain}" + echo -e "${red}错误:文件为空!${plain}" fi done - # 3.4 Apply Settings via x-ui binary + # 3.4 通过 x-ui 二进制文件应用设置 ${xui_folder}/x-ui cert -webCert "$custom_cert" -webCertKey "$custom_key" >/dev/null 2>&1 - - # Set SSL_HOST for composing Panel URL + + # 设置 SSL_HOST 用于组成面板 URL if [[ -n "$custom_domain" ]]; then SSL_HOST="$custom_domain" else SSL_HOST="${server_ip}" fi - echo -e "${green}✓ Custom certificate paths applied.${plain}" - echo -e "${yellow}Note: You are responsible for renewing these files externally.${plain}" + echo -e "${green}✓ 自定义证书路径已应用。${plain}" + echo -e "${yellow}注意:您需要自行管理这些文件的续期。${plain}" systemctl restart x-ui >/dev/null 2>&1 || rc-service x-ui restart >/dev/null 2>&1 ;; *) - echo -e "${red}Invalid option. Skipping SSL setup.${plain}" + echo -e "${red}无效选项。跳过 SSL 配置。${plain}" SSL_HOST="${server_ip}" ;; esac @@ -643,7 +641,7 @@ config_after_install() { local existing_hasDefaultCredential=$(${xui_folder}/x-ui setting -show true | grep -Eo 'hasDefaultCredential: .+' | awk '{print $2}') local existing_webBasePath=$(${xui_folder}/x-ui setting -show true | grep -Eo 'webBasePath: .+' | awk '{print $2}' | sed 's#^/##') local existing_port=$(${xui_folder}/x-ui setting -show true | grep -Eo 'port: .+' | awk '{print $2}') - # Properly detect empty cert by checking if cert: line exists and has content after it + # 通过检查 cert: 行是否存在且之后有内容来正确检测空证书 local existing_cert=$(${xui_folder}/x-ui setting -getCert true | grep 'cert:' | awk -F': ' '{print $2}' | tr -d '[:space:]') local URL_lists=( "https://api4.ipify.org" @@ -663,149 +661,149 @@ config_after_install() { break fi done - + if [[ ${#existing_webBasePath} -lt 4 ]]; then if [[ "$existing_hasDefaultCredential" == "true" ]]; then local config_webBasePath=$(gen_random_string 18) local config_username=$(gen_random_string 10) local config_password=$(gen_random_string 10) - - read -rp "Would you like to customize the Panel Port settings? (If not, a random port will be applied) [y/n]: " config_confirm + + read -rp "是否要自定义面板端口?(否则将使用随机端口)[y/n]:" config_confirm if [[ "${config_confirm}" == "y" || "${config_confirm}" == "Y" ]]; then - read -rp "Please set up the panel port: " config_port - echo -e "${yellow}Your Panel Port is: ${config_port}${plain}" + read -rp "请设置面板端口:" config_port + echo -e "${yellow}您的面板端口为:${config_port}${plain}" else local config_port=$(shuf -i 1024-62000 -n 1) - echo -e "${yellow}Generated random port: ${config_port}${plain}" + echo -e "${yellow}已生成随机端口:${config_port}${plain}" fi - + ${xui_folder}/x-ui setting -username "${config_username}" -password "${config_password}" -port "${config_port}" -webBasePath "${config_webBasePath}" - + echo "" echo -e "${green}═══════════════════════════════════════════${plain}" - echo -e "${green} SSL Certificate Setup (MANDATORY) ${plain}" + echo -e "${green} SSL 证书配置(必需) ${plain}" echo -e "${green}═══════════════════════════════════════════${plain}" - echo -e "${yellow}For security, SSL certificate is required for all panels.${plain}" - echo -e "${yellow}Let's Encrypt now supports both domains and IP addresses!${plain}" + echo -e "${yellow}出于安全考虑,所有面板都需要配置 SSL 证书。${plain}" + echo -e "${yellow}Let's Encrypt 现已支持域名和 IP 地址!${plain}" echo "" prompt_and_setup_ssl "${config_port}" "${config_webBasePath}" "${server_ip}" - - # Display final credentials and access information + + # 显示最终凭据和访问信息 echo "" echo -e "${green}═══════════════════════════════════════════${plain}" - echo -e "${green} Panel Installation Complete! ${plain}" + echo -e "${green} 面板安装完成! ${plain}" echo -e "${green}═══════════════════════════════════════════${plain}" - echo -e "${green}Username: ${config_username}${plain}" - echo -e "${green}Password: ${config_password}${plain}" - echo -e "${green}Port: ${config_port}${plain}" - echo -e "${green}WebBasePath: ${config_webBasePath}${plain}" - echo -e "${green}Access URL: https://${SSL_HOST}:${config_port}/${config_webBasePath}${plain}" + echo -e "${green}用户名: ${config_username}${plain}" + echo -e "${green}密码: ${config_password}${plain}" + echo -e "${green}端口: ${config_port}${plain}" + echo -e "${green}Web路径: ${config_webBasePath}${plain}" + echo -e "${green}访问地址: https://${SSL_HOST}:${config_port}/${config_webBasePath}${plain}" echo -e "${green}═══════════════════════════════════════════${plain}" - echo -e "${yellow}⚠ IMPORTANT: Save these credentials securely!${plain}" - echo -e "${yellow}⚠ SSL Certificate: Enabled and configured${plain}" + echo -e "${yellow}⚠ 重要:请安全保存这些凭据!${plain}" + echo -e "${yellow}⚠ SSL 证书:已启用并配置${plain}" else local config_webBasePath=$(gen_random_string 18) - echo -e "${yellow}WebBasePath is missing or too short. Generating a new one...${plain}" + echo -e "${yellow}WebBasePath 缺失或过短,正在生成新的...${plain}" ${xui_folder}/x-ui setting -webBasePath "${config_webBasePath}" - echo -e "${green}New WebBasePath: ${config_webBasePath}${plain}" + echo -e "${green}新 WebBasePath:${config_webBasePath}${plain}" - # If the panel is already installed but no certificate is configured, prompt for SSL now + # 如果面板已安装但未配置证书,提示配置 SSL if [[ -z "${existing_cert}" ]]; then echo "" echo -e "${green}═══════════════════════════════════════════${plain}" - echo -e "${green} SSL Certificate Setup (RECOMMENDED) ${plain}" + echo -e "${green} SSL 证书配置(推荐) ${plain}" echo -e "${green}═══════════════════════════════════════════${plain}" - echo -e "${yellow}Let's Encrypt now supports both domains and IP addresses!${plain}" + echo -e "${yellow}Let's Encrypt 现已支持域名和 IP 地址!${plain}" echo "" prompt_and_setup_ssl "${existing_port}" "${config_webBasePath}" "${server_ip}" - echo -e "${green}Access URL: https://${SSL_HOST}:${existing_port}/${config_webBasePath}${plain}" + echo -e "${green}访问地址: https://${SSL_HOST}:${existing_port}/${config_webBasePath}${plain}" else - # If a cert already exists, just show the access URL - echo -e "${green}Access URL: https://${server_ip}:${existing_port}/${config_webBasePath}${plain}" + # 如果已有证书,直接显示访问地址 + echo -e "${green}访问地址:https://${server_ip}:${existing_port}/${config_webBasePath}${plain}" fi fi else if [[ "$existing_hasDefaultCredential" == "true" ]]; then local config_username=$(gen_random_string 10) local config_password=$(gen_random_string 10) - - echo -e "${yellow}Default credentials detected. Security update required...${plain}" + + echo -e "${yellow}检测到默认凭据,需要安全更新...${plain}" ${xui_folder}/x-ui setting -username "${config_username}" -password "${config_password}" - echo -e "Generated new random login credentials:" + echo -e "已生成新的随机登录凭据:" echo -e "###############################################" - echo -e "${green}Username: ${config_username}${plain}" - echo -e "${green}Password: ${config_password}${plain}" + echo -e "${green}用户名:${config_username}${plain}" + echo -e "${green}密码: ${config_password}${plain}" echo -e "###############################################" else - echo -e "${green}Username, Password, and WebBasePath are properly set.${plain}" + echo -e "${green}用户名、密码和 WebBasePath 已正确设置。${plain}" fi - # Existing install: if no cert configured, prompt user for SSL setup - # Properly detect empty cert by checking if cert: line exists and has content after it + # 已有安装:如果未配置证书,提示用户配置 SSL + # 通过检查 cert: 行是否存在且之后有内容来正确检测空证书 existing_cert=$(${xui_folder}/x-ui setting -getCert true | grep 'cert:' | awk -F': ' '{print $2}' | tr -d '[:space:]') if [[ -z "$existing_cert" ]]; then echo "" echo -e "${green}═══════════════════════════════════════════${plain}" - echo -e "${green} SSL Certificate Setup (RECOMMENDED) ${plain}" + echo -e "${green} SSL 证书配置(推荐) ${plain}" echo -e "${green}═══════════════════════════════════════════${plain}" - echo -e "${yellow}Let's Encrypt now supports both domains and IP addresses!${plain}" + echo -e "${yellow}Let's Encrypt 现已支持域名和 IP 地址!${plain}" echo "" prompt_and_setup_ssl "${existing_port}" "${existing_webBasePath}" "${server_ip}" - echo -e "${green}Access URL: https://${SSL_HOST}:${existing_port}/${existing_webBasePath}${plain}" + echo -e "${green}访问地址: https://${SSL_HOST}:${existing_port}/${existing_webBasePath}${plain}" else - echo -e "${green}SSL certificate already configured. No action needed.${plain}" + echo -e "${green}SSL 证书已配置,无需操作。${plain}" fi fi - + ${xui_folder}/x-ui migrate } install_x-ui() { cd ${xui_folder%/x-ui}/ - - # Download resources + + # 下载资源 if [ $# == 0 ]; then - tag_version=$(curl -Ls "https://api.github.com/repos/MHSanaei/3x-ui/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/') + tag_version=$(curl -Ls "https://api.github.com/repos/Sora39831/3x-ui/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/') if [[ ! -n "$tag_version" ]]; then - echo -e "${yellow}Trying to fetch version with IPv4...${plain}" - tag_version=$(curl -4 -Ls "https://api.github.com/repos/MHSanaei/3x-ui/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/') + echo -e "${yellow}正在尝试通过 IPv4 获取版本...${plain}" + tag_version=$(curl -4 -Ls "https://api.github.com/repos/Sora39831/3x-ui/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/') if [[ ! -n "$tag_version" ]]; then - echo -e "${red}Failed to fetch x-ui version, it may be due to GitHub API restrictions, please try it later${plain}" + echo -e "${red}获取 x-ui 版本失败,可能是 GitHub API 限制,请稍后重试${plain}" exit 1 fi fi - echo -e "Got x-ui latest version: ${tag_version}, beginning the installation..." - curl -4fLRo ${xui_folder}-linux-$(arch).tar.gz https://github.com/MHSanaei/3x-ui/releases/download/${tag_version}/x-ui-linux-$(arch).tar.gz + echo -e "获取到 x-ui 最新版本:${tag_version},开始安装..." + curl -4fLRo ${xui_folder}-linux-$(arch).tar.gz https://github.com/Sora39831/3x-ui/releases/download/${tag_version}/x-ui-linux-$(arch).tar.gz if [[ $? -ne 0 ]]; then - echo -e "${red}Downloading x-ui failed, please be sure that your server can access GitHub ${plain}" + echo -e "${red}下载 x-ui 失败,请确保服务器可以访问 GitHub${plain}" exit 1 fi else tag_version=$1 tag_version_numeric=${tag_version#v} min_version="2.3.5" - + if [[ "$(printf '%s\n' "$min_version" "$tag_version_numeric" | sort -V | head -n1)" != "$min_version" ]]; then - echo -e "${red}Please use a newer version (at least v2.3.5). Exiting installation.${plain}" + echo -e "${red}请使用更新的版本(至少 v2.3.5)。安装已取消。${plain}" exit 1 fi - - url="https://github.com/MHSanaei/3x-ui/releases/download/${tag_version}/x-ui-linux-$(arch).tar.gz" - echo -e "Beginning to install x-ui $1" + + url="https://github.com/Sora39831/3x-ui/releases/download/${tag_version}/x-ui-linux-$(arch).tar.gz" + echo -e "开始安装 x-ui $1" curl -4fLRo ${xui_folder}-linux-$(arch).tar.gz ${url} if [[ $? -ne 0 ]]; then - echo -e "${red}Download x-ui $1 failed, please check if the version exists ${plain}" + echo -e "${red}下载 x-ui $1 失败,请检查版本是否存在${plain}" exit 1 fi fi - curl -4fLRo /usr/bin/x-ui-temp https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.sh + curl -4fLRo /usr/bin/x-ui-temp https://raw.githubusercontent.com/Sora39831/3x-ui/main/x-ui.sh if [[ $? -ne 0 ]]; then - echo -e "${red}Failed to download x-ui.sh${plain}" + echo -e "${red}下载 x-ui.sh 失败${plain}" exit 1 fi - - # Stop x-ui service and remove old resources + + # 停止 x-ui 服务并删除旧资源 if [[ -e ${xui_folder}/ ]]; then if [[ $release == "alpine" ]]; then rc-service x-ui stop @@ -814,68 +812,68 @@ install_x-ui() { fi rm ${xui_folder}/ -rf fi - - # Extract resources and set permissions + + # 解压资源并设置权限 tar zxvf x-ui-linux-$(arch).tar.gz rm x-ui-linux-$(arch).tar.gz -f - + cd x-ui chmod +x x-ui chmod +x x-ui.sh - - # Check the system's architecture and rename the file accordingly + + # 检查系统架构并重命名文件 if [[ $(arch) == "armv5" || $(arch) == "armv6" || $(arch) == "armv7" ]]; then mv bin/xray-linux-$(arch) bin/xray-linux-arm chmod +x bin/xray-linux-arm fi chmod +x x-ui bin/xray-linux-$(arch) - - # Update x-ui cli and se set permission + + # 更新 x-ui 命令行工具并设置权限 mv -f /usr/bin/x-ui-temp /usr/bin/x-ui chmod +x /usr/bin/x-ui mkdir -p /var/log/x-ui config_after_install - # Etckeeper compatibility + # Etckeeper 兼容性 if [ -d "/etc/.git" ]; then if [ -f "/etc/.gitignore" ]; then if ! grep -q "x-ui/x-ui.db" "/etc/.gitignore"; then echo "" >> "/etc/.gitignore" echo "x-ui/x-ui.db" >> "/etc/.gitignore" - echo -e "${green}Added x-ui.db to /etc/.gitignore for etckeeper${plain}" + echo -e "${green}已将 x-ui.db 添加到 /etc/.gitignore 以支持 etckeeper${plain}" fi else echo "x-ui/x-ui.db" > "/etc/.gitignore" - echo -e "${green}Created /etc/.gitignore and added x-ui.db for etckeeper${plain}" + echo -e "${green}已创建 /etc/.gitignore 并添加 x-ui.db 以支持 etckeeper${plain}" fi fi - + if [[ $release == "alpine" ]]; then - curl -4fLRo /etc/init.d/x-ui https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.rc + curl -4fLRo /etc/init.d/x-ui https://raw.githubusercontent.com/Sora39831/3x-ui/main/x-ui.rc if [[ $? -ne 0 ]]; then - echo -e "${red}Failed to download x-ui.rc${plain}" + echo -e "${red}下载 x-ui.rc 失败${plain}" exit 1 fi chmod +x /etc/init.d/x-ui rc-update add x-ui rc-service x-ui start else - # Install systemd service file + # 安装 systemd 服务文件 service_installed=false - + if [ -f "x-ui.service" ]; then - echo -e "${green}Found x-ui.service in extracted files, installing...${plain}" + echo -e "${green}在解压文件中找到 x-ui.service,正在安装...${plain}" cp -f x-ui.service ${xui_service}/ >/dev/null 2>&1 if [[ $? -eq 0 ]]; then service_installed=true fi fi - + if [ "$service_installed" = false ]; then case "${release}" in ubuntu | debian | armbian) if [ -f "x-ui.service.debian" ]; then - echo -e "${green}Found x-ui.service.debian in extracted files, installing...${plain}" + echo -e "${green}在解压文件中找到 x-ui.service.debian,正在安装...${plain}" cp -f x-ui.service.debian ${xui_service}/x-ui.service >/dev/null 2>&1 if [[ $? -eq 0 ]]; then service_installed=true @@ -884,7 +882,7 @@ install_x-ui() { ;; arch | manjaro | parch) if [ -f "x-ui.service.arch" ]; then - echo -e "${green}Found x-ui.service.arch in extracted files, installing...${plain}" + echo -e "${green}在解压文件中找到 x-ui.service.arch,正在安装...${plain}" cp -f x-ui.service.arch ${xui_service}/x-ui.service >/dev/null 2>&1 if [[ $? -eq 0 ]]; then service_installed=true @@ -893,7 +891,7 @@ install_x-ui() { ;; *) if [ -f "x-ui.service.rhel" ]; then - echo -e "${green}Found x-ui.service.rhel in extracted files, installing...${plain}" + echo -e "${green}在解压文件中找到 x-ui.service.rhel,正在安装...${plain}" cp -f x-ui.service.rhel ${xui_service}/x-ui.service >/dev/null 2>&1 if [[ $? -eq 0 ]]; then service_installed=true @@ -902,64 +900,64 @@ install_x-ui() { ;; esac fi - - # If service file not found in tar.gz, download from GitHub + + # 如果 tar.gz 中未找到服务文件,从 GitHub 下载 if [ "$service_installed" = false ]; then - echo -e "${yellow}Service files not found in tar.gz, downloading from GitHub...${plain}" + echo -e "${yellow}tar.gz 中未找到服务文件,正在从 GitHub 下载...${plain}" case "${release}" in ubuntu | debian | armbian) - curl -4fLRo ${xui_service}/x-ui.service https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.service.debian >/dev/null 2>&1 + curl -4fLRo ${xui_service}/x-ui.service https://raw.githubusercontent.com/Sora39831/3x-ui/main/x-ui.service.debian >/dev/null 2>&1 ;; arch | manjaro | parch) - curl -4fLRo ${xui_service}/x-ui.service https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.service.arch >/dev/null 2>&1 + curl -4fLRo ${xui_service}/x-ui.service https://raw.githubusercontent.com/Sora39831/3x-ui/main/x-ui.service.arch >/dev/null 2>&1 ;; *) - curl -4fLRo ${xui_service}/x-ui.service https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.service.rhel >/dev/null 2>&1 + curl -4fLRo ${xui_service}/x-ui.service https://raw.githubusercontent.com/Sora39831/3x-ui/main/x-ui.service.rhel >/dev/null 2>&1 ;; esac - + if [[ $? -ne 0 ]]; then - echo -e "${red}Failed to install x-ui.service from GitHub${plain}" + echo -e "${red}从 GitHub 安装 x-ui.service 失败${plain}" exit 1 fi service_installed=true fi - + if [ "$service_installed" = true ]; then - echo -e "${green}Setting up systemd unit...${plain}" + echo -e "${green}正在配置 systemd 服务...${plain}" chown root:root ${xui_service}/x-ui.service >/dev/null 2>&1 chmod 644 ${xui_service}/x-ui.service >/dev/null 2>&1 systemctl daemon-reload systemctl enable x-ui systemctl start x-ui else - echo -e "${red}Failed to install x-ui.service file${plain}" + echo -e "${red}安装 x-ui.service 文件失败${plain}" exit 1 fi fi - - echo -e "${green}x-ui ${tag_version}${plain} installation finished, it is running now..." + + echo -e "${green}x-ui ${tag_version}${plain} 安装完成,正在运行..." echo -e "" 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 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 legacy${plain} - 安装旧版本 │ +│ ${blue}x-ui install${plain} - 安装 │ +│ ${blue}x-ui uninstall${plain} - 卸载 │ └───────────────────────────────────────────────────────┘" } -echo -e "${green}Running...${plain}" +echo -e "${green}正在执行...${plain}" install_base install_x-ui $1 diff --git a/update.sh b/update.sh index b9cb3ddc..9d890e60 100755 --- a/update.sh +++ b/update.sh @@ -757,19 +757,19 @@ update_x-ui() { echo -e "${green}Downloading new x-ui version...${plain}" - tag_version=$(${curl_bin} -Ls "https://api.github.com/repos/MHSanaei/3x-ui/releases/latest" 2>/dev/null | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/') + tag_version=$(${curl_bin} -Ls "https://api.github.com/repos/Sora39831/3x-ui/releases/latest" 2>/dev/null | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/') if [[ ! -n "$tag_version" ]]; then echo -e "${yellow}Trying to fetch version with IPv4...${plain}" - tag_version=$(${curl_bin} -4 -Ls "https://api.github.com/repos/MHSanaei/3x-ui/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/') + tag_version=$(${curl_bin} -4 -Ls "https://api.github.com/repos/Sora39831/3x-ui/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/') if [[ ! -n "$tag_version" ]]; then _fail "ERROR: Failed to fetch x-ui version, it may be due to GitHub API restrictions, please try it later" fi fi echo -e "Got x-ui latest version: ${tag_version}, beginning the installation..." - ${curl_bin} -fLRo ${xui_folder}-linux-$(arch).tar.gz https://github.com/MHSanaei/3x-ui/releases/download/${tag_version}/x-ui-linux-$(arch).tar.gz 2>/dev/null + ${curl_bin} -fLRo ${xui_folder}-linux-$(arch).tar.gz https://github.com/Sora39831/3x-ui/releases/download/${tag_version}/x-ui-linux-$(arch).tar.gz 2>/dev/null if [[ $? -ne 0 ]]; then echo -e "${yellow}Trying to fetch version with IPv4...${plain}" - ${curl_bin} -4fLRo ${xui_folder}-linux-$(arch).tar.gz https://github.com/MHSanaei/3x-ui/releases/download/${tag_version}/x-ui-linux-$(arch).tar.gz 2>/dev/null + ${curl_bin} -4fLRo ${xui_folder}-linux-$(arch).tar.gz https://github.com/Sora39831/3x-ui/releases/download/${tag_version}/x-ui-linux-$(arch).tar.gz 2>/dev/null if [[ $? -ne 0 ]]; then _fail "ERROR: Failed to download x-ui, please be sure that your server can access GitHub" fi @@ -832,10 +832,10 @@ update_x-ui() { chmod +x x-ui bin/xray-linux-$(arch) >/dev/null 2>&1 echo -e "${green}Downloading and installing x-ui.sh script...${plain}" - ${curl_bin} -fLRo /usr/bin/x-ui https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.sh >/dev/null 2>&1 + ${curl_bin} -fLRo /usr/bin/x-ui https://raw.githubusercontent.com/Sora39831/3x-ui/main/x-ui.sh >/dev/null 2>&1 if [[ $? -ne 0 ]]; then echo -e "${yellow}Trying to fetch x-ui with IPv4...${plain}" - ${curl_bin} -4fLRo /usr/bin/x-ui https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.sh >/dev/null 2>&1 + ${curl_bin} -4fLRo /usr/bin/x-ui https://raw.githubusercontent.com/Sora39831/3x-ui/main/x-ui.sh >/dev/null 2>&1 if [[ $? -ne 0 ]]; then _fail "ERROR: Failed to download x-ui.sh script, please be sure that your server can access GitHub" fi @@ -855,9 +855,9 @@ update_x-ui() { if [[ $release == "alpine" ]]; then echo -e "${green}Downloading and installing startup unit x-ui.rc...${plain}" - ${curl_bin} -fLRo /etc/init.d/x-ui https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.rc >/dev/null 2>&1 + ${curl_bin} -fLRo /etc/init.d/x-ui https://raw.githubusercontent.com/Sora39831/3x-ui/main/x-ui.rc >/dev/null 2>&1 if [[ $? -ne 0 ]]; then - ${curl_bin} -4fLRo /etc/init.d/x-ui https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.rc >/dev/null 2>&1 + ${curl_bin} -4fLRo /etc/init.d/x-ui https://raw.githubusercontent.com/Sora39831/3x-ui/main/x-ui.rc >/dev/null 2>&1 if [[ $? -ne 0 ]]; then _fail "ERROR: Failed to download startup unit x-ui.rc, please be sure that your server can access GitHub" fi @@ -911,13 +911,13 @@ update_x-ui() { echo -e "${yellow}Service files not found in tar.gz, downloading from GitHub...${plain}" case "${release}" in ubuntu | debian | armbian) - ${curl_bin} -4fLRo ${xui_service}/x-ui.service https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.service.debian >/dev/null 2>&1 + ${curl_bin} -4fLRo ${xui_service}/x-ui.service https://raw.githubusercontent.com/Sora39831/3x-ui/main/x-ui.service.debian >/dev/null 2>&1 ;; arch | manjaro | parch) - ${curl_bin} -4fLRo ${xui_service}/x-ui.service https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.service.arch >/dev/null 2>&1 + ${curl_bin} -4fLRo ${xui_service}/x-ui.service https://raw.githubusercontent.com/Sora39831/3x-ui/main/x-ui.service.arch >/dev/null 2>&1 ;; *) - ${curl_bin} -4fLRo ${xui_service}/x-ui.service https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.service.rhel >/dev/null 2>&1 + ${curl_bin} -4fLRo ${xui_service}/x-ui.service https://raw.githubusercontent.com/Sora39831/3x-ui/main/x-ui.service.rhel >/dev/null 2>&1 ;; esac diff --git a/web/html/index.html b/web/html/index.html index bbbbb708..e442a022 100644 --- a/web/html/index.html +++ b/web/html/index.html @@ -157,7 +157,7 @@ - + v{{ .cur_ver }} @@ -167,7 +167,7 @@ @XrayUI - + {{ i18n "pages.index.documentation" }} diff --git a/x-ui.sh b/x-ui.sh index e26dcce2..0c5be83b 100644 --- a/x-ui.sh +++ b/x-ui.sh @@ -6,20 +6,20 @@ 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}" } -# Port helpers: detect listener and owning process (best effort) +# 端口辅助函数:检测端口监听及所属进程(尽力而为) is_port_in_use() { local port="$1" if command -v ss >/dev/null 2>&1; then @@ -36,7 +36,7 @@ is_port_in_use() { return 1 } -# Simple helpers for domain/IP validation +# 域名/IP 验证简单辅助函数 is_ipv4() { [[ "$1" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]] && return 0 || return 1 } @@ -50,10 +50,10 @@ is_domain() { [[ "$1" =~ ^([A-Za-z0-9](-*[A-Za-z0-9])*\.)+(xn--[a-z0-9]{2,}|[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 @@ -61,15 +61,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}" @@ -79,12 +79,12 @@ 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 else - read -rp "$1 [y/n]: " temp + read -rp "$1 [y/n]:" temp fi if [[ "${temp}" == "y" || "${temp}" == "Y" ]]; then return 0 @@ -94,7 +94,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 @@ -103,12 +103,12 @@ 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 } install() { - bash <(curl -Ls https://raw.githubusercontent.com/MHSanaei/3x-ui/main/install.sh) + bash <(curl -Ls https://raw.githubusercontent.com/Sora39831/3x-ui/main/install.sh) if [[ $? == 0 ]]; then if [[ $# == 0 ]]; then start @@ -119,68 +119,68 @@ 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 return 0 fi - bash <(curl -Ls https://raw.githubusercontent.com/MHSanaei/3x-ui/main/update.sh) + bash <(curl -Ls https://raw.githubusercontent.com/Sora39831/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 return 0 fi - curl -fLRo /usr/bin/x-ui https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.sh + curl -fLRo /usr/bin/x-ui https://raw.githubusercontent.com/Sora39831/3x-ui/main/x-ui.sh chmod +x ${xui_folder}/x-ui.sh 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" + # 使用输入的面板版本号下载 + install_command="bash <(curl -Ls "https://raw.githubusercontent.com/Sora39831/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 @@ -204,40 +204,40 @@ 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 "${green}bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)${plain}" + echo -e "卸载成功。\n" + echo "如需再次安装面板,可使用以下命令:" + echo -e "${green}bash <(curl -Ls https://raw.githubusercontent.com/Sora39831/3x-ui/master/install.sh)${plain}" echo "" - # Trap the SIGTERM signal + # 捕获 SIGTERM 信号 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 fi 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 } @@ -249,26 +249,26 @@ 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 + # 应用新的 Web 路径设置 ${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 @@ -276,14 +276,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 @@ -301,42 +301,42 @@ 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}" + # ssl_cert_issue_for_ip 已经重启面板,但确保其正在运行 start >/dev/null 2>&1 else - LOGE "IP certificate setup failed." - echo -e "${yellow}You can try again via option 19 (SSL Certificate Management).${plain}" + LOGE "IP 证书配置失败。" + echo -e "${yellow}您可以通过选项 19(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 19 (SSL Certificate Management)${plain}" + echo -e "${yellow}访问地址:http://${server_ip}:${existing_port}${existing_webBasePath}${plain}" + echo -e "${yellow}出于安全考虑,请使用选项 19(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 } @@ -345,7 +345,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 @@ -355,9 +355,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 @@ -370,7 +370,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 @@ -380,9 +380,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 @@ -400,9 +400,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 @@ -411,7 +411,7 @@ restart() { restart_xray() { systemctl reload x-ui - LOGI "xray-core Restart signal sent successfully, Please check the log information to confirm whether xray restarted successfully" + LOGI "xray-core 重启信号已发送,请查看日志信息确认 xray 是否重启成功" sleep 2 show_xray_status if [[ $# == 0 ]]; then @@ -437,9 +437,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 @@ -454,9 +454,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 @@ -466,9 +466,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) @@ -481,15 +481,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) @@ -504,11 +504,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 @@ -516,10 +516,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 @@ -533,7 +533,7 @@ bbr_menu() { bbr_menu ;; *) - echo -e "${red}Invalid option. Please select a valid number.${plain}\n" + echo -e "${red}无效选项,请选择有效数字。${plain}\n" bbr_menu ;; esac @@ -542,7 +542,7 @@ bbr_menu() { disable_bbr() { if [[ $(sysctl -n net.ipv4.tcp_congestion_control) != "bbr" ]] || [[ ! $(sysctl -n net.core.default_qdisc) =~ ^(fq|cake)$ ]]; then - echo -e "${yellow}BBR is not currently enabled.${plain}" + echo -e "${yellow}BBR 当前未启用。${plain}" before_show_menu fi @@ -553,7 +553,7 @@ disable_bbr() { rm /etc/sysctl.d/99-bbr-x-ui.conf sysctl --system else - # Replace BBR with CUBIC configurations + # 用 CUBIC 配置替换 BBR if [ -f "/etc/sysctl.conf" ]; then 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 @@ -562,19 +562,19 @@ disable_bbr() { fi if [[ $(sysctl -n net.ipv4.tcp_congestion_control) != "bbr" ]]; 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 [[ $(sysctl -n net.ipv4.tcp_congestion_control) == "bbr" ]] && [[ $(sysctl -n net.core.default_qdisc) =~ ^(fq|cake)$ ]]; then - echo -e "${green}BBR is already enabled!${plain}" + echo -e "${green}BBR 已启用!${plain}" before_show_menu fi - # Enable BBR + # 启用 BBR if [ -d "/etc/sysctl.d/" ]; then { echo "#$(sysctl -n net.core.default_qdisc):$(sysctl -n net.ipv4.tcp_congestion_control)" @@ -582,7 +582,7 @@ enable_bbr() { echo "net.ipv4.tcp_congestion_control = bbr" } > "/etc/sysctl.d/99-bbr-x-ui.conf" if [ -f "/etc/sysctl.conf" ]; then - # Backup old settings from sysctl.conf, if any + # 备份 sysctl.conf 中的旧设置(如果有) sed -i 's/^net.core.default_qdisc/# &/' /etc/sysctl.conf sed -i 's/^net.ipv4.tcp_congestion_control/# &/' /etc/sysctl.conf fi @@ -595,28 +595,28 @@ enable_bbr() { sysctl -p fi - # Verify that BBR is enabled + # 验证 BBR 是否已启用 if [[ $(sysctl -n net.ipv4.tcp_congestion_control) == "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 } update_shell() { - curl -fLRo /usr/bin/x-ui -z /usr/bin/x-ui https://github.com/MHSanaei/3x-ui/raw/main/x-ui.sh + curl -fLRo /usr/bin/x-ui -z /usr/bin/x-ui https://github.com/Sora39831/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 +# 0: 运中, 1: 未运行, 2: 未安装 check_status() { if [[ $release == "alpine" ]]; then if [[ ! -f /etc/init.d/x-ui ]]; then @@ -661,7 +661,7 @@ check_uninstall() { check_status if [[ $? != 2 ]]; then echo "" - LOGE "Panel installed, Please do not reinstall" + LOGE "面板已安装,请勿重复安装" if [[ $# == 0 ]]; then before_show_menu fi @@ -675,7 +675,7 @@ check_install() { check_status if [[ $? == 2 ]]; then echo "" - LOGE "Please install the panel first" + LOGE "请先安装面板" if [[ $# == 0 ]]; then before_show_menu fi @@ -689,15 +689,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 @@ -706,9 +706,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 } @@ -724,22 +724,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 @@ -758,7 +758,7 @@ firewall_menu() { ;; 4) delete_ports - firewall_menu + firewall_wall_menu ;; 5) ufw enable @@ -773,7 +773,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 @@ -781,142 +781,142 @@ 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 - # 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 + # 使用 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 } @@ -934,7 +934,7 @@ update_geofiles() { "RU") dat_files=(geoip_RU geosite_RU); dat_source="runetfreedom/russia-v2ray-rules-dat";; esac for dat in "${dat_files[@]}"; do - # Remove suffix for remote filename (e.g., geoip_IR -> geoip) + # 移除后缀获取远程文件名(例如 geoip_IR -> geoip) remote_file="${dat%%_*}" curl -fLRo ${xui_folder}/bin/${dat}.dat -z ${xui_folder}/bin/${dat}.dat \ https://github.com/${dat_source}/releases/latest/download/${remote_file}.dat @@ -945,9 +945,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 case "$choice" in 0) @@ -955,26 +955,26 @@ update_geo() { ;; 1) update_geofiles "main" - echo -e "${green}Loyalsoldier datasets have been updated successfully!${plain}" + echo -e "${green}Loyalsoldier 数据集更新成功!${plain}" restart ;; 2) update_geofiles "IR" - echo -e "${green}chocolate4u datasets have been updated successfully!${plain}" + echo -e "${green}chocolate4u 数据集更新成功!${plain}" restart ;; 3) update_geofiles "RU" - 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}所有 geo 文件更新成功!${plain}" restart ;; *) - echo -e "${red}Invalid option. Please select a valid number.${plain}\n" + echo -e "${red}无效选项,请选择有效数字。${plain}\n" update_geo ;; esac @@ -983,36 +983,36 @@ update_geo() { } install_acme() { - # Check if acme.sh is already installed + # 检查 acme.sh 是否已安装 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 @@ -1024,16 +1024,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 @@ -1041,16 +1041,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 @@ -1058,18 +1058,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 @@ -1078,11 +1078,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" @@ -1090,25 +1090,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 IP 地址 SSL 证书${plain}" + echo -e "将使用短期配置文件为服务器 IP 获取证书。" + echo -e "${yellow}证书有效期约 6 天,通过 acme.sh cron 自动续期。${plain}" + echo -e "${yellow}80 端口必须开放且可从外网访问。${plain}" + confirm "是否继续?" "y" if [[ $? == 0 ]]; then ssl_cert_issue_for_ip fi @@ -1116,48 +1116,48 @@ 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 + + # 获取服务器 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}" - - # Ask for optional IPv6 + + LOGI "检测到服务器 IP:${server_ip}" + + # 询问可选的 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 - - # check for acme.sh first + read -rp "是否包含 IPv6 地址?(留空跳过):" ipv6_addr + ipv6_addr="${ipv6_addr// /}" # 去除空格 + + # 先检查 acme.sh 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 + + # 安装 socat case "${release}" in ubuntu | debian | armbian) apt-get update >/dev/null 2>&1 && apt-get install socat -y >/dev/null 2>&1 @@ -1182,61 +1182,61 @@ 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 - - # Choose port for HTTP-01 listener (default 80, allow override) + + # 选择 HTTP-01 监听端口(默认 80,允许自定义) local WebPort="" - read -rp "Port to use for ACME HTTP-01 listener (default 80): " WebPort + read -rp "用于 ACME HTTP-01 监听的端口(默认 80):" WebPort WebPort="${WebPort:-80}" if ! [[ "${WebPort}" =~ ^[0-9]+$ ]] || ((WebPort < 1 || WebPort > 65535)); then - LOGE "Invalid port provided. Falling back to 80." + LOGE "无效端口,回退到 80。" WebPort=80 fi - LOGI "Using port ${WebPort} to issue certificate for IP: ${server_ip}" + LOGI "使用端口 ${WebPort} 为 IP 签发证书:${server_ip}" if [[ "${WebPort}" -ne 80 ]]; then - LOGI "Reminder: Let's Encrypt still reaches port 80; forward external port 80 to ${WebPort} for validation." + LOGI "提醒:Let's Encrypt 仍然连接 80 端口;请将外部 80 端口转发到 ${WebPort}。" fi while true; do if is_port_in_use "${WebPort}"; then - LOGI "Port ${WebPort} is currently in use." + LOGI "端口 ${WebPort} 当前被占用。" local alt_port="" - read -rp "Enter another port for acme.sh standalone listener (leave empty to abort): " alt_port + read -rp "请输入另一个端口供 acme.sh 独立监听(留空取消):" alt_port alt_port="${alt_port// /}" if [[ -z "${alt_port}" ]]; then - LOGE "Port ${WebPort} is busy; cannot proceed with issuance." + LOGE "端口 ${WebPort} 被占用,无法继续。" return 1 fi if ! [[ "${alt_port}" =~ ^[0-9]+$ ]] || ((alt_port < 1 || alt_port > 65535)); then - LOGE "Invalid port provided." + LOGE "无效端口。" return 1 fi WebPort="${alt_port}" continue else - LOGI "Port ${WebPort} is free and ready for standalone validation." + LOGI "端口 ${WebPort} 空闲,可以进行独立验证。" break fi done - - # 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 + + # 使用短期配置文件为 IP 签发证书 ~/.acme.sh/acme.sh --set-default-ca --server letsencrypt --force ~/.acme.sh/acme.sh --issue \ ${domain_args} \ @@ -1246,60 +1246,60 @@ ssl_cert_issue_for_ip() { --days 6 \ --httpport ${WebPort} \ --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} 已开放且服务器可从外网访问" + # 清理 acme.sh 数据(IPv4 和 IPv6) 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 可能在 reloadcmd 失败时报告 "Reload error" 并返回非零退出码, + # 但证书文件仍然已安装。我们通过检查文件而非退出码来判断。 ~/.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) + + # 验证证书文件存在(不依赖退出码 - reloadcmd 失败会导致非零) 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 "安装后未找到证书文件" + # 清理 acme.sh 数据(IPv4 和 IPv6) 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" - - # enable auto-renew + + LOGI "证书文件安装成功" + + # 启用自动续期 ~/.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 cron 自动续期)" + 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 } @@ -1307,17 +1307,17 @@ 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 + # 先检查 acme.sh 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.sh 失败,请查看日志" exit 1 fi fi - # install socat + # 安装 socat case "${release}" in ubuntu | debian | armbian) apt-get update >/dev/null 2>&1 && apt-get install socat -y >/dev/null 2>&1 @@ -1342,48 +1342,48 @@ 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" @@ -1392,162 +1392,162 @@ 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 --force ~/.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 "ACME 默认 --reloadcmd 为:${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}" + 2) + 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 + # 检查 acme.sh 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.sh 失败,请查看日志。" 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 + # 设置 Cloudflare API 信息 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 + # 设置默认 CA 为 Let's Encrypt ~/.acme.sh/acme.sh --set-default-ca --server letsencrypt --force if [ $? -ne 0 ]; then - LOGE "Default CA, Let'sEncrypt fail, script exiting..." + LOGE "设置默认 CA(Let's Encrypt)失败,脚本退出..." exit 1 fi export CF_Key="${CF_GlobalKey}" export CF_Email="${CF_AccountEmail}" - # Issue the certificate using Cloudflare DNS + # 使用 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}" if [ -d "$certPath" ]; then rm -rf ${certPath} @@ -1555,76 +1555,76 @@ ssl_cert_issue_CF() { 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 "ACME 默认 --reloadcmd 为:${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}" + 2) + 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 ~/.acme.sh/acme.sh --installcert -d ${CF_Domain} -d *.${CF_Domain} \ --key-file ${certPath}/privkey.pem \ --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 @@ -1632,15 +1632,15 @@ ssl_cert_issue_CF() { } run_speedtest() { - # Check if Speedtest is already installed + # 检查 Speedtest 是否已安装 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..." + # 使用 snap 安装 Speedtest + echo "正在使用 snap 安装 Speedtest..." snap install speedtest else - # Fallback to using package managers + # 回退到使用包管理器 local pkg_manager="" local speedtest_install_script="" @@ -1659,10 +1659,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 @@ -1680,24 +1680,24 @@ ip_validation() { } 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 @@ -1705,7 +1705,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 @@ -1714,19 +1714,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 ;; @@ -1735,24 +1735,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 ;; @@ -1777,7 +1777,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 @@ -1785,9 +1785,9 @@ 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 @@ -1825,41 +1825,41 @@ 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 + # 确保 jail 文件没有冲突 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 + # 检查服务日志文件是否存在,以免 fail2ban 报错 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 + # 创建 iplimit jail 文件 + # 此处不传递 bantime 以使用默认值 create_iplimit_jails - # Launching fail2ban + # 启动 fail2ban if [[ $release == "alpine" ]]; then if [[ $(rc-service fail2ban status | grep -F 'status: started' -c) == 0 ]]; then rc-service fail2ban start @@ -1876,15 +1876,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 @@ -1895,7 +1895,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) @@ -1916,7 +1916,7 @@ remove_iplimit() { dnf autoremove -y ;; centos) - if [[ "${VERSION_ID}" =~ ^7 ]]; then + if [[ "${VERSION_ID}" =~ ^7 ]]; then yum remove fail2ban -y yum autoremove -y else @@ -1931,18 +1931,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 @@ -1951,49 +1951,49 @@ 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}当前 jail 状态:${plain}" + fail2ban-client status 3x-ipl || echo -e "${yellow}无法获取 jail 状态${plain}" } create_iplimit_jails() { - # Use default bantime if not passed => 30 minutes + # 如未传递则使用默认封禁时长 => 30 分钟 local bantime="${1:-30}" - # Uncomment 'allowipv6 = auto' in fail2ban.conf + # 取消 fail2ban.conf 中 'allowipv6 = auto' 的注释 sed -i 's/#allowipv6 = auto/allowipv6 = auto/g' /etc/fail2ban/fail2ban.conf - # On Debian 12+ fail2ban's default backend should be changed to systemd + # 在 Debian 12+ 上,fail2ban 的默认后端应更改为 systemd if [[ "${release}" == "debian" && ${os_version} -ge 12 ]]; then sed -i '0,/action =/s/backend = auto/backend = systemd/' /etc/fail2ban/jail.conf fi @@ -2044,7 +2044,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 限制 jail 文件已创建,封禁时长为 ${bantime} 分钟。${plain}" } iplimit_remove_conflicts() { @@ -2054,10 +2054,10 @@ iplimit_remove_conflicts() { ) for file in "${jail_files[@]}"; do - # Check for [3x-ipl] config in jail file then remove it + # 检查 jail 文件中是否存在 [3x-ipl] 配置,如存在则移除 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}正在移除 jail (${file}) 中 [3x-ipl] 的冲突配置!${plain}\n" fi done } @@ -2092,66 +2092,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未配置 listenIP。请选择:" + 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 @@ -2159,68 +2159,68 @@ 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 restart-xray${plain} - Restart Xray │ -│ ${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 restart-xray${plain} - 重启 Xray │ +│ ${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} - 更新所有 geo 文件 │ +│ ${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} Restart Xray │ -│ ${green}15.${plain} Check Status │ -│ ${green}16.${plain} Logs Management │ +│ ${green}11.${plain} 启动 │ +│ ${green}12.${plain} 停止 │ +│ ${green}13.${plain} 重启 │ +| ${green}14.${plain} 重启 Xray │ +│ ${green}15.${plain} 查看状态 │ +│ ${green}16.${plain} 日志管理 │ │────────────────────────────────────────────────│ -│ ${green}17.${plain} Enable Autostart │ -│ ${green}18.${plain} Disable Autostart │ +│ ${green}17.${plain} 设置开机自启 │ +│ ${green}18.${plain} 取消开机自启 │ │────────────────────────────────────────────────│ -│ ${green}19.${plain} SSL Certificate Management │ -│ ${green}20.${plain} Cloudflare SSL Certificate │ -│ ${green}21.${plain} IP Limit Management │ -│ ${green}22.${plain} Firewall Management │ -│ ${green}23.${plain} SSH Port Forwarding Management │ +│ ${green}19.${plain} SSL 证书管理 │ +│ ${green}20.${plain} Cloudflare SSL 证书 │ +│ ${green}21.${plain} IP 限制管理 │ +│ ${green}22.${plain} 防火墙管理 │ +│ ${green}23.${plain} SSH 端口转发管理 │ │────────────────────────────────────────────────│ -│ ${green}24.${plain} Enable BBR │ -│ ${green}25.${plain} Update Geo Files │ -│ ${green}26.${plain} Speedtest by Ookla │ +│ ${green}24.${plain} BBR 管理 │ +│ ${green}25.${plain} 更新 Geo 文件 │ +│ ${green}26.${plain} 网速测试 (Speedtest) │ ╚────────────────────────────────────────────────╝ " show_status - echo && read -rp "Please enter your selection [0-26]: " num + echo && read -rp "请输入选择 [0-26]:" num case "${num}" in 0) @@ -2305,7 +2305,7 @@ show_menu() { run_speedtest ;; *) - LOGE "Please enter the correct number [0-26]" + LOGE "请输入正确的数字 [0-26]" ;; esac }