From 1ab0e7d80b6316d7a5620daa06ad022030eb3215 Mon Sep 17 00:00:00 2001
From: itboyhan1 <154587375+itboyhan1@users.noreply.github.com>
Date: Wed, 28 May 2025 19:44:03 +0800
Subject: [PATCH 01/18] Update model.go
---
database/model/model.go | 2 ++
1 file changed, 2 insertions(+)
diff --git a/database/model/model.go b/database/model/model.go
index 2e7095d3..452285c8 100644
--- a/database/model/model.go
+++ b/database/model/model.go
@@ -104,4 +104,6 @@ type Client struct {
SubID string `json:"subId" form:"subId"`
Comment string `json:"comment" form:"comment"`
Reset int `json:"reset" form:"reset"`
+ MaxDevices int `json:"maxDevices" form:"maxDevices" gorm:"default:0"` // 新增:最大设备数量限制, 0表示不限制
+ ActiveIPs string `json:"activeIPs" form:"activeIPs" gorm:"type:text"` // 新增:当前活动的IP列表 (JSON字符串)
}
From 2dee6f66f797f40f1d9c94ea20104a2193a3c407 Mon Sep 17 00:00:00 2001
From: itboyhan1 <154587375+itboyhan1@users.noreply.github.com>
Date: Wed, 28 May 2025 19:46:14 +0800
Subject: [PATCH 02/18] Update client.html
---
web/html/form/client.html | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/web/html/form/client.html b/web/html/form/client.html
index c67f1470..6a971a23 100644
--- a/web/html/form/client.html
+++ b/web/html/form/client.html
@@ -83,6 +83,18 @@
+
+
+
+
+ {{ i18n "pages.inbounds.maxDevicesDesc" }}
+
+ {{ i18n "pages.inbounds.maxDevices" }}
+
+
+
+
+
@@ -169,4 +181,4 @@
-{{end}}
\ No newline at end of file
+{{end}}
From d14ab19b816788390c42d30e1211c9c6eb81037d Mon Sep 17 00:00:00 2001
From: itboyhan1 <154587375+itboyhan1@users.noreply.github.com>
Date: Wed, 28 May 2025 19:48:00 +0800
Subject: [PATCH 03/18] Update check_client_ip_job.go
---
web/job/check_client_ip_job.go | 125 +++++++++++++++++++++++++++++----
1 file changed, 112 insertions(+), 13 deletions(-)
diff --git a/web/job/check_client_ip_job.go b/web/job/check_client_ip_job.go
index b95c8ee2..f07421f4 100644
--- a/web/job/check_client_ip_job.go
+++ b/web/job/check_client_ip_job.go
@@ -36,7 +36,7 @@ func (j *CheckClientIpJob) Run() {
}
shouldClearAccessLog := false
- iplimitActive := j.hasLimitIp()
+ iplimitActive := j.hasLimitOrDeviceLimit() // 修改:检查LimitIP或MaxDevices
f2bInstalled := j.checkFail2BanInstalled()
isAccessLogAvailable := j.checkAccessLogAvailable(iplimitActive)
@@ -45,7 +45,7 @@ func (j *CheckClientIpJob) Run() {
shouldClearAccessLog = j.processLogFile()
} else {
if !f2bInstalled {
- logger.Warning("[LimitIP] Fail2Ban is not installed, Please install Fail2Ban from the x-ui bash menu.")
+ logger.Warning("[LimitIP/MaxDevices] Fail2Ban is not installed, Please install Fail2Ban from the x-ui bash menu.")
}
}
}
@@ -76,7 +76,7 @@ func (j *CheckClientIpJob) clearAccessLog() {
j.lastClear = time.Now().Unix()
}
-func (j *CheckClientIpJob) hasLimitIp() bool {
+func (j *CheckClientIpJob) hasLimitOrDeviceLimit() bool { // 修改函数名和逻辑
db := database.GetDB()
var inbounds []*model.Inbound
@@ -96,7 +96,8 @@ func (j *CheckClientIpJob) hasLimitIp() bool {
for _, client := range clients {
limitIp := client.LimitIP
- if limitIp > 0 {
+ maxDevices := client.MaxDevices // 新增:获取MaxDevices
+ if limitIp > 0 || maxDevices > 0 { // 修改:检查LimitIP或MaxDevices
return true
}
}
@@ -144,21 +145,119 @@ func (j *CheckClientIpJob) processLogFile() bool {
}
shouldCleanLog := false
+ db := database.GetDB()
+
for email, uniqueIps := range inboundClientIps {
+ var clientData model.Client
+ // Find the client by email. This requires iterating through inbounds and their clients.
+ // This is a simplified representation. In a real scenario, you'd need a more efficient way to get client by email.
+ foundClient := false
+ var allInbounds []*model.Inbound
+ db.Find(&allInbounds)
+ for _, inbound := range allInbounds {
+ if inbound.Settings == "" {
+ continue
+ }
+ settings := map[string][]model.Client{}
+ json.Unmarshal([]byte(inbound.Settings), &settings)
+ clients := settings["clients"]
+ for _, c := range clients {
+ // Match client by email, or ID, or password based on what's available and matches 'email' (which is clientIdentifier in this context)
+ clientIdentifierInLog := email // email from log is the clientIdentifier
+ matched := false
+ if c.Email != "" && c.Email == clientIdentifierInLog {
+ matched = true
+ } else if c.ID != "" && c.ID == clientIdentifierInLog { // For vmess/vless if email is used as ID in logs
+ matched = true
+ } else if c.Password != "" && c.Password == clientIdentifierInLog { // For trojan if email is used as password in logs
+ matched = true
+ }
- ips := make([]string, 0, len(uniqueIps))
- for ip := range uniqueIps {
- ips = append(ips, ip)
+ if matched {
+ clientData = c
+ clientInboundID = inbound.Id // Store the inbound ID
+ foundClient = true
+ break
+ }
+ }
+ if foundClient {
+ break
+ }
}
- sort.Strings(ips)
- clientIpsRecord, err := j.getInboundClientIps(email)
- if err != nil {
- j.addInboundClientIps(email, ips)
+ if !foundClient {
+ logger.Warningf("Client with identifier %s not found for IP processing", email)
continue
}
- shouldCleanLog = j.updateInboundClientIps(clientIpsRecord, email, ips) || shouldCleanLog
+ currentLoggedIps := make([]string, 0, len(uniqueIps))
+ for ip := range uniqueIps {
+ currentLoggedIps = append(currentLoggedIps, ip)
+ }
+ sort.Strings(currentLoggedIps)
+
+ clientIpsRecord, err := j.getInboundClientIps(email) // This function likely needs to be adapted or clientData used directly
+
+ activeIPs := []string{}
+ if clientData.ActiveIPs != "" {
+ errUnmarshal := json.Unmarshal([]byte(clientData.ActiveIPs), &activeIPs)
+ if errUnmarshal != nil {
+ logger.Warningf("Error unmarshalling ActiveIPs for client %s: %v", email, errUnmarshal)
+ activeIPs = []string{} // Reset if unmarshalling fails
+ }
+ }
+
+ newActiveIPs := make([]string, len(activeIPs))
+ copy(newActiveIPs, activeIPs)
+ changedActiveIPs := false
+
+ for _, loggedIp := range currentLoggedIps {
+ isExistingActiveIP := j.contains(newActiveIPs, loggedIp)
+
+ if clientData.MaxDevices > 0 {
+ if !isExistingActiveIP {
+ if len(newActiveIPs) < clientData.MaxDevices {
+ newActiveIPs = append(newActiveIPs, loggedIp)
+ changedActiveIPs = true
+ } else {
+ if !j.contains(j.disAllowedIps, loggedIp) {
+ j.disAllowedIps = append(j.disAllowedIps, loggedIp)
+ logger.Infof("[MaxDevices] IP %s for client %s banned due to exceeding max device limit (%d)", loggedIp, email, clientData.MaxDevices)
+ shouldCleanLog = true
+ }
+ }
+ }
+ } // End MaxDevices check
+ } // End loop currentLoggedIps
+
+ if changedActiveIPs {
+ activeIPsBytes, marshalErr := json.Marshal(newActiveIPs)
+ if marshalErr != nil {
+ logger.Warningf("Error marshalling new ActiveIPs for client %s: %v", email, marshalErr)
+ } else {
+ // Update clientData.ActiveIPs in the database
+ // This part is complex because clientData is part of a JSON string in Inbound.Settings
+ // A proper solution would involve updating the specific client within the Inbound's settings JSON
+ // and then saving the Inbound object.
+ // For simplicity, we'll log it. A full implementation needs to update the DB.
+ logger.Infof("Client %s ActiveIPs updated to: %s", email, string(activeIPsBytes))
+ // Placeholder for actual DB update logic for clientData.ActiveIPs
+ // Example: err := s.updateClientActiveIPsInDB(inbound.Id, clientData.ID_or_Email, string(activeIPsBytes)); if err != nil { ... }
+ inboundService := service.InboundService{} // Create an instance of InboundService
+ dbUpdateErr := inboundService.UpdateClientActiveIPsInDB(clientInboundID, email, string(activeIPsBytes))
+ if dbUpdateErr != nil {
+ logger.Warningf("Failed to update ActiveIPs in DB for client %s: %v", email, dbUpdateErr)
+ }
+ }
+ }
+
+ if err != nil { // This 'err' is from j.getInboundClientIps(email)
+ j.addInboundClientIps(email, currentLoggedIps) // This function likely needs to be adapted
+ continue
+ }
+
+ // Original LimitIP logic (needs to be integrated with new ActiveIPs logic if LimitIP is also active)
+ shouldCleanLog = j.updateInboundClientIps(clientIpsRecord, email, currentLoggedIps) || shouldCleanLog
}
return shouldCleanLog
@@ -179,7 +278,7 @@ func (j *CheckClientIpJob) checkAccessLogAvailable(iplimitActive bool) bool {
if accessLogPath == "none" || accessLogPath == "" {
if iplimitActive {
- logger.Warning("[LimitIP] Access log path is not set, Please configure the access log path in Xray configs.")
+ logger.Warning("[LimitIP/MaxDevices] Access log path is not set, Please configure the access log path in Xray configs.") // Updated log message
}
return false
}
From b0e278401cbef6bdf3cc71a857058f71816acc18 Mon Sep 17 00:00:00 2001
From: itboyhan1 <154587375+itboyhan1@users.noreply.github.com>
Date: Wed, 28 May 2025 19:49:08 +0800
Subject: [PATCH 04/18] Update inbound.go
---
web/service/inbound.go | 84 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 84 insertions(+)
diff --git a/web/service/inbound.go b/web/service/inbound.go
index f2646dbb..083b2fe6 100644
--- a/web/service/inbound.go
+++ b/web/service/inbound.go
@@ -21,6 +21,90 @@ type InboundService struct {
xrayApi xray.XrayAPI
}
+func (s *InboundService) UpdateClientActiveIPsInDB(inboundID int, clientIdentifier string, newActiveIPsJSON string) error {
+ db := database.GetDB()
+ var inbound model.Inbound
+ err := db.First(&inbound, inboundID).Error
+ if err != nil {
+ return fmt.Errorf("inbound with ID %d not found: %w", inboundID, err)
+ }
+
+ if inbound.Settings == "" {
+ return fmt.Errorf("inbound settings for ID %d are empty", inboundID)
+ }
+
+ settingsMap := make(map[string]interface{})
+ err = json.Unmarshal([]byte(inbound.Settings), &settingsMap)
+ if err != nil {
+ return fmt.Errorf("error unmarshalling settings for inbound ID %d: %w", inboundID, err)
+ }
+
+ clientsRaw, ok := settingsMap["clients"]
+ if !ok {
+ return fmt.Errorf("no 'clients' field in settings for inbound ID %d", inboundID)
+ }
+
+ clients, ok := clientsRaw.([]interface{})
+ if !ok {
+ return fmt.Errorf("'clients' field is not an array in settings for inbound ID %d", inboundID)
+ }
+
+ clientFound := false
+ for i, clientInterface := range clients {
+ clientMap, ok := clientInterface.(map[string]interface{})
+ if !ok {
+ logger.Warningf("Client entry is not a map for inbound ID %d, index %d", inboundID, i)
+ continue
+ }
+
+ // Try to match by email first
+ clientEmail, emailOk := clientMap["email"].(string)
+ if emailOk && clientEmail == clientIdentifier {
+ clientMap["activeIPs"] = newActiveIPsJSON
+ clients[i] = clientMap
+ clientFound = true
+ break
+ }
+
+ // If not matched by email, try to match by ID (for vmess/vless etc.)
+ clientID, idOk := clientMap["id"].(string)
+ if idOk && clientID == clientIdentifier {
+ clientMap["activeIPs"] = newActiveIPsJSON
+ clients[i] = clientMap
+ clientFound = true
+ break
+ }
+
+ // If not matched by email or ID, try to match by Password (for trojan etc.)
+ clientPassword, passwordOk := clientMap["password"].(string)
+ if passwordOk && clientPassword == clientIdentifier {
+ clientMap["activeIPs"] = newActiveIPsJSON
+ clients[i] = clientMap
+ clientFound = true
+ break
+ }
+ }
+
+ if !clientFound {
+ return fmt.Errorf("client with identifier '%s' not found in inbound ID %d", clientIdentifier, inboundID)
+ }
+
+ settingsMap["clients"] = clients
+ updatedSettingsBytes, err := json.Marshal(settingsMap)
+ if err != nil {
+ return fmt.Errorf("error marshalling updated settings for inbound ID %d: %w", inboundID, err)
+ }
+
+ inbound.Settings = string(updatedSettingsBytes)
+ err = db.Save(&inbound).Error
+ if err != nil {
+ return fmt.Errorf("error saving updated inbound settings for ID %d: %w", inboundID, err)
+ }
+
+ logger.Infof("Successfully updated ActiveIPs for client '%s' in inbound ID %d", clientIdentifier, inboundID)
+ return nil
+}
+
func (s *InboundService) GetInbounds(userId int) ([]*model.Inbound, error) {
db := database.GetDB()
var inbounds []*model.Inbound
From 1bf8d8863d03f17ea6fa7f9e820221c555887710 Mon Sep 17 00:00:00 2001
From: itboyhan1 <154587375+itboyhan1@users.noreply.github.com>
Date: Wed, 28 May 2025 19:50:17 +0800
Subject: [PATCH 05/18] Update translate.en_US.toml
---
web/translation/translate.en_US.toml | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/web/translation/translate.en_US.toml b/web/translation/translate.en_US.toml
index da9bedf1..fac8ef76 100644
--- a/web/translation/translate.en_US.toml
+++ b/web/translation/translate.en_US.toml
@@ -220,7 +220,9 @@
"inboundData" = "Inbound's Data"
"exportInbound" = "Export Inbound"
"import" = "Import"
-"importInbound" = "Import an Inbound"
+"importInbound = "Import Inbound"
+maxDevices = "Max Devices"
+maxDevicesDesc = "Maximum number of simultaneously connected devices (0 = unlimited)"
[pages.client]
"add" = "Add Client"
From e5fcc4a926d9a8666f5a2c5fe499ba3da43512d3 Mon Sep 17 00:00:00 2001
From: itboyhan1 <154587375+itboyhan1@users.noreply.github.com>
Date: Wed, 28 May 2025 19:50:48 +0800
Subject: [PATCH 06/18] Update translate.zh_CN.toml
---
web/translation/translate.zh_CN.toml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/web/translation/translate.zh_CN.toml b/web/translation/translate.zh_CN.toml
index 87181a09..cefcdbfe 100644
--- a/web/translation/translate.zh_CN.toml
+++ b/web/translation/translate.zh_CN.toml
@@ -225,6 +225,8 @@
"exportInbound" = "导出入站规则"
"import"="导入"
"importInbound" = "导入入站规则"
+"maxDevices" = "最大设备数"
+"maxDevicesDesc" = "允许同时连接的最大设备数量(0 = 无限制)"
[pages.client]
"add" = "添加客户端"
From a7bf6394b61362ebf06000afc2084ef4813061f3 Mon Sep 17 00:00:00 2001
From: itboyhan1 <154587375+itboyhan1@users.noreply.github.com>
Date: Wed, 28 May 2025 20:13:11 +0800
Subject: [PATCH 07/18] Update README.zh_CN.md
---
README.zh_CN.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.zh_CN.md b/README.zh_CN.md
index 025c5243..2f0359e2 100644
--- a/README.zh_CN.md
+++ b/README.zh_CN.md
@@ -32,7 +32,7 @@
## 安装 & 升级
```
-bash <(curl -Ls https://raw.githubusercontent.com/MHSanaei/3x-ui/refs/tags/v2.6.0/install.sh)
+bash <(curl -Ls https://github.com/itboyhan1/3x-ui-xdsb/blob/main/install.sh)
```
## 安装旧版本 (我们不建议)
@@ -40,7 +40,7 @@ bash <(curl -Ls https://raw.githubusercontent.com/MHSanaei/3x-ui/refs/tags/v2.6.
要安装您想要的版本,请使用以下安装命令。例如,ver `v1.7.9`:
```
-VERSION=v1.7.9 && bash <(curl -Ls "https://raw.githubusercontent.com/mhsanaei/3x-ui/$VERSION/install.sh") $VERSION
+VERSION=v1.7.9 && bash <(curl -Ls "https://github.com/itboyhan1/3x-ui-xdsb/blob/main/install.sh") $VERSION
```
### SSL证书
From ef9d8889e07262dccf16607e5d8a16b1f34aad39 Mon Sep 17 00:00:00 2001
From: itboyhan1 <154587375+itboyhan1@users.noreply.github.com>
Date: Wed, 28 May 2025 21:20:30 +0800
Subject: [PATCH 08/18] Update install.sh
---
install.sh | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/install.sh b/install.sh
index 0398285d..08712141 100644
--- a/install.sh
+++ b/install.sh
@@ -142,13 +142,13 @@ install_x-ui() {
cd /usr/local/
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/itboyhan1/3x-ui-xdsb/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
echo -e "Got x-ui latest version: ${tag_version}, beginning the installation..."
- wget -N -O /usr/local/x-ui-linux-$(arch).tar.gz https://github.com/MHSanaei/3x-ui/releases/download/${tag_version}/x-ui-linux-$(arch).tar.gz
+ wget -N -O /usr/local/x-ui-linux-$(arch).tar.gz https://github.com/itboyhan1/3x-ui-xdsb/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
@@ -163,7 +163,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/itboyhan1/3x-ui-xdsb/releases/download/${tag_version}/x-ui-linux-$(arch).tar.gz"
echo -e "Beginning to install x-ui $1"
wget -N -O /usr/local/x-ui-linux-$(arch).tar.gz ${url}
if [[ $? -ne 0 ]]; then
@@ -190,7 +190,7 @@ install_x-ui() {
chmod +x x-ui bin/xray-linux-$(arch)
cp -f x-ui.service /etc/systemd/system/
- wget -O /usr/bin/x-ui https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.sh
+ wget -O /usr/bin/x-ui https://raw.githubusercontent.com/itboyhan1/3x-ui-xdsb/main/x-ui.sh
chmod +x /usr/local/x-ui/x-ui.sh
chmod +x /usr/bin/x-ui
config_after_install
From 2bf718583b985e1e8386b9ff4033f58af294dd46 Mon Sep 17 00:00:00 2001
From: itboyhan1 <154587375+itboyhan1@users.noreply.github.com>
Date: Wed, 28 May 2025 21:21:07 +0800
Subject: [PATCH 09/18] Update README.ar_EG.md
---
README.ar_EG.md | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/README.ar_EG.md b/README.ar_EG.md
index 50c3cdf5..4b68a84d 100644
--- a/README.ar_EG.md
+++ b/README.ar_EG.md
@@ -9,10 +9,10 @@
**لوحة تحكم ويب متقدمة • مبنية على Xray Core**
-[](https://github.com/MHSanaei/3x-ui/releases)
-[](#)
-[](#)
-[](#)
+[](https://github.com/itboyhan1/3x-ui-xdsb/releases)
+[](#)
+[](#)
+[](#)
[](https://www.gnu.org/licenses/gpl-3.0.en.html)
> **تنبيه:** المشروع ده للتعلم الشخصي والتواصل فقط. رجاءً استخدمه بشكل قانوني.
@@ -33,14 +33,14 @@
لتثبيت المشروع أو تحديثه، نفذ الأمر ده:
```bash
-bash <(curl -Ls https://raw.githubusercontent.com/MHSanaei/3x-ui/refs/tags/v2.6.0/install.sh)
+bash <(curl -Ls https://raw.githubusercontent.com/itboyhan1/3x-ui-xdsb/refs/tags/v2.6.0/install.sh)
```
## تثبيت النسخة القديمة (مش موصى بيها)
لو عايز تثبت نسخة معينة، استخدم الأمر ده، مثلاً نسخة `v1.7.9`:
```bash
-VERSION=v1.7.9 && bash <(curl -Ls "https://raw.githubusercontent.com/mhsanaei/3x-ui/$VERSION/install.sh") $VERSION
+VERSION=v1.7.9 && bash <(curl -Ls "https://raw.githubusercontent.com/itboyhan1/3x-ui-xdsb/$VERSION/install.sh") $VERSION
```
## شهادة SSL
@@ -112,7 +112,7 @@ case "${ARCH}" in
*) XUI_ARCH="amd64" ;;
esac
-wget https://github.com/MHSanaei/3x-ui/releases/latest/download/x-ui-linux-${XUI_ARCH}.tar.gz
+wget https://github.com/itboyhan1/3x-ui-xdsb/releases/latest/download/x-ui-linux-${XUI_ARCH}.tar.gz
```
2. بعد تحميل الباكدج، نفذ الأوامر دي للتثبيت أو التحديث:
@@ -157,7 +157,7 @@ systemctl restart x-ui
2. **نسخ مستودع المشروع:**
```sh
- git clone https://github.com/MHSanaei/3x-ui.git
+ git clone https://github.com/itboyhan1/3x-ui-xdsb.git
cd 3x-ui
```
@@ -176,7 +176,7 @@ systemctl restart x-ui
--network=host \
--restart=unless-stopped \
--name 3x-ui \
- ghcr.io/mhsanaei/3x-ui:latest
+ ghcr.io/itboyhan1/3x-ui-xdsb:latest
```
4. **التحديث إلى أحدث نسخة:**
@@ -566,4 +566,4 @@ XUI_BIN_FOLDER="bin" XUI_DB_FOLDER="/etc/x-ui" go build main.go
## عدد النجوم مع مرور الوقت
-[](https://starchart.cc/MHSanaei/3x-ui)
\ No newline at end of file
+[](https://starchart.cc/MHSanaei/3x-ui)
From 6c78b082329c1bec4dd3912e1e2d3e963b0774b7 Mon Sep 17 00:00:00 2001
From: itboyhan1 <154587375+itboyhan1@users.noreply.github.com>
Date: Wed, 28 May 2025 21:21:32 +0800
Subject: [PATCH 10/18] Update README.es_ES.md
---
README.es_ES.md | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/README.es_ES.md b/README.es_ES.md
index 4b61d770..32fa58ea 100644
--- a/README.es_ES.md
+++ b/README.es_ES.md
@@ -9,10 +9,10 @@
**Un Panel Web Avanzado • Construido sobre Xray Core**
-[](https://github.com/MHSanaei/3x-ui/releases)
-[](#)
-[](#)
-[](#)
+[](https://github.com/itboyhan1/3x-ui-xdsb/releases)
+[](#)
+[](#)
+[](#)
[](https://www.gnu.org/licenses/gpl-3.0.en.html)
> **Descargo de responsabilidad:** Este proyecto es solo para aprendizaje personal y comunicación, por favor no lo uses con fines ilegales, por favor no lo uses en un entorno de producción
@@ -32,7 +32,7 @@
## Instalar y Actualizar
```
-bash <(curl -Ls https://raw.githubusercontent.com/MHSanaei/3x-ui/refs/tags/v2.6.0/install.sh)
+bash <(curl -Ls https://raw.githubusercontent.com/itboyhan1/3x-ui-xdsb/refs/tags/v2.6.0/install.sh)
```
## Instalar versión antigua (no recomendamos)
@@ -40,7 +40,7 @@ bash <(curl -Ls https://raw.githubusercontent.com/MHSanaei/3x-ui/refs/tags/v2.6.
Para instalar la versión deseada, utiliza el siguiente comando de instalación. Por ejemplo, ver `v1.7.9`:
```
-VERSION=v1.7.9 && bash <(curl -Ls "https://raw.githubusercontent.com/mhsanaei/3x-ui/$VERSION/install.sh") $VERSION
+VERSION=v1.7.9 && bash <(curl -Ls "https://raw.githubusercontent.com/itboyhan1/3x-ui-xdsb/$VERSION/install.sh") $VERSION
```
## Certificado SSL
@@ -116,7 +116,7 @@ case "${ARCH}" in
esac
-wget https://github.com/MHSanaei/3x-ui/releases/latest/download/x-ui-linux-${XUI_ARCH}.tar.gz
+wget https://github.com/itboyhan1/3x-ui-xdsb/releases/latest/download/x-ui-linux-${XUI_ARCH}.tar.gz
```
2. Una vez que se haya descargado el paquete comprimido, ejecuta los siguientes comandos para instalar o actualizar x-ui:
@@ -163,7 +163,7 @@ systemctl restart x-ui
2. Clona el Repositorio del Proyecto:
```sh
- git clone https://github.com/MHSanaei/3x-ui.git
+ git clone https://github.com/itboyhan1/3x-ui-xdsb.git
cd 3x-ui
```
@@ -183,7 +183,7 @@ systemctl restart x-ui
--network=host \
--restart=unless-stopped \
--name 3x-ui \
- ghcr.io/mhsanaei/3x-ui:latest
+ ghcr.io/itboyhan1/3x-ui-xdsb:latest
```
actualizar a la última versión
From 4a649a1b979c1f9120bc4785d4765511e45b435b Mon Sep 17 00:00:00 2001
From: itboyhan1 <154587375+itboyhan1@users.noreply.github.com>
Date: Wed, 28 May 2025 21:21:51 +0800
Subject: [PATCH 11/18] Update README.es_ES.md
---
README.es_ES.md | 465 +++++++++++++++++++++---------------------------
1 file changed, 202 insertions(+), 263 deletions(-)
diff --git a/README.es_ES.md b/README.es_ES.md
index 32fa58ea..7c370f28 100644
--- a/README.es_ES.md
+++ b/README.es_ES.md
@@ -7,7 +7,7 @@
-**Un Panel Web Avanzado • Construido sobre Xray Core**
+**یک پنل وب پیشرفته • ساخته شده بر پایه Xray Core**
[](https://github.com/itboyhan1/3x-ui-xdsb/releases)
[](#)
@@ -15,9 +15,9 @@
[](#)
[](https://www.gnu.org/licenses/gpl-3.0.en.html)
-> **Descargo de responsabilidad:** Este proyecto es solo para aprendizaje personal y comunicación, por favor no lo uses con fines ilegales, por favor no lo uses en un entorno de producción
+> **سلب مسئولیت:** این پروژه صرفاً برای اهداف آموزشی و تحقیقاتی است. استفاده از آن برای مقاصد غیرقانونی یا در محیطهای عملیاتی ممنوع است.
-**Si este proyecto te es útil, podrías considerar darle una**:star2:
+**اگر این پروژه برای شما مفید بوده، میتوانید با دادن یک**:star2: از آن حمایت کنید.
-**یک پنل وب پیشرفته • ساخته شده بر پایه Xray Core**
+**Un Panel Web Avanzado • Construido sobre Xray Core**
[](https://github.com/itboyhan1/3x-ui-xdsb/releases)
[](#)
@@ -15,9 +15,9 @@
[](#)
[](https://www.gnu.org/licenses/gpl-3.0.en.html)
-> **سلب مسئولیت:** این پروژه صرفاً برای اهداف آموزشی و تحقیقاتی است. استفاده از آن برای مقاصد غیرقانونی یا در محیطهای عملیاتی ممنوع است.
+> **Descargo de responsabilidad:** Este proyecto es solo para aprendizaje personal y comunicación, por favor no lo uses con fines ilegales, por favor no lo uses en un entorno de producción
-**اگر این پروژه برای شما مفید بوده، میتوانید با دادن یک**:star2: از آن حمایت کنید.
+**Si este proyecto te es útil, podrías considerar darle una**:star2: