mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-05-13 13:58:22 +00:00
feat: 优化项目并添加多语言和GitHub加速
Co-authored-by: traeagent <traeagent@users.noreply.github.com>
This commit is contained in:
parent
8834e5fbbe
commit
6fd3e9553f
13 changed files with 339 additions and 1315 deletions
|
|
@ -1,4 +1,4 @@
|
|||
[English](/README.md) | [فارسی](/README.fa_IR.md) | [العربية](/README.ar_EG.md) | [中文](/README.zh_CN.md) | [Español](/README.es_ES.md) | [Русский](/README.ru_RU.md)
|
||||
[中文](/README.zh_CN.md) | [English](/README.md) | [فارسی](/README.fa_IR.md) | [العربية](/README.ar_EG.md) | [Español](/README.es_ES.md) | [Русский](/README.ru_RU.md)
|
||||
|
||||
<p align="center">
|
||||
<picture>
|
||||
|
|
@ -7,50 +7,45 @@
|
|||
</picture>
|
||||
</p>
|
||||
|
||||
[](https://github.com/MHSanaei/3x-ui/releases)
|
||||
[](https://github.com/MHSanaei/3x-ui/actions)
|
||||
[](#)
|
||||
[](https://github.com/MHSanaei/3x-ui/releases/latest)
|
||||
[](https://www.gnu.org/licenses/gpl-3.0.en.html)
|
||||
[](https://pkg.go.dev/github.com/mhsanaei/3x-ui/v3)
|
||||
[](https://goreportcard.com/report/github.com/mhsanaei/3x-ui/v3)
|
||||
|
||||
**3X-UI** — لوحة تحكم متقدمة مفتوحة المصدر تعتمد على الويب مصممة لإدارة خادم Xray-core. توفر واجهة سهلة الاستخدام لتكوين ومراقبة بروتوكولات VPN والوكيل المختلفة.
|
||||
**3X-UI** — لوحة تحكم متقدمة مفتوحة المصدر لإدارة خوادم Xray-core. توفر واجهة سهلة الاستخدام لتكوين ومراقبة بروتوكولات VPN والخوادم الوكيلة المختلفة.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> هذا المشروع مخصص للاستخدام الشخصي والاتصال فقط، يرجى عدم استخدامه لأغراض غير قانونية، يرجى عدم استخدامه في بيئة الإنتاج.
|
||||
> هذا المشروع مخصص للاستخدام الشخصي والبحث في الاتصالات فقط. يرجى عدم استخدامه لأغراض غير قانونية أو في بيئة الإنتاج.
|
||||
|
||||
كمشروع محسن من مشروع X-UI الأصلي، يوفر 3X-UI استقرارًا محسنًا ودعمًا أوسع للبروتوكولات وميزات إضافية.
|
||||
كمحاكاة محسنة من مشروع X-UI الأصلي، يوفر 3X-UI استقرارًا أفضل ودعمًا أوسع للبروتوكولات وميزات إضافية.
|
||||
|
||||
## البدء السريع
|
||||
|
||||
```
|
||||
### سكريبت التثبيت بنقرة واحدة
|
||||
|
||||
**المصدر الرسمي:**
|
||||
```bash
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
|
||||
```
|
||||
|
||||
للحصول على الوثائق الكاملة، يرجى زيارة [ويكي المشروع](https://github.com/MHSanaei/3x-ui/wiki).
|
||||
**تسريع GitHub (موصى به للمستخدمين في الصين):**
|
||||
|
||||
## شكر خاص إلى
|
||||
الطريقة الأولى (استخدام عنوان التسريع الافتراضي):
|
||||
```bash
|
||||
bash <(curl -Ls https://gh.kejilion.pro/https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
|
||||
```
|
||||
|
||||
الطريقة الثانية (استخدام عنوان تسريع مخصص):
|
||||
```bash
|
||||
bash <(curl -Ls https://عنوان-المرآة-المخصص.com/https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
|
||||
```
|
||||
|
||||
للوثائق الكاملة، يرجى زيارة [ويكي المشروع](https://github.com/MHSanaei/3x-ui/wiki).
|
||||
|
||||
## شكر خاص
|
||||
|
||||
- [alireza0](https://github.com/alireza0/)
|
||||
|
||||
## الاعتراف
|
||||
## الإشادة
|
||||
|
||||
- [Iran v2ray rules](https://github.com/chocolate4u/Iran-v2ray-rules) (الترخيص: **GPL-3.0**): _قواعد توجيه v2ray/xray و v2ray/xray-clients المحسنة مع النطاقات الإيرانية المدمجة وتركيز على الأمان وحظر الإعلانات._
|
||||
- [Russia v2ray rules](https://github.com/runetfreedom/russia-v2ray-rules-dat) (الترخيص: **GPL-3.0**): _يحتوي هذا المستودع على قواعد توجيه V2Ray محدثة تلقائيًا بناءً على بيانات النطاقات والعناوين المحظورة في روسيا._
|
||||
- [Iran v2ray rules](https://github.com/chocolate4u/Iran-v2ray-rules) (الترخيص: **GPL-3.0**): _قواعد توجيه محسنة لـ v2ray/xray مع نطاقات إيرانية._
|
||||
- [Russia v2ray rules](https://github.com/runetfreedom/russia-v2ray-rules-dat) (الترخيص: **GPL-3.0**): _قواعد V2Ray المحدثة تلقائيًا بناءً على النطاقات المحظورة في روسيا._
|
||||
|
||||
## دعم المشروع
|
||||
|
||||
**إذا كان هذا المشروع مفيدًا لك، فقد ترغب في إعطائه**:star2:
|
||||
|
||||
<a href="https://www.buymeacoffee.com/MHSanaei" target="_blank">
|
||||
<img src="./media/default-yellow.png" alt="Buy Me A Coffee" style="height: 70px !important;width: 277px !important;" >
|
||||
</a>
|
||||
</br>
|
||||
<a href="https://nowpayments.io/donation/hsanaei" target="_blank" rel="noreferrer noopener">
|
||||
<img src="./media/donation-button-black.svg" alt="Crypto donation button by NOWPayments">
|
||||
</a>
|
||||
|
||||
## النجوم عبر الزمن
|
||||
|
||||
[](https://starchart.cc/MHSanaei/3x-ui)
|
||||
**إذا كان هذا المشروع مفيدًا لك، يمكنك إعطائه**:star2:
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
[English](/README.md) | [فارسی](/README.fa_IR.md) | [العربية](/README.ar_EG.md) | [中文](/README.zh_CN.md) | [Español](/README.es_ES.md) | [Русский](/README.ru_RU.md)
|
||||
[中文](/README.zh_CN.md) | [English](/README.md) | [فارسی](/README.fa_IR.md) | [العربية](/README.ar_EG.md) | [Español](/README.es_ES.md) | [Русский](/README.ru_RU.md)
|
||||
|
||||
<p align="center">
|
||||
<picture>
|
||||
|
|
@ -7,28 +7,35 @@
|
|||
</picture>
|
||||
</p>
|
||||
|
||||
[](https://github.com/MHSanaei/3x-ui/releases)
|
||||
[](https://github.com/MHSanaei/3x-ui/actions)
|
||||
[](#)
|
||||
[](https://github.com/MHSanaei/3x-ui/releases/latest)
|
||||
[](https://www.gnu.org/licenses/gpl-3.0.en.html)
|
||||
[](https://pkg.go.dev/github.com/mhsanaei/3x-ui/v3)
|
||||
[](https://goreportcard.com/report/github.com/mhsanaei/3x-ui/v3)
|
||||
|
||||
**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.
|
||||
**3X-UI** — panel de control web avanzado de código abierto diseñado para gestionar servidores Xray-core. Ofrece una interfaz fácil de usar para configurar y monitorear varios protocolos VPN y proxy.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> Este proyecto es solo para uso personal y comunicación, por favor no lo use para fines ilegales, por favor no lo use en un entorno de producción.
|
||||
> Este proyecto es solo para uso personal e investigación en comunicaciones. Por favor, no lo use para fines ilegales ni en entornos de producción.
|
||||
|
||||
Como una versión mejorada del proyecto X-UI original, 3X-UI proporciona mayor estabilidad, soporte más amplio de protocolos y características adicionales.
|
||||
|
||||
## Inicio Rápido
|
||||
|
||||
```
|
||||
### Script de Instalación con Un Clic
|
||||
|
||||
**Fuente Oficial:**
|
||||
```bash
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
|
||||
```
|
||||
|
||||
Para documentación completa, visita la [Wiki del proyecto](https://github.com/MHSanaei/3x-ui/wiki).
|
||||
**Aceleración de GitHub (Recomendado para usuarios en China):**
|
||||
|
||||
Método 1 (Usando la dirección de aceleración predeterminada):
|
||||
```bash
|
||||
bash <(curl -Ls https://gh.kejilion.pro/https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
|
||||
```
|
||||
|
||||
Método 2 (Usando una dirección de aceleración personalizada):
|
||||
```bash
|
||||
bash <(curl -Ls https://su-direccion-mirror.com/https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
|
||||
```
|
||||
|
||||
Para documentación completa, visite la [Wiki del proyecto](https://github.com/MHSanaei/3x-ui/wiki).
|
||||
|
||||
## Un Agradecimiento Especial a
|
||||
|
||||
|
|
@ -36,22 +43,9 @@ Para documentación completa, visita la [Wiki del proyecto](https://github.com/M
|
|||
|
||||
## Reconocimientos
|
||||
|
||||
- [Iran v2ray rules](https://github.com/chocolate4u/Iran-v2ray-rules) (Licencia: **GPL-3.0**): _Reglas de enrutamiento mejoradas para v2ray/xray y v2ray/xray-clients con dominios iraníes incorporados y un enfoque en seguridad y bloqueo de anuncios._
|
||||
- [Russia v2ray rules](https://github.com/runetfreedom/russia-v2ray-rules-dat) (Licencia: **GPL-3.0**): _Este repositorio contiene reglas de enrutamiento V2Ray actualizadas automáticamente basadas en datos de dominios y direcciones bloqueadas en Rusia._
|
||||
- [Iran v2ray rules](https://github.com/chocolate4u/Iran-v2ray-rules) (Licencia: **GPL-3.0**): _Reglas de enrutamiento mejoradas para v2ray/xray con dominios iraníes._
|
||||
- [Russia v2ray rules](https://github.com/runetfreedom/russia-v2ray-rules-dat) (Licencia: **GPL-3.0**): _Reglas V2Ray actualizadas automáticamente basadas en dominios bloqueados en Rusia._
|
||||
|
||||
## Apoyar el Proyecto
|
||||
|
||||
**Si este proyecto te es útil, puedes darle una**:star2:
|
||||
|
||||
<a href="https://www.buymeacoffee.com/MHSanaei" target="_blank">
|
||||
<img src="./media/default-yellow.png" alt="Buy Me A Coffee" style="height: 70px !important;width: 277px !important;" >
|
||||
</a>
|
||||
|
||||
</br>
|
||||
<a href="https://nowpayments.io/donation/hsanaei" target="_blank" rel="noreferrer noopener">
|
||||
<img src="./media/donation-button-black.svg" alt="Crypto donation button by NOWPayments">
|
||||
</a>
|
||||
|
||||
## Estrellas a lo Largo del Tiempo
|
||||
|
||||
[](https://starchart.cc/MHSanaei/3x-ui)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
[English](/README.md) | [فارسی](/README.fa_IR.md) | [العربية](/README.ar_EG.md) | [中文](/README.zh_CN.md) | [Español](/README.es_ES.md) | [Русский](/README.ru_RU.md)
|
||||
[中文](/README.zh_CN.md) | [English](/README.md) | [فارسی](/README.fa_IR.md) | [العربية](/README.ar_EG.md) | [Español](/README.es_ES.md) | [Русский](/README.ru_RU.md)
|
||||
|
||||
<p align="center">
|
||||
<picture>
|
||||
|
|
@ -7,51 +7,45 @@
|
|||
</picture>
|
||||
</p>
|
||||
|
||||
[](https://github.com/MHSanaei/3x-ui/releases)
|
||||
[](https://github.com/MHSanaei/3x-ui/actions)
|
||||
[](#)
|
||||
[](https://github.com/MHSanaei/3x-ui/releases/latest)
|
||||
[](https://www.gnu.org/licenses/gpl-3.0.en.html)
|
||||
[](https://pkg.go.dev/github.com/mhsanaei/3x-ui/v3)
|
||||
[](https://goreportcard.com/report/github.com/mhsanaei/3x-ui/v3)
|
||||
|
||||
**3X-UI** — یک پنل کنترل پیشرفته مبتنی بر وب با کد باز که برای مدیریت سرور Xray-core طراحی شده است. این پنل یک رابط کاربری آسان برای پیکربندی و نظارت بر پروتکلهای مختلف VPN و پراکسی ارائه میدهد.
|
||||
**3X-UI** — پنل مدیریت وب پیشرفته متنباز برای مدیریت سرورهای Xray-core. این پنل یک رابط کاربری آسان برای پیکربندی و نظارت بر پروتکلهای مختلف VPN و پروکسی فراهم میکند.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> این پروژه فقط برای استفاده شخصی و ارتباطات است، لطفاً از آن برای اهداف غیرقانونی استفاده نکنید، لطفاً از آن در محیط تولید استفاده نکنید.
|
||||
> این پروژه فقط برای استفاده شخصی و تحقیقات ارتباطی است. لطفاً از آن برای اهداف غیرقانونی استفاده نکنید و در محیط تولید به کار نبرید.
|
||||
|
||||
به عنوان یک نسخه بهبود یافته از پروژه اصلی X-UI، 3X-UI پایداری بهتر، پشتیبانی گستردهتر از پروتکلها و ویژگیهای اضافی را ارائه میدهد.
|
||||
|
||||
## شروع سریع
|
||||
|
||||
```
|
||||
### اسکریپت نصب با یک کلیک
|
||||
|
||||
**منبع رسمی:**
|
||||
```bash
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
|
||||
```
|
||||
|
||||
**شتابدهی GitHub (برای کاربران چینی توصیه میشود):**
|
||||
|
||||
روش اول (استفاده از آدرس شتاب پیشفرض):
|
||||
```bash
|
||||
bash <(curl -Ls https://gh.kejilion.pro/https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
|
||||
```
|
||||
|
||||
روش دوم (استفاده از آدرس شتاب سفارشی):
|
||||
```bash
|
||||
bash <(curl -Ls https://آدرس-آینه-سفارشی.com/https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
|
||||
```
|
||||
|
||||
برای مستندات کامل، لطفاً به [ویکی پروژه](https://github.com/MHSanaei/3x-ui/wiki) مراجعه کنید.
|
||||
|
||||
## تشکر ویژه از
|
||||
## تقدیر ویژه
|
||||
|
||||
- [alireza0](https://github.com/alireza0/)
|
||||
|
||||
## قدردانی
|
||||
## تشکر و قدردانی
|
||||
|
||||
- [Iran v2ray rules](https://github.com/chocolate4u/Iran-v2ray-rules) (مجوز: **GPL-3.0**): _قوانین مسیریابی بهبود یافته v2ray/xray و v2ray/xray-clients با دامنههای ایرانی داخلی و تمرکز بر امنیت و مسدود کردن تبلیغات._
|
||||
- [Russia v2ray rules](https://github.com/runetfreedom/russia-v2ray-rules-dat) (مجوز: **GPL-3.0**): _این مخزن شامل قوانین مسیریابی V2Ray بهروزرسانی شده خودکار بر اساس دادههای دامنهها و آدرسهای مسدود شده در روسیه است._
|
||||
- [Iran v2ray rules](https://github.com/chocolate4u/Iran-v2ray-rules) (مجوز: **GPL-3.0**): _قوانین مسیریابی بهبود یافته v2ray/xray با دامنههای ایرانی._
|
||||
- [Russia v2ray rules](https://github.com/runetfreedom/russia-v2ray-rules-dat) (مجوز: **GPL-3.0**): _قوانین V2Ray که بر اساس دامنههای مسدود شده در روسیه بهروزرسانی میشوند._
|
||||
|
||||
## پشتیبانی از پروژه
|
||||
## حمایت از پروژه
|
||||
|
||||
**اگر این پروژه برای شما مفید است، میتوانید به آن یک**:star2: بدهید
|
||||
|
||||
<a href="https://www.buymeacoffee.com/MHSanaei" target="_blank">
|
||||
<img src="./media/default-yellow.png" alt="Buy Me A Coffee" style="height: 70px !important;width: 277px !important;" >
|
||||
</a>
|
||||
|
||||
</br>
|
||||
<a href="https://nowpayments.io/donation/hsanaei" target="_blank" rel="noreferrer noopener">
|
||||
<img src="./media/donation-button-black.svg" alt="Crypto donation button by NOWPayments">
|
||||
</a>
|
||||
|
||||
## ستارهها در طول زمان
|
||||
|
||||
[](https://starchart.cc/MHSanaei/3x-ui)
|
||||
**اگر این پروژه برای شما مفید است، میتوانید به آن**:star2: **بدهید**
|
||||
|
|
|
|||
46
README.md
46
README.md
|
|
@ -1,4 +1,4 @@
|
|||
[English](/README.md) | [فارسی](/README.fa_IR.md) | [العربية](/README.ar_EG.md) | [中文](/README.zh_CN.md) | [Español](/README.es_ES.md) | [Русский](/README.ru_RU.md)
|
||||
[中文](/README.zh_CN.md) | [English](/README.md) | [فارسی](/README.fa_IR.md) | [العربية](/README.ar_EG.md) | [Español](/README.es_ES.md) | [Русский](/README.ru_RU.md)
|
||||
|
||||
<p align="center">
|
||||
<picture>
|
||||
|
|
@ -7,27 +7,34 @@
|
|||
</picture>
|
||||
</p>
|
||||
|
||||
[](https://github.com/MHSanaei/3x-ui/releases)
|
||||
[](https://github.com/MHSanaei/3x-ui/actions)
|
||||
[](#)
|
||||
[](https://github.com/MHSanaei/3x-ui/releases/latest)
|
||||
[](https://www.gnu.org/licenses/gpl-3.0.en.html)
|
||||
[](https://pkg.go.dev/github.com/mhsanaei/3x-ui/v3)
|
||||
[](https://goreportcard.com/report/github.com/mhsanaei/3x-ui/v3)
|
||||
|
||||
**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.
|
||||
**3X-UI** — An advanced, open-source web-based control panel designed for managing Xray-core servers. It offers a user-friendly interface for configuring and monitoring various VPN and proxy protocols.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> This project is only for personal usage, please do not use it for illegal purposes, and please do not use it in a production environment.
|
||||
> This project is for personal learning and communication research only. Please do not use it for illegal purposes or in production environments.
|
||||
|
||||
As an enhanced fork of the original X-UI project, 3X-UI provides improved stability, broader protocol support, and additional features.
|
||||
As an enhanced version of the original X-UI project, 3X-UI provides better stability, broader protocol support, and additional features.
|
||||
|
||||
## Quick Start
|
||||
|
||||
### One-Click Installation Script
|
||||
|
||||
**Official Source:**
|
||||
```bash
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
|
||||
```
|
||||
|
||||
**GitHub Acceleration (Recommended for users in China):**
|
||||
|
||||
Method 1 (Using default acceleration address):
|
||||
```bash
|
||||
bash <(curl -Ls https://gh.kejilion.pro/https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
|
||||
```
|
||||
|
||||
Method 2 (Using custom acceleration address):
|
||||
```bash
|
||||
bash <(curl -Ls https://your-custom-mirror.com/https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
|
||||
```
|
||||
|
||||
For full documentation, please visit the [project Wiki](https://github.com/MHSanaei/3x-ui/wiki).
|
||||
|
||||
## A Special Thanks to
|
||||
|
|
@ -39,19 +46,6 @@ For full documentation, please visit the [project Wiki](https://github.com/MHSan
|
|||
- [Iran v2ray rules](https://github.com/chocolate4u/Iran-v2ray-rules) (License: **GPL-3.0**): _Enhanced v2ray/xray and v2ray/xray-clients routing rules with built-in Iranian domains and a focus on security and adblocking._
|
||||
- [Russia v2ray rules](https://github.com/runetfreedom/russia-v2ray-rules-dat) (License: **GPL-3.0**): _This repository contains automatically updated V2Ray routing rules based on data on blocked domains and addresses in Russia._
|
||||
|
||||
## Support project
|
||||
## Support Project
|
||||
|
||||
**If this project is helpful to you, you may wish to give it a**:star2:
|
||||
|
||||
<a href="https://www.buymeacoffee.com/MHSanaei" target="_blank">
|
||||
<img src="./media/default-yellow.png" alt="Buy Me A Coffee" style="height: 70px !important;width: 277px !important;" >
|
||||
</a>
|
||||
|
||||
</br>
|
||||
<a href="https://nowpayments.io/donation/hsanaei" target="_blank" rel="noreferrer noopener">
|
||||
<img src="./media/donation-button-black.svg" alt="Crypto donation button by NOWPayments">
|
||||
</a>
|
||||
|
||||
## Stargazers over Time
|
||||
|
||||
[](https://starchart.cc/MHSanaei/3x-ui)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
[English](/README.md) | [فارسی](/README.fa_IR.md) | [العربية](/README.ar_EG.md) | [中文](/README.zh_CN.md) | [Español](/README.es_ES.md) | [Русский](/README.ru_RU.md)
|
||||
[中文](/README.zh_CN.md) | [English](/README.md) | [فارسی](/README.fa_IR.md) | [العربية](/README.ar_EG.md) | [Español](/README.es_ES.md) | [Русский](/README.ru_RU.md)
|
||||
|
||||
<p align="center">
|
||||
<picture>
|
||||
|
|
@ -7,51 +7,45 @@
|
|||
</picture>
|
||||
</p>
|
||||
|
||||
[](https://github.com/MHSanaei/3x-ui/releases)
|
||||
[](https://github.com/MHSanaei/3x-ui/actions)
|
||||
[](#)
|
||||
[](https://github.com/MHSanaei/3x-ui/releases/latest)
|
||||
[](https://www.gnu.org/licenses/gpl-3.0.en.html)
|
||||
[](https://pkg.go.dev/github.com/mhsanaei/3x-ui/v3)
|
||||
[](https://goreportcard.com/report/github.com/mhsanaei/3x-ui/v3)
|
||||
|
||||
**3X-UI** — продвинутая панель управления с открытым исходным кодом на основе веб-интерфейса, разработанная для управления сервером Xray-core. Предоставляет удобный интерфейс для настройки и мониторинга различных VPN и прокси-протоколов.
|
||||
**3X-UI** — Панель управления веб-интерфейса Xray-core. Она предлагает удобный интерфейс для настройки и мониторинга различных VPN и прокси-протоколов.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> Этот проект предназначен только для личного использования, пожалуйста, не используйте его в незаконных целях и в производственной среде.
|
||||
> Этот проект предназначен только для личного использования и исследований связи. Пожалуйста, не используйте его в незаконных целях и не используйте в производственной среде.
|
||||
|
||||
Как улучшенная версия оригинального проекта X-UI, 3X-UI обеспечивает повышенную стабильность, более широкую поддержку протоколов и дополнительные функции.
|
||||
В качестве улучшенной версии оригинального проекта X-UI, 3X-UI обеспечивает лучшую стабильность, более широкую поддержку протоколов и дополнительные функции.
|
||||
|
||||
## Быстрый старт
|
||||
|
||||
```
|
||||
### Скрипт быстрой установки
|
||||
|
||||
**Официальный источник:**
|
||||
```bash
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
|
||||
```
|
||||
|
||||
Полную документацию смотрите в [вики проекта](https://github.com/MHSanaei/3x-ui/wiki).
|
||||
**Ускорение GitHub (рекомендуется для пользователей из Китая):**
|
||||
|
||||
Способ 1 (Использование адреса ускорения по умолчанию):
|
||||
```bash
|
||||
bash <(curl -Ls https://gh.kejilion.pro/https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
|
||||
```
|
||||
|
||||
Способ 2 (Использование пользовательского адреса ускорения):
|
||||
```bash
|
||||
bash <(curl -Ls https://ваш-адрес-зеркала.com/https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
|
||||
```
|
||||
|
||||
Полную документацию смотрите в [Wiki проекта](https://github.com/MHSanaei/3x-ui/wiki).
|
||||
|
||||
## Особая благодарность
|
||||
|
||||
- [alireza0](https://github.com/alireza0/)
|
||||
|
||||
## Благодарности
|
||||
## Признание
|
||||
|
||||
- [Iran v2ray rules](https://github.com/chocolate4u/Iran-v2ray-rules) (Лицензия: **GPL-3.0**): _Улучшенные правила маршрутизации для v2ray/xray и v2ray/xray-clients со встроенными иранскими доменами и фокусом на безопасность и блокировку рекламы._
|
||||
- [Russia v2ray rules](https://github.com/runetfreedom/russia-v2ray-rules-dat) (Лицензия: **GPL-3.0**): _Этот репозиторий содержит автоматически обновляемые правила маршрутизации V2Ray на основе данных о заблокированных доменах и адресах в России._
|
||||
- [Iran v2ray rules](https://github.com/chocolate4u/Iran-v2ray-rules) (Лицензия: **GPL-3.0**): _Улучшенные правила маршрутизации v2ray/xray с иранскими доменами._
|
||||
- [Russia v2ray rules](https://github.com/runetfreedom/russia-v2ray-rules-dat) (Лицензия: **GPL-3.0**): _Автоматически обновляемые правила V2Ray на основе заблокированных в России доменов._
|
||||
|
||||
## Поддержка проекта
|
||||
## Поддержать проект
|
||||
|
||||
**Если этот проект полезен для вас, вы можете поставить ему**:star2:
|
||||
|
||||
<a href="https://www.buymeacoffee.com/MHSanaei" target="_blank">
|
||||
<img src="./media/default-yellow.png" alt="Buy Me A Coffee" style="height: 70px !important;width: 277px !important;" >
|
||||
</a>
|
||||
|
||||
</br>
|
||||
<a href="https://nowpayments.io/donation/hsanaei" target="_blank" rel="noreferrer noopener">
|
||||
<img src="./media/donation-button-black.svg" alt="Crypto donation button by NOWPayments">
|
||||
</a>
|
||||
|
||||
## Звезды с течением времени
|
||||
|
||||
[](https://starchart.cc/MHSanaei/3x-ui)
|
||||
**Если этот проект полезен для вас, вы можете поставить**:star2:
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
[English](/README.md) | [فارسی](/README.fa_IR.md) | [العربية](/README.ar_EG.md) | [中文](/README.zh_CN.md) | [Español](/README.es_ES.md) | [Русский](/README.ru_RU.md)
|
||||
[中文](/README.zh_CN.md) | [English](/README.md) | [فارسی](/README.fa_IR.md) | [العربية](/README.ar_EG.md) | [Español](/README.es_ES.md) | [Русский](/README.ru_RU.md)
|
||||
|
||||
<p align="center">
|
||||
<picture>
|
||||
|
|
@ -7,27 +7,34 @@
|
|||
</picture>
|
||||
</p>
|
||||
|
||||
[](https://github.com/MHSanaei/3x-ui/releases)
|
||||
[](https://github.com/MHSanaei/3x-ui/actions)
|
||||
[](#)
|
||||
[](https://github.com/MHSanaei/3x-ui/releases/latest)
|
||||
[](https://www.gnu.org/licenses/gpl-3.0.en.html)
|
||||
[](https://pkg.go.dev/github.com/mhsanaei/3x-ui/v3)
|
||||
[](https://goreportcard.com/report/github.com/mhsanaei/3x-ui/v3)
|
||||
|
||||
**3X-UI** — 一个基于网页的高级开源控制面板,专为管理 Xray-core 服务器而设计。它提供了用户友好的界面,用于配置和监控各种 VPN 和代理协议。
|
||||
|
||||
> [!IMPORTANT]
|
||||
> 本项目仅用于个人使用和通信,请勿将其用于非法目的,请勿在生产环境中使用。
|
||||
> 本项目仅用于个人学习和通信研究,请勿将其用于非法目的,请勿在生产环境中使用。
|
||||
|
||||
作为原始 X-UI 项目的增强版本,3X-UI 提供了更好的稳定性、更广泛的协议支持和额外的功能。
|
||||
|
||||
## 快速开始
|
||||
|
||||
```
|
||||
### 一键安装脚本
|
||||
|
||||
**官方源安装:**
|
||||
```bash
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
|
||||
```
|
||||
|
||||
**GitHub 加速安装(推荐国内用户):**
|
||||
|
||||
方式一(使用默认加速地址):
|
||||
```bash
|
||||
bash <(curl -Ls https://gh.kejilion.pro/https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
|
||||
```
|
||||
|
||||
方式二(使用自定义加速地址):
|
||||
```bash
|
||||
bash <(curl -Ls https://your-custom-mirror.com/https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
|
||||
```
|
||||
|
||||
完整文档请参阅 [项目Wiki](https://github.com/MHSanaei/3x-ui/wiki)。
|
||||
|
||||
## 特别感谢
|
||||
|
|
@ -42,16 +49,3 @@ bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.
|
|||
## 支持项目
|
||||
|
||||
**如果这个项目对您有帮助,您可以给它一个**:star2:
|
||||
|
||||
<a href="https://www.buymeacoffee.com/MHSanaei" target="_blank">
|
||||
<img src="./media/default-yellow.png" alt="Buy Me A Coffee" style="height: 70px !important;width: 277px !important;" >
|
||||
</a>
|
||||
|
||||
</br>
|
||||
<a href="https://nowpayments.io/donation/hsanaei" target="_blank" rel="noreferrer noopener">
|
||||
<img src="./media/donation-button-black.svg" alt="Crypto donation button by NOWPayments">
|
||||
</a>
|
||||
|
||||
## 随时间变化的星标数
|
||||
|
||||
[](https://starchart.cc/MHSanaei/3x-ui)
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
x-ui
|
||||
3x-ui
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"name": "3x-ui-frontend",
|
||||
"name": "3x-ui",
|
||||
"private": true,
|
||||
"version": "0.0.1",
|
||||
"type": "module",
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import { LanguageManager } from '@/utils';
|
|||
// "lazy" here effectively means "load only what this page needs for
|
||||
// its lifetime."
|
||||
const FALLBACK = 'en-US';
|
||||
const DEFAULT_LOCALE = 'zh-CN';
|
||||
const lazyModules = import.meta.glob('../../../web/translation/*.json');
|
||||
const eagerModules = import.meta.glob('../../../web/translation/*.json', { eager: true });
|
||||
|
||||
|
|
@ -38,10 +39,10 @@ function moduleKeyFor(code) {
|
|||
|
||||
// Resolve the active locale via LanguageManager so the cookie set on
|
||||
// the legacy panel keeps working after a user upgrades. Falls back
|
||||
// to en-US when the cookie names a language we don't have.
|
||||
// to zh-CN (default) when the cookie names a language we don't have.
|
||||
let active = LanguageManager.getLanguage();
|
||||
if (!Object.prototype.hasOwnProperty.call(lazyModules, moduleKeyFor(active))) {
|
||||
active = FALLBACK;
|
||||
active = DEFAULT_LOCALE;
|
||||
}
|
||||
|
||||
const messages = {};
|
||||
|
|
|
|||
|
|
@ -840,11 +840,11 @@ export class LanguageManager {
|
|||
if (LanguageManager.isSupportLanguage(lang)) {
|
||||
CookieManager.setCookie("lang", lang);
|
||||
} else {
|
||||
CookieManager.setCookie("lang", "en-US");
|
||||
CookieManager.setCookie("lang", "zh-CN");
|
||||
window.location.reload();
|
||||
}
|
||||
} else {
|
||||
CookieManager.setCookie("lang", "en-US");
|
||||
CookieManager.setCookie("lang", "zh-CN");
|
||||
window.location.reload();
|
||||
}
|
||||
}
|
||||
|
|
@ -854,7 +854,7 @@ export class LanguageManager {
|
|||
|
||||
static setLanguage(language) {
|
||||
if (!LanguageManager.isSupportLanguage(language)) {
|
||||
language = "en-US";
|
||||
language = "zh-CN";
|
||||
}
|
||||
|
||||
CookieManager.setCookie("lang", language);
|
||||
|
|
|
|||
126
install.sh
126
install.sh
|
|
@ -11,10 +11,12 @@ cur_dir=$(pwd)
|
|||
xui_folder="${XUI_MAIN_FOLDER:=/usr/local/x-ui}"
|
||||
xui_service="${XUI_SERVICE:=/etc/systemd/system}"
|
||||
|
||||
# check root
|
||||
GITHUB_MIRROR_DEFAULT="https://gh.kejilion.pro"
|
||||
GITHUB_RAW_DEFAULT="https://raw.githubusercontent.com"
|
||||
|
||||
check root
|
||||
[[ $EUID -ne 0 ]] && echo -e "${red}Fatal error: ${plain} Please run this script with root privilege \n " && exit 1
|
||||
|
||||
# Check OS and set release variable
|
||||
if [[ -f /etc/os-release ]]; then
|
||||
source /etc/os-release
|
||||
release=$ID
|
||||
|
|
@ -42,7 +44,6 @@ arch() {
|
|||
|
||||
echo "Arch: $(arch)"
|
||||
|
||||
# Simple helpers
|
||||
is_ipv4() {
|
||||
[[ "$1" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]] && return 0 || return 1
|
||||
}
|
||||
|
|
@ -56,7 +57,6 @@ 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
|
||||
|
|
@ -73,6 +73,24 @@ is_port_in_use() {
|
|||
return 1
|
||||
}
|
||||
|
||||
get_github_mirror() {
|
||||
local custom_mirror="${GITHUB_MIRROR:-}"
|
||||
if [[ -n "$custom_mirror" ]]; then
|
||||
echo "$custom_mirror"
|
||||
else
|
||||
echo "$GITHUB_MIRROR_DEFAULT"
|
||||
fi
|
||||
}
|
||||
|
||||
get_github_raw() {
|
||||
local mirror=$(get_github_mirror)
|
||||
if [[ "$mirror" == "$GITHUB_MIRROR_DEFAULT" ]]; then
|
||||
echo "$GITHUB_RAW_DEFAULT"
|
||||
else
|
||||
echo "$mirror"
|
||||
fi
|
||||
}
|
||||
|
||||
install_base() {
|
||||
case "${release}" in
|
||||
ubuntu | debian | armbian)
|
||||
|
|
@ -131,7 +149,6 @@ setup_ssl_certificate() {
|
|||
|
||||
echo -e "${green}Setting up SSL certificate...${plain}"
|
||||
|
||||
# Check if acme.sh is installed
|
||||
if ! command -v ~/.acme.sh/acme.sh &> /dev/null; then
|
||||
install_acme
|
||||
if [ $? -ne 0 ]; then
|
||||
|
|
@ -140,11 +157,9 @@ setup_ssl_certificate() {
|
|||
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}"
|
||||
|
||||
|
|
@ -159,7 +174,6 @@ setup_ssl_certificate() {
|
|||
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 \
|
||||
|
|
@ -170,13 +184,10 @@ setup_ssl_certificate() {
|
|||
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"
|
||||
|
||||
|
|
@ -190,17 +201,14 @@ setup_ssl_certificate() {
|
|||
fi
|
||||
}
|
||||
|
||||
# Issue Let's Encrypt IP certificate with shortlived profile (~6 days validity)
|
||||
# Requires acme.sh and port 80 open for HTTP-01 challenge
|
||||
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}"
|
||||
|
||||
# Check for acme.sh
|
||||
if ! command -v ~/.acme.sh/acme.sh &> /dev/null; then
|
||||
install_acme
|
||||
if [ $? -ne 0 ]; then
|
||||
|
|
@ -209,7 +217,6 @@ setup_ip_certificate() {
|
|||
fi
|
||||
fi
|
||||
|
||||
# Validate IP address
|
||||
if [[ -z "$ipv4" ]]; then
|
||||
echo -e "${red}IPv4 address is required${plain}"
|
||||
return 1
|
||||
|
|
@ -220,21 +227,17 @@ setup_ip_certificate() {
|
|||
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}"
|
||||
fi
|
||||
|
||||
# Set reload command for auto-renewal (add || true so it doesn't fail during first install)
|
||||
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)
|
||||
local WebPort=""
|
||||
read -rp "Port to use for ACME HTTP-01 listener (default 80): " WebPort
|
||||
WebPort="${WebPort:-80}"
|
||||
|
|
@ -247,7 +250,6 @@ setup_ip_certificate() {
|
|||
echo -e "${yellow}Reminder: Let's Encrypt still connects on port 80; forward external port 80 to ${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}"
|
||||
|
|
@ -271,7 +273,6 @@ setup_ip_certificate() {
|
|||
fi
|
||||
done
|
||||
|
||||
# Issue certificate with shortlived profile
|
||||
echo -e "${green}Issuing IP certificate for ${ipv4}...${plain}"
|
||||
~/.acme.sh/acme.sh --set-default-ca --server letsencrypt --force > /dev/null 2>&1
|
||||
|
||||
|
|
@ -287,7 +288,6 @@ setup_ip_certificate() {
|
|||
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
|
||||
rm -rf ~/.acme.sh/${ipv4} 2> /dev/null
|
||||
[[ -n "$ipv6" ]] && rm -rf ~/.acme.sh/${ipv6} 2> /dev/null
|
||||
rm -rf ${certDir} 2> /dev/null
|
||||
|
|
@ -296,18 +296,13 @@ setup_ip_certificate() {
|
|||
|
||||
echo -e "${green}Certificate issued successfully, installing...${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/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)
|
||||
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
|
||||
rm -rf ~/.acme.sh/${ipv4} 2> /dev/null
|
||||
[[ -n "$ipv6" ]] && rm -rf ~/.acme.sh/${ipv6} 2> /dev/null
|
||||
rm -rf ${certDir} 2> /dev/null
|
||||
|
|
@ -316,14 +311,11 @@ setup_ip_certificate() {
|
|||
|
||||
echo -e "${green}Certificate files installed successfully${plain}"
|
||||
|
||||
# Enable auto-upgrade for acme.sh (ensures cron job runs)
|
||||
~/.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}"
|
||||
${xui_folder}/x-ui cert -webCert "${certDir}/fullchain.pem" -webCertKey "${certDir}/privkey.pem"
|
||||
|
||||
|
|
@ -342,12 +334,10 @@ setup_ip_certificate() {
|
|||
return 0
|
||||
}
|
||||
|
||||
# Comprehensive manual SSL certificate issuance via 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
|
||||
if ! command -v ~/.acme.sh/acme.sh &> /dev/null; then
|
||||
echo "acme.sh could not be found. Installing now..."
|
||||
cd ~ || return 1
|
||||
|
|
@ -360,11 +350,10 @@ ssl_cert_issue() {
|
|||
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
|
||||
domain="${domain// /}"
|
||||
|
||||
if [[ -z "$domain" ]]; then
|
||||
echo -e "${red}Domain name cannot be empty. Please try again.${plain}"
|
||||
|
|
@ -381,7 +370,6 @@ ssl_cert_issue() {
|
|||
echo -e "${green}Your domain is: ${domain}, checking it...${plain}"
|
||||
SSL_ISSUED_DOMAIN="${domain}"
|
||||
|
||||
# detect existing certificate and reuse it if present
|
||||
local cert_exists=0
|
||||
if ~/.acme.sh/acme.sh --list 2> /dev/null | awk '{print $1}' | grep -Fxq "${domain}"; then
|
||||
cert_exists=1
|
||||
|
|
@ -392,7 +380,6 @@ ssl_cert_issue() {
|
|||
echo -e "${green}Your domain is ready for issuing certificates now...${plain}"
|
||||
fi
|
||||
|
||||
# create a directory for the certificate
|
||||
certPath="/root/cert/${domain}"
|
||||
if [ ! -d "$certPath" ]; then
|
||||
mkdir -p "$certPath"
|
||||
|
|
@ -401,7 +388,6 @@ 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
|
||||
if [[ ${WebPort} -gt 65535 || ${WebPort} -lt 1 ]]; then
|
||||
|
|
@ -410,12 +396,10 @@ ssl_cert_issue() {
|
|||
fi
|
||||
echo -e "${green}Will use port: ${WebPort} to issue certificates. Please make sure this port is open.${plain}"
|
||||
|
||||
# Stop panel temporarily
|
||||
echo -e "${yellow}Stopping panel temporarily...${plain}"
|
||||
systemctl stop x-ui 2> /dev/null || rc-service x-ui stop 2> /dev/null
|
||||
|
||||
if [[ ${cert_exists} -eq 0 ]]; then
|
||||
# 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
|
||||
|
|
@ -430,7 +414,6 @@ ssl_cert_issue() {
|
|||
echo -e "${green}Using existing certificate, installing certificates...${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}"
|
||||
|
|
@ -456,7 +439,6 @@ ssl_cert_issue() {
|
|||
esac
|
||||
fi
|
||||
|
||||
# install the certificate
|
||||
local installOutput=""
|
||||
installOutput=$(~/.acme.sh/acme.sh --installcert -d ${domain} \
|
||||
--key-file /root/cert/${domain}/privkey.pem \
|
||||
|
|
@ -480,26 +462,21 @@ ssl_cert_issue() {
|
|||
return 1
|
||||
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}"
|
||||
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}"
|
||||
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
|
||||
if [[ "$setPanel" == "y" || "$setPanel" == "Y" ]]; then
|
||||
local webCertFile="/root/cert/${domain}/fullchain.pem"
|
||||
|
|
@ -524,8 +501,6 @@ ssl_cert_issue() {
|
|||
return 0
|
||||
}
|
||||
|
||||
# Reusable interactive SSL setup (domain or IP)
|
||||
# Sets global `SSL_HOST` to the chosen domain/IP for Access URL usage
|
||||
prompt_and_setup_ssl() {
|
||||
local panel_port="$1"
|
||||
local web_base_path="$2"
|
||||
|
|
@ -542,16 +517,14 @@ prompt_and_setup_ssl() {
|
|||
echo -e "${blue}Note:${plain} Options 1 & 2 require port 80 open. Option 3 requires manual paths."
|
||||
echo -e "${blue}Note:${plain} Option 4 serves the panel over plain HTTP — only safe behind nginx/Caddy or an SSH tunnel."
|
||||
read -rp "Choose an option (default 2 for IP): " ssl_choice
|
||||
ssl_choice="${ssl_choice// /}" # Trim whitespace
|
||||
ssl_choice="${ssl_choice// /}"
|
||||
|
||||
# Default to 2 (IP cert) if input is empty or invalid (not 1, 3 or 4)
|
||||
if [[ "$ssl_choice" != "1" && "$ssl_choice" != "3" && "$ssl_choice" != "4" ]]; 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}"
|
||||
if ssl_cert_issue; then
|
||||
local cert_domain="${SSL_ISSUED_DOMAIN}"
|
||||
|
|
@ -572,15 +545,12 @@ prompt_and_setup_ssl() {
|
|||
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
|
||||
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
|
||||
ipv6_addr="${ipv6_addr// /}"
|
||||
|
||||
# Stop panel if running (port 80 needed)
|
||||
if [[ $release == "alpine" ]]; then
|
||||
rc-service x-ui stop > /dev/null 2>&1
|
||||
else
|
||||
|
|
@ -597,20 +567,16 @@ prompt_and_setup_ssl() {
|
|||
fi
|
||||
;;
|
||||
3)
|
||||
# User chose Custom Paths (User Provided) option
|
||||
echo -e "${green}Using custom existing certificate...${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// /}" # Remove spaces
|
||||
custom_domain="${custom_domain// /}"
|
||||
|
||||
# 3.2 Loop for Certificate Path
|
||||
while true; do
|
||||
read -rp "Input certificate path (keywords: .crt / fullchain): " custom_cert
|
||||
# Strip quotes if present
|
||||
custom_cert=$(echo "$custom_cert" | tr -d '"' | tr -d "'")
|
||||
|
||||
if [[ -f "$custom_cert" && -r "$custom_cert" && -s "$custom_cert" ]]; then
|
||||
|
|
@ -624,10 +590,8 @@ prompt_and_setup_ssl() {
|
|||
fi
|
||||
done
|
||||
|
||||
# 3.3 Loop for Private Key Path
|
||||
while true; do
|
||||
read -rp "Input private key path (keywords: .key / privatekey): " custom_key
|
||||
# Strip quotes if present
|
||||
custom_key=$(echo "$custom_key" | tr -d '"' | tr -d "'")
|
||||
|
||||
if [[ -f "$custom_key" && -r "$custom_key" && -s "$custom_key" ]]; then
|
||||
|
|
@ -641,10 +605,8 @@ prompt_and_setup_ssl() {
|
|||
fi
|
||||
done
|
||||
|
||||
# 3.4 Apply Settings via x-ui binary
|
||||
${xui_folder}/x-ui cert -webCert "$custom_cert" -webCertKey "$custom_key" > /dev/null 2>&1
|
||||
|
||||
# Set SSL_HOST for composing Panel URL
|
||||
if [[ -n "$custom_domain" ]]; then
|
||||
SSL_HOST="$custom_domain"
|
||||
else
|
||||
|
|
@ -702,7 +664,6 @@ 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
|
||||
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"
|
||||
|
|
@ -763,7 +724,6 @@ config_after_install() {
|
|||
|
||||
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}"
|
||||
|
|
@ -786,7 +746,6 @@ config_after_install() {
|
|||
${xui_folder}/x-ui setting -webBasePath "${config_webBasePath}"
|
||||
echo -e "${green}New WebBasePath: ${config_webBasePath}${plain}"
|
||||
|
||||
# If the panel is already installed but no certificate is configured, prompt for SSL now
|
||||
if [[ -z "${existing_cert}" ]]; then
|
||||
echo ""
|
||||
echo -e "${green}═══════════════════════════════════════════${plain}"
|
||||
|
|
@ -797,7 +756,6 @@ config_after_install() {
|
|||
prompt_and_setup_ssl "${existing_port}" "${config_webBasePath}" "${server_ip}"
|
||||
echo -e "${green}Access URL: ${SSL_SCHEME}://${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}"
|
||||
fi
|
||||
fi
|
||||
|
|
@ -817,8 +775,6 @@ config_after_install() {
|
|||
echo -e "${green}Username, Password, and WebBasePath are properly set.${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
|
||||
existing_cert=$(${xui_folder}/x-ui setting -getCert true | grep 'cert:' | awk -F': ' '{print $2}' | tr -d '[:space:]')
|
||||
if [[ -z "$existing_cert" ]]; then
|
||||
echo ""
|
||||
|
|
@ -840,19 +796,20 @@ config_after_install() {
|
|||
install_x-ui() {
|
||||
cd ${xui_folder%/x-ui}/
|
||||
|
||||
# Download resources
|
||||
local github_raw=$(get_github_raw)
|
||||
|
||||
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/mhsanaei/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/')
|
||||
tag_version=$(curl -4 -Ls "https://api.github.com/repos/mhsanaei/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}"
|
||||
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
|
||||
curl -4fLRo ${xui_folder}-linux-$(arch).tar.gz https://github.com/mhsanaei/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}"
|
||||
exit 1
|
||||
|
|
@ -867,7 +824,7 @@ install_x-ui() {
|
|||
exit 1
|
||||
fi
|
||||
|
||||
url="https://github.com/MHSanaei/3x-ui/releases/download/${tag_version}/x-ui-linux-$(arch).tar.gz"
|
||||
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"
|
||||
curl -4fLRo ${xui_folder}-linux-$(arch).tar.gz ${url}
|
||||
if [[ $? -ne 0 ]]; then
|
||||
|
|
@ -875,13 +832,12 @@ install_x-ui() {
|
|||
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 ${github_raw}/mhsanaei/3x-ui/main/x-ui.sh
|
||||
if [[ $? -ne 0 ]]; then
|
||||
echo -e "${red}Failed to download x-ui.sh${plain}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Stop x-ui service and remove old resources
|
||||
if [[ -e ${xui_folder}/ ]]; then
|
||||
if [[ $release == "alpine" ]]; then
|
||||
rc-service x-ui stop
|
||||
|
|
@ -891,7 +847,6 @@ install_x-ui() {
|
|||
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
|
||||
|
||||
|
|
@ -899,20 +854,17 @@ install_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
|
||||
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
|
||||
if [ -d "/etc/.git" ]; then
|
||||
if [ -f "/etc/.gitignore" ]; then
|
||||
if ! grep -q "x-ui/x-ui.db" "/etc/.gitignore"; then
|
||||
|
|
@ -927,7 +879,7 @@ install_x-ui() {
|
|||
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 ${github_raw}/mhsanaei/3x-ui/main/x-ui.rc
|
||||
if [[ $? -ne 0 ]]; then
|
||||
echo -e "${red}Failed to download x-ui.rc${plain}"
|
||||
exit 1
|
||||
|
|
@ -936,7 +888,6 @@ install_x-ui() {
|
|||
rc-update add x-ui
|
||||
rc-service x-ui start
|
||||
else
|
||||
# Install systemd service file
|
||||
service_installed=false
|
||||
|
||||
if [ -f "x-ui.service" ]; then
|
||||
|
|
@ -979,18 +930,17 @@ install_x-ui() {
|
|||
esac
|
||||
fi
|
||||
|
||||
# If service file not found in tar.gz, download from GitHub
|
||||
if [ "$service_installed" = false ]; then
|
||||
echo -e "${yellow}Service files not found in tar.gz, downloading from 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 ${github_raw}/mhsanaei/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 ${github_raw}/mhsanaei/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 ${github_raw}/mhsanaei/3x-ui/main/x-ui.service.rhel > /dev/null 2>&1
|
||||
;;
|
||||
esac
|
||||
|
||||
|
|
|
|||
240
x-ui.sh
240
x-ui.sh
|
|
@ -6,7 +6,9 @@ blue='\033[0;34m'
|
|||
yellow='\033[0;33m'
|
||||
plain='\033[0m'
|
||||
|
||||
#Add some basic function here
|
||||
GITHUB_MIRROR_DEFAULT="https://gh.kejilion.pro"
|
||||
GITHUB_RAW_DEFAULT="https://raw.githubusercontent.com"
|
||||
|
||||
function LOGD() {
|
||||
echo -e "${yellow}[DEG] $* ${plain}"
|
||||
}
|
||||
|
|
@ -19,7 +21,33 @@ function LOGI() {
|
|||
echo -e "${green}[INF] $* ${plain}"
|
||||
}
|
||||
|
||||
# Port helpers: detect listener and owning process (best effort)
|
||||
get_github_mirror() {
|
||||
local custom_mirror="${GITHUB_MIRROR:-}"
|
||||
if [[ -n "$custom_mirror" ]]; then
|
||||
echo "$custom_mirror"
|
||||
else
|
||||
echo "$GITHUB_MIRROR_DEFAULT"
|
||||
fi
|
||||
}
|
||||
|
||||
get_github_raw() {
|
||||
local mirror=$(get_github_mirror)
|
||||
if [[ "$mirror" == "$GITHUB_MIRROR_DEFAULT" ]]; then
|
||||
echo "$GITHUB_RAW_DEFAULT"
|
||||
else
|
||||
echo "$mirror"
|
||||
fi
|
||||
}
|
||||
|
||||
get_github_download_url() {
|
||||
local mirror=$(get_github_mirror)
|
||||
if [[ "$mirror" == "$GITHUB_MIRROR_DEFAULT" ]]; then
|
||||
echo "https://github.com"
|
||||
else
|
||||
echo "$mirror"
|
||||
fi
|
||||
}
|
||||
|
||||
is_port_in_use() {
|
||||
local port="$1"
|
||||
if command -v ss > /dev/null 2>&1; then
|
||||
|
|
@ -36,7 +64,6 @@ is_port_in_use() {
|
|||
return 1
|
||||
}
|
||||
|
||||
# Simple helpers for domain/IP validation
|
||||
is_ipv4() {
|
||||
[[ "$1" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]] && return 0 || return 1
|
||||
}
|
||||
|
|
@ -50,10 +77,8 @@ 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
|
||||
|
||||
# Check OS and set release variable
|
||||
if [[ -f /etc/os-release ]]; then
|
||||
source /etc/os-release
|
||||
release=$ID
|
||||
|
|
@ -69,7 +94,6 @@ echo "The OS release is: $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}"
|
||||
|
|
@ -77,6 +101,9 @@ mkdir -p "${log_folder}"
|
|||
iplimit_log_path="${log_folder}/3xipl.log"
|
||||
iplimit_banned_log_path="${log_folder}/3xipl-banned.log"
|
||||
|
||||
REPO_OWNER="mhsanaei"
|
||||
REPO_NAME="3x-ui"
|
||||
|
||||
confirm() {
|
||||
if [[ $# > 1 ]]; then
|
||||
echo && read -rp "$1 [Default $2]: " temp
|
||||
|
|
@ -108,7 +135,8 @@ before_show_menu() {
|
|||
}
|
||||
|
||||
install() {
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/MHSanaei/3x-ui/main/install.sh)
|
||||
local github_raw=$(get_github_raw)
|
||||
bash <(curl -Ls ${github_raw}/${REPO_OWNER}/${REPO_NAME}/main/install.sh)
|
||||
if [[ $? == 0 ]]; then
|
||||
if [[ $# == 0 ]]; then
|
||||
start
|
||||
|
|
@ -127,7 +155,8 @@ update() {
|
|||
fi
|
||||
return 0
|
||||
fi
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/MHSanaei/3x-ui/main/update.sh)
|
||||
local github_raw=$(get_github_raw)
|
||||
bash <(curl -Ls ${github_raw}/${REPO_OWNER}/${REPO_NAME}/main/update.sh)
|
||||
if [[ $? == 0 ]]; then
|
||||
LOGI "Update is complete, Panel has automatically restarted "
|
||||
before_show_menu
|
||||
|
|
@ -145,7 +174,8 @@ update_menu() {
|
|||
return 0
|
||||
fi
|
||||
|
||||
curl -fLRo /usr/bin/x-ui https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.sh
|
||||
local github_raw=$(get_github_raw)
|
||||
curl -fLRo /usr/bin/x-ui ${github_raw}/${REPO_OWNER}/${REPO_NAME}/main/x-ui.sh
|
||||
chmod +x ${xui_folder}/x-ui.sh
|
||||
chmod +x /usr/bin/x-ui
|
||||
|
||||
|
|
@ -166,16 +196,14 @@ legacy_version() {
|
|||
echo "Panel version cannot be empty. Exiting."
|
||||
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"
|
||||
local install_command="bash <(curl -Ls ${github_raw}/${REPO_OWNER}/${REPO_NAME}/v$tag_version/install.sh) v$tag_version"
|
||||
|
||||
echo "Downloading and installing panel version $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
|
||||
}
|
||||
|
||||
|
|
@ -206,9 +234,9 @@ uninstall() {
|
|||
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}"
|
||||
local github_raw=$(get_github_raw)
|
||||
echo -e "${green}bash <(curl -Ls ${github_raw}/${REPO_OWNER}/${REPO_NAME}/main/install.sh)${plain}"
|
||||
echo ""
|
||||
# Trap the SIGTERM signal
|
||||
trap delete_script SIGTERM
|
||||
delete_script
|
||||
}
|
||||
|
|
@ -259,7 +287,6 @@ reset_webbasepath() {
|
|||
|
||||
config_webBasePath=$(gen_random_string 18)
|
||||
|
||||
# Apply the new web base path setting
|
||||
${xui_folder}/x-ui setting -webBasePath "${config_webBasePath}" > /dev/null 2>&1
|
||||
|
||||
echo -e "Web base path has been reset to: ${green}${config_webBasePath}${plain}"
|
||||
|
|
@ -340,7 +367,6 @@ check_config() {
|
|||
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
|
||||
start 0 > /dev/null 2>&1
|
||||
else
|
||||
LOGE "IP certificate setup failed."
|
||||
|
|
@ -579,7 +605,6 @@ disable_bbr() {
|
|||
rm /etc/sysctl.d/99-bbr-x-ui.conf
|
||||
sysctl --system
|
||||
else
|
||||
# Replace BBR with CUBIC configurations
|
||||
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
|
||||
|
|
@ -600,7 +625,6 @@ enable_bbr() {
|
|||
before_show_menu
|
||||
fi
|
||||
|
||||
# Enable BBR
|
||||
if [ -d "/etc/sysctl.d/" ]; then
|
||||
{
|
||||
echo "#$(sysctl -n net.core.default_qdisc):$(sysctl -n net.ipv4.tcp_congestion_control)"
|
||||
|
|
@ -608,7 +632,6 @@ 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
|
||||
sed -i 's/^net.core.default_qdisc/# &/' /etc/sysctl.conf
|
||||
sed -i 's/^net.ipv4.tcp_congestion_control/# &/' /etc/sysctl.conf
|
||||
fi
|
||||
|
|
@ -621,7 +644,6 @@ enable_bbr() {
|
|||
sysctl -p
|
||||
fi
|
||||
|
||||
# Verify that BBR is enabled
|
||||
if [[ $(sysctl -n net.ipv4.tcp_congestion_control) == "bbr" ]]; then
|
||||
echo -e "${green}BBR has been enabled successfully.${plain}"
|
||||
else
|
||||
|
|
@ -630,7 +652,9 @@ enable_bbr() {
|
|||
}
|
||||
|
||||
update_shell() {
|
||||
curl -fLRo /usr/bin/x-ui -z /usr/bin/x-ui https://github.com/MHSanaei/3x-ui/raw/main/x-ui.sh
|
||||
local github_raw=$(get_github_raw)
|
||||
local github_download=$(get_github_download_url)
|
||||
curl -fLRo /usr/bin/x-ui -z /usr/bin/x-ui ${github_raw}/${REPO_OWNER}/${REPO_NAME}/main/x-ui.sh
|
||||
if [[ $? != 0 ]]; then
|
||||
echo ""
|
||||
LOGE "Failed to download script, Please check whether the machine can connect Github"
|
||||
|
|
@ -642,7 +666,6 @@ update_shell() {
|
|||
fi
|
||||
}
|
||||
|
||||
# 0: running, 1: not running, 2: not installed
|
||||
check_status() {
|
||||
if [[ $release == "alpine" ]]; then
|
||||
if [[ ! -f /etc/init.d/x-ui ]]; then
|
||||
|
|
@ -814,130 +837,103 @@ install_firewall() {
|
|||
echo "ufw firewall is already installed"
|
||||
fi
|
||||
|
||||
# Check if the firewall is inactive
|
||||
if ufw status | grep -q "Status: active"; then
|
||||
echo "Firewall is already active"
|
||||
else
|
||||
echo "Activating firewall..."
|
||||
# Open the necessary ports
|
||||
ufw allow ssh
|
||||
ufw allow http
|
||||
ufw allow https
|
||||
ufw allow 2053/tcp #webPort
|
||||
ufw allow 2096/tcp #subport
|
||||
ufw allow 2053/tcp
|
||||
ufw allow 2096/tcp
|
||||
|
||||
# Enable the firewall
|
||||
ufw --force enable
|
||||
fi
|
||||
}
|
||||
|
||||
open_ports() {
|
||||
# Prompt the user to enter the ports they want to open
|
||||
read -rp "Enter the ports you want to open (e.g. 80,443,2053 or range 400-500): " ports
|
||||
|
||||
# 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
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Open the specified ports using ufw
|
||||
IFS=',' read -ra PORT_LIST <<< "$ports"
|
||||
for port in "${PORT_LIST[@]}"; do
|
||||
if [[ $port == *-* ]]; then
|
||||
# Split the range into start and end ports
|
||||
start_port=$(echo $port | cut -d'-' -f1)
|
||||
end_port=$(echo $port | cut -d'-' -f2)
|
||||
# Open the port range
|
||||
ufw allow $start_port:$end_port/tcp
|
||||
ufw allow $start_port:$end_port/udp
|
||||
else
|
||||
# Open the single port
|
||||
ufw allow "$port"
|
||||
fi
|
||||
done
|
||||
|
||||
# Confirm that the ports are opened
|
||||
echo "Opened the specified ports:"
|
||||
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:"
|
||||
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
|
||||
|
||||
if [[ $choice -eq 1 ]]; then
|
||||
# Deleting by rule numbers
|
||||
read -rp "Enter the rule numbers you want to delete (1, 2, etc.): " 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
|
||||
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"
|
||||
done
|
||||
|
||||
echo "Selected rules have been deleted."
|
||||
|
||||
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
|
||||
|
||||
# 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
|
||||
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:"
|
||||
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
|
||||
|
|
@ -969,7 +965,6 @@ update_geofiles() {
|
|||
;;
|
||||
esac
|
||||
for dat in "${dat_files[@]}"; do
|
||||
# Remove suffix for remote filename (e.g., 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
|
||||
|
|
@ -1018,14 +1013,13 @@ update_geo() {
|
|||
}
|
||||
|
||||
install_acme() {
|
||||
# Check if acme.sh is already installed
|
||||
if command -v ~/.acme.sh/acme.sh &> /dev/null; then
|
||||
LOGI "acme.sh is already installed."
|
||||
return 0
|
||||
fi
|
||||
|
||||
LOGI "Installing acme.sh..."
|
||||
cd ~ || return 1 # Ensure you can change to the home directory
|
||||
cd ~ || return 1
|
||||
|
||||
curl -s https://get.acme.sh | sh
|
||||
if [ $? -ne 0 ]; then
|
||||
|
|
@ -1164,7 +1158,6 @@ ssl_cert_issue_for_ip() {
|
|||
local existing_webBasePath=$(${xui_folder}/x-ui setting -show true | grep -Eo 'webBasePath: .+' | awk '{print $2}')
|
||||
local existing_port=$(${xui_folder}/x-ui setting -show true | grep -Eo 'port: .+' | awk '{print $2}')
|
||||
|
||||
# Get server IP
|
||||
local URL_lists=(
|
||||
"https://api4.ipify.org"
|
||||
"https://ipv4.icanhazip.com"
|
||||
|
|
@ -1198,12 +1191,10 @@ ssl_cert_issue_for_ip() {
|
|||
|
||||
LOGI "Server IP detected: ${server_ip}"
|
||||
|
||||
# Ask for optional IPv6
|
||||
local ipv6_addr=""
|
||||
read -rp "Do you have an IPv6 address to include? (leave empty to skip): " ipv6_addr
|
||||
ipv6_addr="${ipv6_addr// /}" # Trim whitespace
|
||||
ipv6_addr="${ipv6_addr// /}"
|
||||
|
||||
# check for acme.sh first
|
||||
if ! command -v ~/.acme.sh/acme.sh &> /dev/null; then
|
||||
LOGI "acme.sh not found, installing..."
|
||||
install_acme
|
||||
|
|
@ -1213,7 +1204,6 @@ ssl_cert_issue_for_ip() {
|
|||
fi
|
||||
fi
|
||||
|
||||
# install socat
|
||||
case "${release}" in
|
||||
ubuntu | debian | armbian)
|
||||
apt-get update > /dev/null 2>&1 && apt-get install socat -y > /dev/null 2>&1
|
||||
|
|
@ -1238,22 +1228,18 @@ ssl_cert_issue_for_ip() {
|
|||
apk add socat curl openssl > /dev/null 2>&1
|
||||
;;
|
||||
*)
|
||||
LOGW "Unsupported OS for automatic socat installation"
|
||||
;;
|
||||
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}"
|
||||
fi
|
||||
|
||||
# Choose port for HTTP-01 listener (default 80, allow override)
|
||||
local WebPort=""
|
||||
read -rp "Port to use for ACME HTTP-01 listener (default 80): " WebPort
|
||||
WebPort="${WebPort:-80}"
|
||||
|
|
@ -1289,10 +1275,8 @@ ssl_cert_issue_for_ip() {
|
|||
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
|
||||
~/.acme.sh/acme.sh --set-default-ca --server letsencrypt --force
|
||||
~/.acme.sh/acme.sh --issue \
|
||||
${domain_args} \
|
||||
|
|
@ -1306,7 +1290,6 @@ ssl_cert_issue_for_ip() {
|
|||
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
|
||||
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
|
||||
|
|
@ -1315,18 +1298,13 @@ ssl_cert_issue_for_ip() {
|
|||
LOGI "Certificate issued successfully for IP: ${server_ip}"
|
||||
fi
|
||||
|
||||
# Install the certificate
|
||||
# Note: acme.sh may report "Reload error" and exit non-zero if reloadcmd fails,
|
||||
# but the cert files are still installed. We check for files instead of exit code.
|
||||
~/.acme.sh/acme.sh --installcert -d ${server_ip} \
|
||||
--key-file "${certPath}/privkey.pem" \
|
||||
--fullchain-file "${certPath}/fullchain.pem" \
|
||||
--reloadcmd "${reloadCmd}" 2>&1 || true
|
||||
|
||||
# Verify certificate files exist (don't rely on exit code - reloadcmd failure causes non-zero)
|
||||
if [[ ! -f "${certPath}/fullchain.pem" || ! -f "${certPath}/privkey.pem" ]]; then
|
||||
LOGE "Certificate files not found after installation"
|
||||
# Cleanup acme.sh data for both IPv4 and IPv6 if specified
|
||||
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
|
||||
|
|
@ -1335,12 +1313,10 @@ ssl_cert_issue_for_ip() {
|
|||
|
||||
LOGI "Certificate files installed successfully"
|
||||
|
||||
# enable auto-renew
|
||||
~/.acme.sh/acme.sh --upgrade --auto-upgrade > /dev/null 2>&1
|
||||
chmod 600 $certPath/privkey.pem 2> /dev/null
|
||||
chmod 644 $certPath/fullchain.pem 2> /dev/null
|
||||
|
||||
# Set certificate paths for the panel
|
||||
local webCertFile="${certPath}/fullchain.pem"
|
||||
local webKeyFile="${certPath}/privkey.pem"
|
||||
|
||||
|
|
@ -1363,7 +1339,6 @@ ssl_cert_issue_for_ip() {
|
|||
ssl_cert_issue() {
|
||||
local existing_webBasePath=$(${xui_folder}/x-ui setting -show true | grep -Eo 'webBasePath: .+' | awk '{print $2}')
|
||||
local existing_port=$(${xui_folder}/x-ui setting -show true | grep -Eo 'port: .+' | awk '{print $2}')
|
||||
# check for acme.sh first
|
||||
if ! command -v ~/.acme.sh/acme.sh &> /dev/null; then
|
||||
echo "acme.sh could not be found. we will install it"
|
||||
install_acme
|
||||
|
|
@ -1373,7 +1348,6 @@ ssl_cert_issue() {
|
|||
fi
|
||||
fi
|
||||
|
||||
# install socat
|
||||
case "${release}" in
|
||||
ubuntu | debian | armbian)
|
||||
apt-get update > /dev/null 2>&1 && apt-get install socat -y > /dev/null 2>&1
|
||||
|
|
@ -1398,7 +1372,6 @@ ssl_cert_issue() {
|
|||
apk add socat curl openssl > /dev/null 2>&1
|
||||
;;
|
||||
*)
|
||||
LOGW "Unsupported OS for automatic socat installation"
|
||||
;;
|
||||
esac
|
||||
if [ $? -ne 0 ]; then
|
||||
|
|
@ -1408,11 +1381,10 @@ ssl_cert_issue() {
|
|||
LOGI "install socat succeed..."
|
||||
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
|
||||
domain="${domain// /}"
|
||||
|
||||
if [[ -z "$domain" ]]; then
|
||||
LOGE "Domain name cannot be empty. Please try again."
|
||||
|
|
@ -1429,7 +1401,6 @@ ssl_cert_issue() {
|
|||
LOGD "Your domain is: ${domain}, checking it..."
|
||||
SSL_ISSUED_DOMAIN="${domain}"
|
||||
|
||||
# detect existing certificate and reuse it if present
|
||||
local cert_exists=0
|
||||
if ~/.acme.sh/acme.sh --list 2> /dev/null | awk '{print $1}' | grep -Fxq "${domain}"; then
|
||||
cert_exists=1
|
||||
|
|
@ -1440,7 +1411,6 @@ ssl_cert_issue() {
|
|||
LOGI "Your domain is ready for issuing certificates now..."
|
||||
fi
|
||||
|
||||
# create a directory for the certificate
|
||||
certPath="/root/cert/${domain}"
|
||||
if [ ! -d "$certPath" ]; then
|
||||
mkdir -p "$certPath"
|
||||
|
|
@ -1449,7 +1419,6 @@ 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
|
||||
if [[ ${WebPort} -gt 65535 || ${WebPort} -lt 1 ]]; then
|
||||
|
|
@ -1459,7 +1428,6 @@ ssl_cert_issue() {
|
|||
LOGI "Will use port: ${WebPort} to issue certificates. Please make sure this port is open."
|
||||
|
||||
if [[ ${cert_exists} -eq 0 ]]; then
|
||||
# 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
|
||||
|
|
@ -1499,7 +1467,6 @@ ssl_cert_issue() {
|
|||
esac
|
||||
fi
|
||||
|
||||
# install the certificate
|
||||
local installOutput=""
|
||||
installOutput=$(~/.acme.sh/acme.sh --installcert -d ${domain} \
|
||||
--key-file /root/cert/${domain}/privkey.pem \
|
||||
|
|
@ -1522,7 +1489,6 @@ ssl_cert_issue() {
|
|||
exit 1
|
||||
fi
|
||||
|
||||
# enable auto-renew
|
||||
~/.acme.sh/acme.sh --upgrade --auto-upgrade
|
||||
if [ $? -ne 0 ]; then
|
||||
LOGE "Auto renew failed, certificate details:"
|
||||
|
|
@ -1537,7 +1503,6 @@ ssl_cert_issue() {
|
|||
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
|
||||
if [[ "$setPanel" == "y" || "$setPanel" == "Y" ]]; then
|
||||
local webCertFile="/root/cert/${domain}/fullchain.pem"
|
||||
|
|
@ -1572,7 +1537,6 @@ ssl_cert_issue_CF() {
|
|||
confirm "Do you confirm the information and wish to proceed? [y/n]" "y"
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
# Check for acme.sh first
|
||||
if ! command -v ~/.acme.sh/acme.sh &> /dev/null; then
|
||||
echo "acme.sh could not be found. We will install it."
|
||||
install_acme
|
||||
|
|
@ -1588,7 +1552,6 @@ ssl_cert_issue_CF() {
|
|||
read -rp "Input your domain here: " CF_Domain
|
||||
LOGD "Your domain name is set to: ${CF_Domain}"
|
||||
|
||||
# Set up Cloudflare API details
|
||||
CF_GlobalKey=""
|
||||
CF_AccountEmail=""
|
||||
LOGD "Please set the API key:"
|
||||
|
|
@ -1599,7 +1562,6 @@ ssl_cert_issue_CF() {
|
|||
read -rp "Input your email here: " CF_AccountEmail
|
||||
LOGD "Your registered email address is: ${CF_AccountEmail}"
|
||||
|
||||
# Set the default CA to 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..."
|
||||
|
|
@ -1609,7 +1571,6 @@ ssl_cert_issue_CF() {
|
|||
export CF_Key="${CF_GlobalKey}"
|
||||
export CF_Email="${CF_AccountEmail}"
|
||||
|
||||
# Issue the certificate using Cloudflare DNS
|
||||
~/.acme.sh/acme.sh --issue --dns dns_cf -d ${CF_Domain} -d *.${CF_Domain} --log --force
|
||||
if [ $? -ne 0 ]; then
|
||||
LOGE "Certificate issuance failed, script exiting..."
|
||||
|
|
@ -1618,7 +1579,6 @@ ssl_cert_issue_CF() {
|
|||
LOGI "Certificate issued successfully, Installing..."
|
||||
fi
|
||||
|
||||
# Install the certificate
|
||||
certPath="/root/cert/${CF_Domain}"
|
||||
if [ -d "$certPath" ]; then
|
||||
rm -rf ${certPath}
|
||||
|
|
@ -1666,7 +1626,6 @@ ssl_cert_issue_CF() {
|
|||
LOGI "Certificate installed successfully, Turning on automatic updates..."
|
||||
fi
|
||||
|
||||
# Enable auto-update
|
||||
~/.acme.sh/acme.sh --upgrade --auto-upgrade
|
||||
if [ $? -ne 0 ]; then
|
||||
LOGE "Auto update setup failed, script exiting..."
|
||||
|
|
@ -1678,7 +1637,6 @@ ssl_cert_issue_CF() {
|
|||
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
|
||||
if [[ "$setPanel" == "y" || "$setPanel" == "Y" ]]; then
|
||||
local webCertFile="${certPath}/fullchain.pem"
|
||||
|
|
@ -1703,15 +1661,11 @@ ssl_cert_issue_CF() {
|
|||
}
|
||||
|
||||
run_speedtest() {
|
||||
# Check if Speedtest is already installed
|
||||
if ! command -v speedtest &> /dev/null; then
|
||||
# If not installed, determine installation method
|
||||
if command -v snap &> /dev/null; then
|
||||
# Use snap to install Speedtest
|
||||
echo "Installing Speedtest using snap..."
|
||||
snap install speedtest
|
||||
else
|
||||
# Fallback to using package managers
|
||||
local pkg_manager=""
|
||||
local speedtest_install_script=""
|
||||
|
||||
|
|
@ -1745,7 +1699,7 @@ run_speedtest() {
|
|||
|
||||
ip_validation() {
|
||||
ipv6_regex="^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$"
|
||||
ipv4_regex="^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]?|0)\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]?|0)$"
|
||||
ipv4_regex="^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|0)\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|0)$"
|
||||
}
|
||||
|
||||
iplimit_main() {
|
||||
|
|
@ -1856,14 +1810,6 @@ install_iplimit() {
|
|||
if ! command -v fail2ban-client &> /dev/null; then
|
||||
echo -e "${green}Fail2ban is not installed. Installing now...!${plain}\n"
|
||||
|
||||
# Install fail2ban together with nftables. Recent fail2ban packages
|
||||
# default to `banaction = nftables-multiport` in /etc/fail2ban/jail.conf,
|
||||
# but the `nftables` package isn't pulled in as a dependency on most
|
||||
# minimal server images (Debian 12+, Ubuntu 24+, fresh RHEL-family).
|
||||
# Without `nft` in PATH the default sshd jail fails to ban with
|
||||
# stderr: '/bin/sh: 1: nft: not found'
|
||||
# even though our own 3x-ipl jail uses iptables. Bundling the binary
|
||||
# at install time prevents that confusing log spam for new installs.
|
||||
case "${release}" in
|
||||
ubuntu)
|
||||
apt-get update
|
||||
|
|
@ -1918,24 +1864,18 @@ install_iplimit() {
|
|||
|
||||
echo -e "${green}Configuring IP Limit...${plain}\n"
|
||||
|
||||
# make sure there's no conflict for jail files
|
||||
iplimit_remove_conflicts
|
||||
|
||||
# Check if log file exists
|
||||
if ! test -f "${iplimit_banned_log_path}"; then
|
||||
touch ${iplimit_banned_log_path}
|
||||
fi
|
||||
|
||||
# Check if service log file exists so fail2ban won't return error
|
||||
if ! test -f "${iplimit_log_path}"; then
|
||||
touch ${iplimit_log_path}
|
||||
fi
|
||||
|
||||
# Create the iplimit jail files
|
||||
# we didn't pass the bantime here to use the default value
|
||||
create_iplimit_jails
|
||||
|
||||
# Launching fail2ban
|
||||
if [[ $release == "alpine" ]]; then
|
||||
if [[ $(rc-service fail2ban status | grep -F 'status: started' -c) == 0 ]]; then
|
||||
rc-service fail2ban start
|
||||
|
|
@ -2063,13 +2003,10 @@ show_banlog() {
|
|||
}
|
||||
|
||||
create_iplimit_jails() {
|
||||
# Use default bantime if not passed => 30 minutes
|
||||
local bantime="${1:-30}"
|
||||
|
||||
# Uncomment 'allowipv6 = auto' in fail2ban.conf
|
||||
sed -i 's/#allowipv6 = auto/allowipv6 = auto/g' /etc/fail2ban/fail2ban.conf
|
||||
|
||||
# On Debian 12+ fail2ban's default backend should be changed to systemd
|
||||
if [[ "${release}" == "debian" && ${os_version} -ge 12 ]]; then
|
||||
sed -i '0,/action =/s/backend = auto/backend = systemd/' /etc/fail2ban/jail.conf
|
||||
fi
|
||||
|
|
@ -2130,7 +2067,6 @@ iplimit_remove_conflicts() {
|
|||
)
|
||||
|
||||
for file in "${jail_files[@]}"; do
|
||||
# Check for [3x-ipl] config in jail file then remove it
|
||||
if test -f "${file}" && grep -qw '3x-ipl' ${file}; then
|
||||
sed -i "/\[3x-ipl\]/,/^$/d" ${file}
|
||||
echo -e "${yellow}Removing conflicts of [3x-ipl] in jail (${file})!${plain}\n"
|
||||
|
|
@ -2270,42 +2206,42 @@ show_usage() {
|
|||
|
||||
show_menu() {
|
||||
echo -e "
|
||||
╔────────────────────────────────────────────────╗
|
||||
│ ${green}3X-UI Panel Management Script${plain} │
|
||||
│ ${green}0.${plain} Exit Script │
|
||||
│────────────────────────────────────────────────│
|
||||
│ ${green}1.${plain} Install │
|
||||
│ ${green}2.${plain} Update │
|
||||
│ ${green}3.${plain} Update Menu │
|
||||
│ ${green}4.${plain} Legacy Version │
|
||||
│ ${green}5.${plain} Uninstall │
|
||||
│────────────────────────────────────────────────│
|
||||
│ ${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}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}17.${plain} Enable Autostart │
|
||||
│ ${green}18.${plain} Disable Autostart │
|
||||
│────────────────────────────────────────────────│
|
||||
│ ${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}24.${plain} Enable BBR │
|
||||
│ ${green}25.${plain} Update Geo Files │
|
||||
│ ${green}26.${plain} Speedtest by Ookla │
|
||||
╚────────────────────────────────────────────────╝
|
||||
╔════════════════════════════════════════════════════╗
|
||||
║ ${green}3X-UI Panel Management Script${plain} ║
|
||||
║ ${green}0.${plain} Exit Script ║
|
||||
║──────────────────────────────────────────────────║
|
||||
║ ${green}1.${plain} Install ║
|
||||
║ ${green}2.${plain} Update ║
|
||||
║ ${green}3.${plain} Update Menu ║
|
||||
║ ${green}4.${plain} Legacy Version ║
|
||||
║ ${green}5.${plain} Uninstall ║
|
||||
║──────────────────────────────────────────────────║
|
||||
║ ${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}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}17.${plain} Enable Autostart ║
|
||||
║ ${green}18.${plain} Disable Autostart ║
|
||||
║──────────────────────────────────────────────────║
|
||||
║ ${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}24.${plain} Enable BBR ║
|
||||
║ ${green}25.${plain} Update Geo Files ║
|
||||
║ ${green}26.${plain} Speedtest by Ookla ║
|
||||
╚════════════════════════════════════════════════════╝
|
||||
"
|
||||
show_status
|
||||
echo && read -rp "Please enter your selection [0-26]: " num
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue