mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2025-09-09 19:56:19 +00:00
Merge branch 'main' into main
This commit is contained in:
commit
45b9a4a838
21 changed files with 139 additions and 564 deletions
51
README.md
51
README.md
|
@ -25,10 +25,10 @@ bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.
|
||||||
|
|
||||||
## Install Custom Version
|
## Install Custom Version
|
||||||
|
|
||||||
To install your desired version, add the version to the end of the installation command. e.g., ver `v2.1.0`:
|
To install your desired version, add the version to the end of the installation command. e.g., ver `v2.1.1`:
|
||||||
|
|
||||||
```
|
```
|
||||||
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) v2.1.0
|
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) v2.1.1
|
||||||
```
|
```
|
||||||
## Manual Install & Upgrade
|
## Manual Install & Upgrade
|
||||||
|
|
||||||
|
@ -103,6 +103,15 @@ systemctl restart x-ui
|
||||||
ghcr.io/mhsanaei/3x-ui:latest
|
ghcr.io/mhsanaei/3x-ui:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
|
update to latest version
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cd 3x-ui
|
||||||
|
docker compose down
|
||||||
|
docker compose pull 3x-ui
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
|
||||||
|
@ -196,26 +205,6 @@ certbot renew --dry-run
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
|
||||||
## Xray Configurations
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>Click for Xray configurations details</summary>
|
|
||||||
|
|
||||||
#### Usage
|
|
||||||
|
|
||||||
**1.** Copy & paste into the Advanced Xray Configuration:
|
|
||||||
|
|
||||||
- [traffic](./media/configs/traffic.json)
|
|
||||||
- [traffic + Block all Iran IP address](./media/configs/traffic+block-iran-ip.json)
|
|
||||||
- [traffic + Block all Iran Domains](./media/configs/traffic+block-iran-domains.json)
|
|
||||||
- [traffic + Block Ads + Use IPv4 for Google](./media/configs/traffic+block-ads+ipv4-google.json)
|
|
||||||
- [traffic + Block Ads + Route Google + Netflix + Spotify + OpenAI (ChatGPT) to WARP](./media/configs/traffic+block-ads+warp.json)
|
|
||||||
|
|
||||||
***Tip:*** *You don't need to do this for a fresh install.*
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
## [WARP Configuration](https://gitlab.com/fscarmen/warp)
|
## [WARP Configuration](https://gitlab.com/fscarmen/warp)
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
|
@ -223,21 +212,21 @@ certbot renew --dry-run
|
||||||
|
|
||||||
#### Usage
|
#### Usage
|
||||||
|
|
||||||
If you want to use routing to WARP follow steps as below:
|
If you want to use routing to WARP before v2.1.0 follow steps as below:
|
||||||
|
|
||||||
**1.** If you already installed warp, you can uninstall using below command:
|
**1.** Install WARP on **SOCKS Proxy Mode**:
|
||||||
|
|
||||||
```sh
|
|
||||||
warp u
|
|
||||||
```
|
|
||||||
|
|
||||||
**2.** Install WARP on **SOCKS Proxy Mode**:
|
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
bash <(curl -sSL https://raw.githubusercontent.com/hamid-gh98/x-ui-scripts/main/install_warp_proxy.sh)
|
bash <(curl -sSL https://raw.githubusercontent.com/hamid-gh98/x-ui-scripts/main/install_warp_proxy.sh)
|
||||||
```
|
```
|
||||||
|
|
||||||
**3.** Turn on the config you need in panel or [Copy and paste this file to Xray Configuration](./media/configs/traffic+block-ads+warp.json)
|
**2.** If you already installed warp, you can uninstall using below command:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
warp u
|
||||||
|
```
|
||||||
|
|
||||||
|
**3.** Turn on the config you need in panel
|
||||||
|
|
||||||
Config Features:
|
Config Features:
|
||||||
|
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
2.1.2
|
2.1.1
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ type Inbound struct {
|
||||||
|
|
||||||
// config part
|
// config part
|
||||||
Listen string `json:"listen" form:"listen"`
|
Listen string `json:"listen" form:"listen"`
|
||||||
Port int `json:"port" form:"port" gorm:"unique"`
|
Port int `json:"port" form:"port"`
|
||||||
Protocol Protocol `json:"protocol" form:"protocol"`
|
Protocol Protocol `json:"protocol" form:"protocol"`
|
||||||
Settings string `json:"settings" form:"settings"`
|
Settings string `json:"settings" form:"settings"`
|
||||||
StreamSettings string `json:"streamSettings" form:"streamSettings"`
|
StreamSettings string `json:"streamSettings" form:"streamSettings"`
|
||||||
|
|
|
@ -167,6 +167,7 @@ install_x-ui() {
|
||||||
|
|
||||||
# Check the system's architecture and rename the file accordingly
|
# Check the system's architecture and rename the file accordingly
|
||||||
if [[ $(arch3xui) == "armv5" || $(arch3xui) == "armv6" || $(arch3xui) == "armv7" ]]; then
|
if [[ $(arch3xui) == "armv5" || $(arch3xui) == "armv6" || $(arch3xui) == "armv7" ]]; then
|
||||||
|
|
||||||
mv bin/xray-linux-$(arch3xui) bin/xray-linux-arm
|
mv bin/xray-linux-$(arch3xui) bin/xray-linux-arm
|
||||||
chmod +x bin/xray-linux-arm
|
chmod +x bin/xray-linux-arm
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -1,97 +0,0 @@
|
||||||
{
|
|
||||||
"log": {
|
|
||||||
"loglevel": "warning",
|
|
||||||
"error": "./error.log"
|
|
||||||
},
|
|
||||||
"api": {
|
|
||||||
"tag": "api",
|
|
||||||
"services": [
|
|
||||||
"HandlerService",
|
|
||||||
"LoggerService",
|
|
||||||
"StatsService"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"inbounds": [
|
|
||||||
{
|
|
||||||
"tag": "api",
|
|
||||||
"listen": "127.0.0.1",
|
|
||||||
"port": 62789,
|
|
||||||
"protocol": "dokodemo-door",
|
|
||||||
"settings": {
|
|
||||||
"address": "127.0.0.1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"outbounds": [
|
|
||||||
{
|
|
||||||
"protocol": "freedom",
|
|
||||||
"settings": {}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "blocked",
|
|
||||||
"protocol": "blackhole",
|
|
||||||
"settings": {}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "IPv4",
|
|
||||||
"protocol": "freedom",
|
|
||||||
"settings": {
|
|
||||||
"domainStrategy": "UseIPv4"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"policy": {
|
|
||||||
"levels": {
|
|
||||||
"0": {
|
|
||||||
"statsUserDownlink": true,
|
|
||||||
"statsUserUplink": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"system": {
|
|
||||||
"statsInboundDownlink": true,
|
|
||||||
"statsInboundUplink": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"routing": {
|
|
||||||
"domainStrategy": "IPIfNonMatch",
|
|
||||||
"rules": [
|
|
||||||
{
|
|
||||||
"type": "field",
|
|
||||||
"inboundTag": [
|
|
||||||
"api"
|
|
||||||
],
|
|
||||||
"outboundTag": "api"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "field",
|
|
||||||
"outboundTag": "blocked",
|
|
||||||
"ip": [
|
|
||||||
"geoip:private"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "field",
|
|
||||||
"outboundTag": "blocked",
|
|
||||||
"protocol": [
|
|
||||||
"bittorrent"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "field",
|
|
||||||
"outboundTag": "blocked",
|
|
||||||
"domain": [
|
|
||||||
"geosite:category-ads-all",
|
|
||||||
"ext:geosite_IR.dat:category-ads-all"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "field",
|
|
||||||
"outboundTag": "IPv4",
|
|
||||||
"domain": [
|
|
||||||
"geosite:google"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"stats": {}
|
|
||||||
}
|
|
|
@ -1,105 +0,0 @@
|
||||||
{
|
|
||||||
"log": {
|
|
||||||
"loglevel": "warning",
|
|
||||||
"error": "./error.log"
|
|
||||||
},
|
|
||||||
"api": {
|
|
||||||
"tag": "api",
|
|
||||||
"services": [
|
|
||||||
"HandlerService",
|
|
||||||
"LoggerService",
|
|
||||||
"StatsService"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"inbounds": [
|
|
||||||
{
|
|
||||||
"tag": "api",
|
|
||||||
"listen": "127.0.0.1",
|
|
||||||
"port": 62789,
|
|
||||||
"protocol": "dokodemo-door",
|
|
||||||
"settings": {
|
|
||||||
"address": "127.0.0.1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"outbounds": [
|
|
||||||
{
|
|
||||||
"protocol": "freedom",
|
|
||||||
"settings": {}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "blocked",
|
|
||||||
"protocol": "blackhole",
|
|
||||||
"settings": {}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "WARP",
|
|
||||||
"protocol": "socks",
|
|
||||||
"settings": {
|
|
||||||
"servers": [
|
|
||||||
{
|
|
||||||
"address": "127.0.0.1",
|
|
||||||
"port": 40000
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"policy": {
|
|
||||||
"levels": {
|
|
||||||
"0": {
|
|
||||||
"statsUserDownlink": true,
|
|
||||||
"statsUserUplink": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"system": {
|
|
||||||
"statsInboundDownlink": true,
|
|
||||||
"statsInboundUplink": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"routing": {
|
|
||||||
"domainStrategy": "IPIfNonMatch",
|
|
||||||
"rules": [
|
|
||||||
{
|
|
||||||
"type": "field",
|
|
||||||
"inboundTag": [
|
|
||||||
"api"
|
|
||||||
],
|
|
||||||
"outboundTag": "api"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "field",
|
|
||||||
"outboundTag": "blocked",
|
|
||||||
"ip": [
|
|
||||||
"geoip:private"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "field",
|
|
||||||
"outboundTag": "blocked",
|
|
||||||
"protocol": [
|
|
||||||
"bittorrent"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "field",
|
|
||||||
"outboundTag": "blocked",
|
|
||||||
"domain": [
|
|
||||||
"geosite:category-ads-all",
|
|
||||||
"ext:geosite_IR.dat:category-ads-all"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "field",
|
|
||||||
"outboundTag": "WARP",
|
|
||||||
"domain": [
|
|
||||||
"geosite:spotify",
|
|
||||||
"geosite:netflix",
|
|
||||||
"geosite:openai",
|
|
||||||
"geosite:google"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"stats": {}
|
|
||||||
}
|
|
|
@ -1,84 +0,0 @@
|
||||||
{
|
|
||||||
"log": {
|
|
||||||
"loglevel": "warning",
|
|
||||||
"error": "./error.log"
|
|
||||||
},
|
|
||||||
"api": {
|
|
||||||
"tag": "api",
|
|
||||||
"services": [
|
|
||||||
"HandlerService",
|
|
||||||
"LoggerService",
|
|
||||||
"StatsService"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"inbounds": [
|
|
||||||
{
|
|
||||||
"tag": "api",
|
|
||||||
"listen": "127.0.0.1",
|
|
||||||
"port": 62789,
|
|
||||||
"protocol": "dokodemo-door",
|
|
||||||
"settings": {
|
|
||||||
"address": "127.0.0.1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"outbounds": [
|
|
||||||
{
|
|
||||||
"protocol": "freedom",
|
|
||||||
"settings": {}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "blocked",
|
|
||||||
"protocol": "blackhole",
|
|
||||||
"settings": {}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"policy": {
|
|
||||||
"levels": {
|
|
||||||
"0": {
|
|
||||||
"statsUserDownlink": true,
|
|
||||||
"statsUserUplink": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"system": {
|
|
||||||
"statsInboundDownlink": true,
|
|
||||||
"statsInboundUplink": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"routing": {
|
|
||||||
"domainStrategy": "IPIfNonMatch",
|
|
||||||
"rules": [
|
|
||||||
{
|
|
||||||
"type": "field",
|
|
||||||
"inboundTag": [
|
|
||||||
"api"
|
|
||||||
],
|
|
||||||
"outboundTag": "api"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "field",
|
|
||||||
"outboundTag": "blocked",
|
|
||||||
"ip": [
|
|
||||||
"geoip:private"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "field",
|
|
||||||
"outboundTag": "blocked",
|
|
||||||
"protocol": [
|
|
||||||
"bittorrent"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "field",
|
|
||||||
"outboundTag": "blocked",
|
|
||||||
"domain": [
|
|
||||||
"regexp:.*\\.ir$",
|
|
||||||
"regexp:.*\\.xn--mgba3a4f16a$",
|
|
||||||
"ext:geosite_IR.dat:ir"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"stats": {}
|
|
||||||
}
|
|
|
@ -1,76 +0,0 @@
|
||||||
{
|
|
||||||
"log": {
|
|
||||||
"loglevel": "warning",
|
|
||||||
"error": "./error.log"
|
|
||||||
},
|
|
||||||
"api": {
|
|
||||||
"tag": "api",
|
|
||||||
"services": [
|
|
||||||
"HandlerService",
|
|
||||||
"LoggerService",
|
|
||||||
"StatsService"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"inbounds": [
|
|
||||||
{
|
|
||||||
"tag": "api",
|
|
||||||
"listen": "127.0.0.1",
|
|
||||||
"port": 62789,
|
|
||||||
"protocol": "dokodemo-door",
|
|
||||||
"settings": {
|
|
||||||
"address": "127.0.0.1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"outbounds": [
|
|
||||||
{
|
|
||||||
"protocol": "freedom",
|
|
||||||
"settings": {}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "blocked",
|
|
||||||
"protocol": "blackhole",
|
|
||||||
"settings": {}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"policy": {
|
|
||||||
"levels": {
|
|
||||||
"0": {
|
|
||||||
"statsUserDownlink": true,
|
|
||||||
"statsUserUplink": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"system": {
|
|
||||||
"statsInboundDownlink": true,
|
|
||||||
"statsInboundUplink": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"routing": {
|
|
||||||
"domainStrategy": "IPIfNonMatch",
|
|
||||||
"rules": [
|
|
||||||
{
|
|
||||||
"type": "field",
|
|
||||||
"inboundTag": [
|
|
||||||
"api"
|
|
||||||
],
|
|
||||||
"outboundTag": "api"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "field",
|
|
||||||
"outboundTag": "blocked",
|
|
||||||
"ip": [
|
|
||||||
"geoip:private",
|
|
||||||
"ext:geoip_IR.dat:ir"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "field",
|
|
||||||
"outboundTag": "blocked",
|
|
||||||
"protocol": [
|
|
||||||
"bittorrent"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"stats": {}
|
|
||||||
}
|
|
|
@ -1,65 +0,0 @@
|
||||||
{
|
|
||||||
"log": {
|
|
||||||
"loglevel": "warning",
|
|
||||||
"error": "./error.log"
|
|
||||||
},
|
|
||||||
"api": {
|
|
||||||
"tag": "api",
|
|
||||||
"services": ["HandlerService", "LoggerService", "StatsService"]
|
|
||||||
},
|
|
||||||
"inbounds": [
|
|
||||||
{
|
|
||||||
"tag": "api",
|
|
||||||
"listen": "127.0.0.1",
|
|
||||||
"port": 62789,
|
|
||||||
"protocol": "dokodemo-door",
|
|
||||||
"settings": {
|
|
||||||
"address": "127.0.0.1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"outbounds": [
|
|
||||||
{
|
|
||||||
"protocol": "freedom",
|
|
||||||
"settings": {}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "blocked",
|
|
||||||
"protocol": "blackhole",
|
|
||||||
"settings": {}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"policy": {
|
|
||||||
"levels": {
|
|
||||||
"0": {
|
|
||||||
"statsUserDownlink": true,
|
|
||||||
"statsUserUplink": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"system": {
|
|
||||||
"statsInboundDownlink": true,
|
|
||||||
"statsInboundUplink": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"routing": {
|
|
||||||
"domainStrategy": "IPIfNonMatch",
|
|
||||||
"rules": [
|
|
||||||
{
|
|
||||||
"type": "field",
|
|
||||||
"inboundTag": ["api"],
|
|
||||||
"outboundTag": "api"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "field",
|
|
||||||
"outboundTag": "blocked",
|
|
||||||
"ip": ["geoip:private"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "field",
|
|
||||||
"outboundTag": "blocked",
|
|
||||||
"protocol": ["bittorrent"]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"stats": {}
|
|
||||||
}
|
|
|
@ -85,7 +85,11 @@ func (a *InboundController) addInbound(c *gin.Context) {
|
||||||
}
|
}
|
||||||
user := session.GetLoginUser(c)
|
user := session.GetLoginUser(c)
|
||||||
inbound.UserId = user.Id
|
inbound.UserId = user.Id
|
||||||
inbound.Tag = fmt.Sprintf("inbound-%v", inbound.Port)
|
if inbound.Listen == "" || inbound.Listen == "0.0.0.0" || inbound.Listen == "::" || inbound.Listen == "::0" {
|
||||||
|
inbound.Tag = fmt.Sprintf("inbound-0.0.0.0:%v", inbound.Port)
|
||||||
|
} else {
|
||||||
|
inbound.Tag = fmt.Sprintf("inbound-%v:%v", inbound.Listen, inbound.Port)
|
||||||
|
}
|
||||||
|
|
||||||
needRestart := false
|
needRestart := false
|
||||||
inbound, needRestart, err = a.inboundService.AddInbound(inbound)
|
inbound, needRestart, err = a.inboundService.AddInbound(inbound)
|
||||||
|
@ -278,7 +282,11 @@ func (a *InboundController) importInbound(c *gin.Context) {
|
||||||
user := session.GetLoginUser(c)
|
user := session.GetLoginUser(c)
|
||||||
inbound.Id = 0
|
inbound.Id = 0
|
||||||
inbound.UserId = user.Id
|
inbound.UserId = user.Id
|
||||||
inbound.Tag = fmt.Sprintf("inbound-%v", inbound.Port)
|
if inbound.Listen == "" || inbound.Listen == "0.0.0.0" || inbound.Listen == "::" || inbound.Listen == "::0" {
|
||||||
|
inbound.Tag = fmt.Sprintf("inbound-0.0.0.0:%v", inbound.Port)
|
||||||
|
} else {
|
||||||
|
inbound.Tag = fmt.Sprintf("inbound-%v:%v", inbound.Listen, inbound.Port)
|
||||||
|
}
|
||||||
|
|
||||||
for index := range inbound.ClientStats {
|
for index := range inbound.ClientStats {
|
||||||
inbound.ClientStats[index].Id = 0
|
inbound.ClientStats[index].Id = 0
|
||||||
|
|
|
@ -93,7 +93,7 @@
|
||||||
<a-col :sm="24" :md="12">
|
<a-col :sm="24" :md="12">
|
||||||
<a-card hoverable>
|
<a-card hoverable>
|
||||||
{{ i18n "pages.index.xrayStatus" }}:
|
{{ i18n "pages.index.xrayStatus" }}:
|
||||||
<a-tag :color="status.xray.color">[[ status.xray.state.toUpperCase() ]]</a-tag>
|
<a-tag :color="status.xray.color">[[ status.xray.state ]]</a-tag>
|
||||||
<a-popover v-if="status.xray.state === State.Error"
|
<a-popover v-if="status.xray.state === State.Error"
|
||||||
:overlay-class-name="themeSwitcher.currentTheme">
|
:overlay-class-name="themeSwitcher.currentTheme">
|
||||||
<span slot="title" style="font-size: 12pt">An error occurred while running Xray
|
<span slot="title" style="font-size: 12pt">An error occurred while running Xray
|
||||||
|
|
|
@ -244,7 +244,7 @@
|
||||||
<setting-list-item type="switch" title='{{ i18n "pages.settings.tgNotifyBackup" }}' desc='{{ i18n "pages.settings.tgNotifyBackupDesc" }}' v-model="allSetting.tgBotBackup"></setting-list-item>
|
<setting-list-item type="switch" title='{{ i18n "pages.settings.tgNotifyBackup" }}' desc='{{ i18n "pages.settings.tgNotifyBackupDesc" }}' v-model="allSetting.tgBotBackup"></setting-list-item>
|
||||||
<setting-list-item type="switch" title='{{ i18n "pages.settings.tgNotifyLogin" }}' desc='{{ i18n "pages.settings.tgNotifyLoginDesc" }}' v-model="allSetting.tgBotLoginNotify"></setting-list-item>
|
<setting-list-item type="switch" title='{{ i18n "pages.settings.tgNotifyLogin" }}' desc='{{ i18n "pages.settings.tgNotifyLoginDesc" }}' v-model="allSetting.tgBotLoginNotify"></setting-list-item>
|
||||||
<setting-list-item type="number" title='{{ i18n "pages.settings.tgNotifyCpu" }}' desc='{{ i18n "pages.settings.tgNotifyCpuDesc" }}' v-model="allSetting.tgCpu" :min="0" :max="100"></setting-list-item>
|
<setting-list-item type="number" title='{{ i18n "pages.settings.tgNotifyCpu" }}' desc='{{ i18n "pages.settings.tgNotifyCpuDesc" }}' v-model="allSetting.tgCpu" :min="0" :max="100"></setting-list-item>
|
||||||
<setting-list-item type="text" title='{{ i18n "pages.settings.telegramProxy"}}' desc='{{ i18n "pages.settings.telegramProxyDesc"}}' v-model="allSetting.tgBotProxy" placeholder="socks5://[user:pass@]host:port"></setting-list-item>
|
<setting-list-item type="text" title='{{ i18n "pages.settings.telegramProxy"}}' desc='{{ i18n "pages.settings.telegramProxyDesc"}}' v-model="allSetting.tgBotProxy" placeholder="socks5://user:pass@host:port"></setting-list-item>
|
||||||
<a-list-item>
|
<a-list-item>
|
||||||
<a-row style="padding: 20px">
|
<a-row style="padding: 20px">
|
||||||
<a-col :lg="24" :xl="12">
|
<a-col :lg="24" :xl="12">
|
||||||
|
|
|
@ -1122,26 +1122,6 @@
|
||||||
this.templateRuleSetter({ outboundTag: "warp", property: "domain", data: newValue });
|
this.templateRuleSetter({ outboundTag: "warp", property: "domain", data: newValue });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
manualBlockedIPs: {
|
|
||||||
get: function () { return JSON.stringify(this.blockedIPs, null, 2); },
|
|
||||||
set: debounce(function (value) { this.blockedIPs = JSON.parse(value); }, 1000)
|
|
||||||
},
|
|
||||||
manualBlockedDomains: {
|
|
||||||
get: function () { return JSON.stringify(this.blockedDomains, null, 2); },
|
|
||||||
set: debounce(function (value) { this.blockedDomains = JSON.parse(value); }, 1000)
|
|
||||||
},
|
|
||||||
manualDirectIPs: {
|
|
||||||
get: function () { return JSON.stringify(this.directIPs, null, 2); },
|
|
||||||
set: debounce(function (value) { this.directIPs = JSON.parse(value); }, 1000)
|
|
||||||
},
|
|
||||||
manualDirectDomains: {
|
|
||||||
get: function () { return JSON.stringify(this.directDomains, null, 2); },
|
|
||||||
set: debounce(function (value) { this.directDomains = JSON.parse(value); }, 1000)
|
|
||||||
},
|
|
||||||
manualIPv4Domains: {
|
|
||||||
get: function () { return JSON.stringify(this.ipv4Domains, null, 2); },
|
|
||||||
set: debounce(function (value) { this.ipv4Domains = JSON.parse(value); }, 1000)
|
|
||||||
},
|
|
||||||
torrentSettings: {
|
torrentSettings: {
|
||||||
get: function () {
|
get: function () {
|
||||||
return doAllItemsExist(this.settingsData.protocols.bittorrent, this.blockedProtocols);
|
return doAllItemsExist(this.settingsData.protocols.bittorrent, this.blockedProtocols);
|
||||||
|
|
|
@ -38,9 +38,25 @@ func (s *InboundService) GetAllInbounds() ([]*model.Inbound, error) {
|
||||||
return inbounds, nil
|
return inbounds, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *InboundService) checkPortExist(port int, ignoreId int) (bool, error) {
|
func (s *InboundService) checkPortExist(listen string, port int, ignoreId int) (bool, error) {
|
||||||
db := database.GetDB()
|
db := database.GetDB()
|
||||||
db = db.Model(model.Inbound{}).Where("port = ?", port)
|
if listen == "" || listen == "0.0.0.0" || listen == "::" || listen == "::0" {
|
||||||
|
db = db.Model(model.Inbound{}).Where("port = ?", port)
|
||||||
|
} else {
|
||||||
|
db = db.Model(model.Inbound{}).
|
||||||
|
Where("port = ?", port).
|
||||||
|
Where(
|
||||||
|
db.Model(model.Inbound{}).Where(
|
||||||
|
"listen = ?", listen,
|
||||||
|
).Or(
|
||||||
|
"listen = \"\"",
|
||||||
|
).Or(
|
||||||
|
"listen = \"0.0.0.0\"",
|
||||||
|
).Or(
|
||||||
|
"listen = \"::\"",
|
||||||
|
).Or(
|
||||||
|
"listen = \"::0\""))
|
||||||
|
}
|
||||||
if ignoreId > 0 {
|
if ignoreId > 0 {
|
||||||
db = db.Where("id != ?", ignoreId)
|
db = db.Where("id != ?", ignoreId)
|
||||||
}
|
}
|
||||||
|
@ -135,7 +151,7 @@ func (s *InboundService) checkEmailExistForInbound(inbound *model.Inbound) (stri
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *InboundService) AddInbound(inbound *model.Inbound) (*model.Inbound, bool, error) {
|
func (s *InboundService) AddInbound(inbound *model.Inbound) (*model.Inbound, bool, error) {
|
||||||
exist, err := s.checkPortExist(inbound.Port, 0)
|
exist, err := s.checkPortExist(inbound.Listen, inbound.Port, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return inbound, false, err
|
return inbound, false, err
|
||||||
}
|
}
|
||||||
|
@ -252,7 +268,7 @@ func (s *InboundService) GetInbound(id int) (*model.Inbound, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *InboundService) UpdateInbound(inbound *model.Inbound) (*model.Inbound, bool, error) {
|
func (s *InboundService) UpdateInbound(inbound *model.Inbound) (*model.Inbound, bool, error) {
|
||||||
exist, err := s.checkPortExist(inbound.Port, inbound.Id)
|
exist, err := s.checkPortExist(inbound.Listen, inbound.Port, inbound.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return inbound, false, err
|
return inbound, false, err
|
||||||
}
|
}
|
||||||
|
@ -295,7 +311,12 @@ func (s *InboundService) UpdateInbound(inbound *model.Inbound) (*model.Inbound,
|
||||||
oldInbound.Settings = inbound.Settings
|
oldInbound.Settings = inbound.Settings
|
||||||
oldInbound.StreamSettings = inbound.StreamSettings
|
oldInbound.StreamSettings = inbound.StreamSettings
|
||||||
oldInbound.Sniffing = inbound.Sniffing
|
oldInbound.Sniffing = inbound.Sniffing
|
||||||
oldInbound.Tag = fmt.Sprintf("inbound-%v", inbound.Port)
|
if inbound.Listen == "" || inbound.Listen == "0.0.0.0" || inbound.Listen == "::" || inbound.Listen == "::0" {
|
||||||
|
oldInbound.Tag = fmt.Sprintf("inbound-0.0.0.0:%v", inbound.Port)
|
||||||
|
} else {
|
||||||
|
oldInbound.Tag = fmt.Sprintf("inbound-%v:%v", inbound.Listen, inbound.Port)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
needRestart := false
|
needRestart := false
|
||||||
s.xrayApi.Init(p.GetAPIPort())
|
s.xrayApi.Init(p.GetAPIPort())
|
||||||
|
|
|
@ -54,11 +54,11 @@
|
||||||
"security" = "Security"
|
"security" = "Security"
|
||||||
|
|
||||||
[menu]
|
[menu]
|
||||||
"dashboard" = "OVERVIEW"
|
"dashboard" = "Overview"
|
||||||
"inbounds" = "INBOUNDS"
|
"inbounds" = "Inbounds"
|
||||||
"settings" = "PANEL SETTINGS"
|
"settings" = "Panel Settings"
|
||||||
"xray" = "XRAY CONFIGS"
|
"xray" = "Xray Configs"
|
||||||
"logout" = "LOG OUT"
|
"logout" = "Log Out"
|
||||||
"link" = "Manage"
|
"link" = "Manage"
|
||||||
|
|
||||||
[pages.login]
|
[pages.login]
|
||||||
|
@ -319,7 +319,7 @@
|
||||||
"ipv4Configs" = "IPv4 Routing"
|
"ipv4Configs" = "IPv4 Routing"
|
||||||
"ipv4ConfigsDesc" = "These options will route traffic based on a specific destination via IPv4."
|
"ipv4ConfigsDesc" = "These options will route traffic based on a specific destination via IPv4."
|
||||||
"warpConfigs" = "WARP Routing"
|
"warpConfigs" = "WARP Routing"
|
||||||
"warpConfigsDesc" = "These options will route traffic based on a specific destination via WARP. (follow the guide on the Panel’s GitHub)"
|
"warpConfigsDesc" = "These options will route traffic based on a specific destination via WARP."
|
||||||
"Template" = "Advanced Xray Configuration Template"
|
"Template" = "Advanced Xray Configuration Template"
|
||||||
"TemplateDesc" = "The final Xray config file will be generated based on this template."
|
"TemplateDesc" = "The final Xray config file will be generated based on this template."
|
||||||
"FreedomStrategy" = "Freedom Protocol Strategy"
|
"FreedomStrategy" = "Freedom Protocol Strategy"
|
||||||
|
@ -476,7 +476,6 @@
|
||||||
"helpAdminCommands" = "To search for a client email:\r\n<code>/usage [Email]</code>\r\n\r\nTo search for inbounds (with client stats):\r\n<code>/inbound [Remark]</code>"
|
"helpAdminCommands" = "To search for a client email:\r\n<code>/usage [Email]</code>\r\n\r\nTo search for inbounds (with client stats):\r\n<code>/inbound [Remark]</code>"
|
||||||
"helpClientCommands" = "To search for statistics, use the following command:\r\n\r\n<code>/usage [Email]</code>"
|
"helpClientCommands" = "To search for statistics, use the following command:\r\n\r\n<code>/usage [Email]</code>"
|
||||||
|
|
||||||
|
|
||||||
[tgbot.messages]
|
[tgbot.messages]
|
||||||
"cpuThreshold" = "🔴 CPU Load {{ .Percent }}% exceeds the threshold of {{ .Threshold }}%"
|
"cpuThreshold" = "🔴 CPU Load {{ .Percent }}% exceeds the threshold of {{ .Threshold }}%"
|
||||||
"selectUserFailed" = "❌ Error in user selection!"
|
"selectUserFailed" = "❌ Error in user selection!"
|
||||||
|
@ -522,7 +521,6 @@
|
||||||
"yes" = "✅ Yes"
|
"yes" = "✅ Yes"
|
||||||
"no" = "❌ No"
|
"no" = "❌ No"
|
||||||
|
|
||||||
|
|
||||||
[tgbot.buttons]
|
[tgbot.buttons]
|
||||||
"closeKeyboard" = "❌ Close Keyboard"
|
"closeKeyboard" = "❌ Close Keyboard"
|
||||||
"cancel" = "❌ Cancel"
|
"cancel" = "❌ Cancel"
|
||||||
|
@ -556,7 +554,6 @@
|
||||||
"limitTraffic" = "🚧 Traffic Limit"
|
"limitTraffic" = "🚧 Traffic Limit"
|
||||||
"getBanLogs" = "Get Ban Logs"
|
"getBanLogs" = "Get Ban Logs"
|
||||||
|
|
||||||
|
|
||||||
[tgbot.answers]
|
[tgbot.answers]
|
||||||
"successfulOperation" = "✅ Operation successful!"
|
"successfulOperation" = "✅ Operation successful!"
|
||||||
"errorOperation" = "❗ Error in operation."
|
"errorOperation" = "❗ Error in operation."
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
"username" = "Nombre de Usuario"
|
"username" = "Nombre de Usuario"
|
||||||
"password" = "Contraseña"
|
"password" = "Contraseña"
|
||||||
"login" = "Acceso"
|
"login" = "Acceder"
|
||||||
"confirm" = "Confirmar"
|
"confirm" = "Confirmar"
|
||||||
"cancel" = "Cancelar"
|
"cancel" = "Cancelar"
|
||||||
"close" = "Cerrar"
|
"close" = "Cerrar"
|
||||||
|
@ -59,10 +59,10 @@
|
||||||
"settings" = "Configuraciones"
|
"settings" = "Configuraciones"
|
||||||
"xray" = "Configuración Xray"
|
"xray" = "Configuración Xray"
|
||||||
"logout" = "Cerrar Sesión"
|
"logout" = "Cerrar Sesión"
|
||||||
"link" = "Otro"
|
"link" = "Gestionar"
|
||||||
|
|
||||||
[pages.login]
|
[pages.login]
|
||||||
"title" = "Grata"
|
"title" = "Bienvenido"
|
||||||
"loginAgain" = "El límite de tiempo de inicio de sesión ha expirado. Por favor, inicia sesión nuevamente."
|
"loginAgain" = "El límite de tiempo de inicio de sesión ha expirado. Por favor, inicia sesión nuevamente."
|
||||||
|
|
||||||
[pages.login.toasts]
|
[pages.login.toasts]
|
||||||
|
|
|
@ -501,8 +501,8 @@
|
||||||
"time" = "⏰ زمان: {{ .Time }}\r\n"
|
"time" = "⏰ زمان: {{ .Time }}\r\n"
|
||||||
"inbound" = "📍 نامورودی: {{ .Remark }}\r\n"
|
"inbound" = "📍 نامورودی: {{ .Remark }}\r\n"
|
||||||
"port" = "🔌 پورت: {{ .Port }}\r\n"
|
"port" = "🔌 پورت: {{ .Port }}\r\n"
|
||||||
"expire" = "📅 تاریخانقضا: {{ .DateTime }}\r\n \r\n"
|
"expire" = "📅 تاریخانقضا: {{ .Time }}\r\n\r\n"
|
||||||
"expireIn" = "📅 باقیماندهتاانقضا: {{ .Time }}\r\n \r\n"
|
"expireIn" = "📅 باقیماندهتاانقضا: {{ .Time }}\r\n\r\n"
|
||||||
"active" = "💡 فعال: {{ .Enable }}\r\n"
|
"active" = "💡 فعال: {{ .Enable }}\r\n"
|
||||||
"enabled" = "🚨 وضعیت: {{ .Enable }}\r\n"
|
"enabled" = "🚨 وضعیت: {{ .Enable }}\r\n"
|
||||||
"online" = "🌐 وضعیت اتصال: {{ .Status }}\r\n"
|
"online" = "🌐 وضعیت اتصال: {{ .Status }}\r\n"
|
||||||
|
@ -515,7 +515,7 @@
|
||||||
"exhaustedCount" = "🚨 تعداد {{ .Type }} بهاتمامرسیدهاست:\r\n"
|
"exhaustedCount" = "🚨 تعداد {{ .Type }} بهاتمامرسیدهاست:\r\n"
|
||||||
"onlinesCount" = "🌐 کاربرانآنلاین: {{ .Count }}\r\n"
|
"onlinesCount" = "🌐 کاربرانآنلاین: {{ .Count }}\r\n"
|
||||||
"disabled" = "🛑 غیرفعال: {{ .Disabled }}\r\n"
|
"disabled" = "🛑 غیرفعال: {{ .Disabled }}\r\n"
|
||||||
"depleteSoon" = "🔜 بهزودیبهپایانخواهدرسید: {{ .Deplete }}\r\n \r\n"
|
"depleteSoon" = "🔜 بهزودیبهپایانخواهدرسید: {{ .Deplete }}\r\n\r\n"
|
||||||
"backupTime" = "🗄 زمانپشتیبانگیری: {{ .Time }}\r\n"
|
"backupTime" = "🗄 زمانپشتیبانگیری: {{ .Time }}\r\n"
|
||||||
"refreshedOn" = "\r\n📋🔄 تازهسازی شده در: {{ .Time }}\r\n\r\n"
|
"refreshedOn" = "\r\n📋🔄 تازهسازی شده در: {{ .Time }}\r\n\r\n"
|
||||||
"yes" = "✅ بله"
|
"yes" = "✅ بله"
|
||||||
|
@ -537,7 +537,6 @@
|
||||||
"clientUsage" = "دریافت آمار کاربر"
|
"clientUsage" = "دریافت آمار کاربر"
|
||||||
"onlines" = "کاربران آنلاین"
|
"onlines" = "کاربران آنلاین"
|
||||||
"commands" = "دستورات"
|
"commands" = "دستورات"
|
||||||
|
|
||||||
"refresh" = "🔄 تازهسازی"
|
"refresh" = "🔄 تازهسازی"
|
||||||
"clearIPs" = "❌ پاکسازی آدرسها"
|
"clearIPs" = "❌ پاکسازی آدرسها"
|
||||||
"removeTGUser" = "❌ حذف کاربر تلگرام"
|
"removeTGUser" = "❌ حذف کاربر تلگرام"
|
||||||
|
|
|
@ -503,7 +503,7 @@
|
||||||
"port" = "🔌 Порт: {{ .Port }}\r\n"
|
"port" = "🔌 Порт: {{ .Port }}\r\n"
|
||||||
"expire" = "📅 Дата окончания: {{ .Time }}\r\n"
|
"expire" = "📅 Дата окончания: {{ .Time }}\r\n"
|
||||||
"expireIn" = "📅 Окончание через: {{ .Time }}\r\n"
|
"expireIn" = "📅 Окончание через: {{ .Time }}\r\n"
|
||||||
"active" = "💡 Активен: ✅ Да\r\n"
|
"active" = "💡 Активен: {{ .Enable }}\r\n"
|
||||||
"enabled" = "🚨 Включен: {{ .Enable }}\r\n"
|
"enabled" = "🚨 Включен: {{ .Enable }}\r\n"
|
||||||
"online" = "🌐 Статус соединения: {{ .Status }}\r\n"
|
"online" = "🌐 Статус соединения: {{ .Status }}\r\n"
|
||||||
"email" = "📧 Email: {{ .Email }}\r\n"
|
"email" = "📧 Email: {{ .Email }}\r\n"
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
"transmission" = "Truyền tải"
|
"transmission" = "Truyền tải"
|
||||||
"host" = "Máy chủ"
|
"host" = "Máy chủ"
|
||||||
"path" = "Đường dẫn"
|
"path" = "Đường dẫn"
|
||||||
"camouflage" = "camouflage"
|
"camouflage" = "Ngụy trang"
|
||||||
"status" = "Trạng thái"
|
"status" = "Trạng thái"
|
||||||
"enabled" = "Đã kích hoạt"
|
"enabled" = "Đã kích hoạt"
|
||||||
"disabled" = "Đã tắt"
|
"disabled" = "Đã tắt"
|
||||||
|
@ -125,8 +125,8 @@
|
||||||
"modifyInbound" = "Chỉnh sửa điểm vào (Inbound)"
|
"modifyInbound" = "Chỉnh sửa điểm vào (Inbound)"
|
||||||
"deleteInbound" = "Xóa điểm vào (Inbound)"
|
"deleteInbound" = "Xóa điểm vào (Inbound)"
|
||||||
"deleteInboundContent" = "Xác nhận xóa điểm vào? (Inbound)"
|
"deleteInboundContent" = "Xác nhận xóa điểm vào? (Inbound)"
|
||||||
"deleteClient" = "Xóa khách hàng"
|
"deleteClient" = "Xóa người dùng"
|
||||||
"deleteClientContent" = "Bạn có chắc chắn muốn xóa ứng dụng khách không?"
|
"deleteClientContent" = "Bạn có chắc chắn muốn xóa người dùng không?"
|
||||||
"resetTrafficContent" = "Xác nhận đặt lại lưu lượng?"
|
"resetTrafficContent" = "Xác nhận đặt lại lưu lượng?"
|
||||||
"copyLink" = "Sao chép liên kết"
|
"copyLink" = "Sao chép liên kết"
|
||||||
"address" = "Địa chỉ"
|
"address" = "Địa chỉ"
|
||||||
|
@ -145,7 +145,7 @@
|
||||||
"keyPath" = "Đường dẫn khóa riêng tư"
|
"keyPath" = "Đường dẫn khóa riêng tư"
|
||||||
"keyContent" = "Nội dung khóa riêng tư"
|
"keyContent" = "Nội dung khóa riêng tư"
|
||||||
"clickOnQRcode" = "Nhấn vào Mã QR để sao chép"
|
"clickOnQRcode" = "Nhấn vào Mã QR để sao chép"
|
||||||
"client" = "Máy Khách"
|
"client" = "Người dùng"
|
||||||
"export" = "Xuất liên kết"
|
"export" = "Xuất liên kết"
|
||||||
"clone" = "Sao chép"
|
"clone" = "Sao chép"
|
||||||
"cloneInbound" = "Sao chép điểm vào (Inbound)"
|
"cloneInbound" = "Sao chép điểm vào (Inbound)"
|
||||||
|
@ -154,15 +154,15 @@
|
||||||
"resetAllTraffic" = "Đặt lại lưu lượng cho tất cả điểm vào"
|
"resetAllTraffic" = "Đặt lại lưu lượng cho tất cả điểm vào"
|
||||||
"resetAllTrafficTitle" = "Đặt lại lưu lượng cho tất cả điểm vào"
|
"resetAllTrafficTitle" = "Đặt lại lưu lượng cho tất cả điểm vào"
|
||||||
"resetAllTrafficContent" = "Bạn có chắc chắn muốn đặt lại lưu lượng cho tất cả điểm vào không?"
|
"resetAllTrafficContent" = "Bạn có chắc chắn muốn đặt lại lưu lượng cho tất cả điểm vào không?"
|
||||||
"resetInboundClientTraffics" = "Đặt lại lưu lượng cho các client của điểm vào"
|
"resetInboundClientTraffics" = "Đặt lại lưu lượng toàn bộ người dùng của điểm vào"
|
||||||
"resetInboundClientTrafficTitle" = "Đặt lại lưu lượng cho tất cả lưu lượng của client"
|
"resetInboundClientTrafficTitle" = "Đặt lại lưu lượng cho toàn bộ người dùng của điểm vào"
|
||||||
"resetInboundClientTrafficContent" = "Bạn có chắc chắn muốn đặt lại tất cả lưu lượng cho các client của điểm vào này không?"
|
"resetInboundClientTrafficContent" = "Bạn có chắc chắn muốn đặt lại tất cả lưu lượng cho các người dùng của điểm vào này không?"
|
||||||
"resetAllClientTraffics" = "Đặt lại lưu lượng cho tất cả client"
|
"resetAllClientTraffics" = "Đặt lại lưu lượng cho toàn bộ người dùng"
|
||||||
"resetAllClientTrafficTitle" = "Đặt lại lưu lượng cho tất cả client"
|
"resetAllClientTrafficTitle" = "Đặt lại lưu lượng cho toàn bộ người dùng"
|
||||||
"resetAllClientTrafficContent" = "Bạn có chắc chắn muốn đặt lại tất cả lưu lượng cho tất cả client không?"
|
"resetAllClientTrafficContent" = "Bạn có chắc chắn muốn đặt lại tất cả lưu lượng cho toàn bộ người dùng không?"
|
||||||
"delDepletedClients" = "Xóa các client đã cạn kiệt"
|
"delDepletedClients" = "Xóa các người dùng đã cạn kiệt"
|
||||||
"delDepletedClientsTitle" = "Xóa các client đã cạn kiệt"
|
"delDepletedClientsTitle" = "Xóa các người dùng đã cạn kiệt"
|
||||||
"delDepletedClientsContent" = "Bạn có chắc chắn muốn xóa tất cả các client đã cạn kiệt không?"
|
"delDepletedClientsContent" = "Bạn có chắc chắn muốn xóa toàn bộ người dùng đã cạn kiệt không?"
|
||||||
"email" = "Email"
|
"email" = "Email"
|
||||||
"emailDesc" = "Vui lòng cung cấp một địa chỉ email duy nhất."
|
"emailDesc" = "Vui lòng cung cấp một địa chỉ email duy nhất."
|
||||||
"IPLimit" = "Giới hạn IP"
|
"IPLimit" = "Giới hạn IP"
|
||||||
|
@ -174,20 +174,20 @@
|
||||||
"xtlsDesc" = "Xray core cần phiên bản 1.7.5"
|
"xtlsDesc" = "Xray core cần phiên bản 1.7.5"
|
||||||
"realityDesc" = "Xray core cần phiên bản 1.8.0 hoặc cao hơn."
|
"realityDesc" = "Xray core cần phiên bản 1.8.0 hoặc cao hơn."
|
||||||
"telegramDesc" = "Chỉ sử dụng ID trò chuyện (bạn có thể nhận được nó ở đây @userinfobot hoặc sử dụng lệnh '/id' trong bot)"
|
"telegramDesc" = "Chỉ sử dụng ID trò chuyện (bạn có thể nhận được nó ở đây @userinfobot hoặc sử dụng lệnh '/id' trong bot)"
|
||||||
"subscriptionDesc" = "Bạn có thể tìm liên kết đăng ký của mình trong Chi tiết, cũng như bạn có thể sử dụng cùng tên cho nhiều cấu hình khác nhau"
|
"subscriptionDesc" = "Bạn có thể tìm liên kết gói đăng ký của mình trong Chi tiết, cũng như bạn có thể sử dụng cùng tên cho nhiều cấu hình khác nhau"
|
||||||
"info" = "Thông tin"
|
"info" = "Thông tin"
|
||||||
"same" = "Giống nhau"
|
"same" = "Giống nhau"
|
||||||
"inboundData" = "Dữ liệu gửi đến"
|
"inboundData" = "Dữ liệu gửi đến"
|
||||||
"copyToClipboard" = "Sao chép vào bảng nhớ tạm"
|
"copyToClipboard" = "Sao chép vào bảng nhớ tạm"
|
||||||
"import" = "Nhập"
|
"import" = "Nhập"
|
||||||
"importInbound" = "Nhập hàng gửi về"
|
"importInbound" = "Nhập inbound"
|
||||||
|
|
||||||
[pages.client]
|
[pages.client]
|
||||||
"add" = "Thêm Client"
|
"add" = "Thêm người dùng"
|
||||||
"edit" = "Chỉnh sửa Client"
|
"edit" = "Chỉnh sửa người dùng"
|
||||||
"submitAdd" = "Thêm Client"
|
"submitAdd" = "Thêm"
|
||||||
"submitEdit" = "Lưu thay đổi"
|
"submitEdit" = "Lưu thay đổi"
|
||||||
"clientCount" = "Số lượng Client"
|
"clientCount" = "Số lượng người dùng"
|
||||||
"bulk" = "Thêm hàng loạt"
|
"bulk" = "Thêm hàng loạt"
|
||||||
"method" = "Phương pháp"
|
"method" = "Phương pháp"
|
||||||
"first" = "Đầu tiên"
|
"first" = "Đầu tiên"
|
||||||
|
@ -212,11 +212,11 @@
|
||||||
[pages.inbounds.stream.tcp]
|
[pages.inbounds.stream.tcp]
|
||||||
"version" = "Phiên bản"
|
"version" = "Phiên bản"
|
||||||
"method" = "Phương pháp"
|
"method" = "Phương pháp"
|
||||||
"path" = "Con đường"
|
"path" = "Đường dẫn"
|
||||||
"status" = "Trạng thái"
|
"status" = "Trạng thái"
|
||||||
"statusDescription" = "Tình trạng Mô tả"
|
"statusDescription" = "Tình trạng Mô tả"
|
||||||
"requestHeader" = "Tiêu đề yêu cầu"
|
"requestHeader" = "Header yêu cầu"
|
||||||
"responseHeader" = "Tiêu đề phản hồi"
|
"responseHeader" = "Header phản hồi"
|
||||||
|
|
||||||
[pages.inbounds.stream.quic]
|
[pages.inbounds.stream.quic]
|
||||||
"encryption" = "Mã hóa"
|
"encryption" = "Mã hóa"
|
||||||
|
@ -225,30 +225,30 @@
|
||||||
"title" = "Cài đặt"
|
"title" = "Cài đặt"
|
||||||
"save" = "Lưu"
|
"save" = "Lưu"
|
||||||
"infoDesc" = "Mọi thay đổi được thực hiện ở đây cần phải được lưu. Vui lòng khởi động lại bảng điều khiển để áp dụng các thay đổi."
|
"infoDesc" = "Mọi thay đổi được thực hiện ở đây cần phải được lưu. Vui lòng khởi động lại bảng điều khiển để áp dụng các thay đổi."
|
||||||
"restartPanel" = "Khởi động lại Bảng điều khiển"
|
"restartPanel" = "Khởi động lại bảng điều khiển"
|
||||||
"restartPanelDesc" = "Bạn có chắc chắn muốn khởi động lại bảng điều khiển? Nhấn OK để khởi động lại sau 3 giây. Nếu bạn không thể truy cập bảng điều khiển sau khi khởi động lại, vui lòng xem thông tin nhật ký của bảng điều khiển trên máy chủ."
|
"restartPanelDesc" = "Bạn có chắc chắn muốn khởi động lại bảng điều khiển? Nhấn OK để khởi động lại sau 3 giây. Nếu bạn không thể truy cập bảng điều khiển sau khi khởi động lại, vui lòng xem thông tin nhật ký của bảng điều khiển trên máy chủ."
|
||||||
"actions" = "Hành động"
|
"actions" = "Hành động"
|
||||||
"resetDefaultConfig" = "Đặt lại Cấu hình Mặc định"
|
"resetDefaultConfig" = "Đặt lại cấu hình mặc định"
|
||||||
"panelSettings" = "Cài đặt Bảng điều khiển"
|
"panelSettings" = "Bảng điều khiển"
|
||||||
"securitySettings" = "Cài đặt Bảo mật"
|
"securitySettings" = "Bảo mật"
|
||||||
"TGBotSettings" = "Cài đặt Bot Telegram"
|
"TGBotSettings" = "Bot Telegram"
|
||||||
"panelListeningIP" = "IP Nghe của Bảng điều khiển"
|
"panelListeningIP" = "IP Nghe của bảng điều khiển"
|
||||||
"panelListeningIPDesc" = "Mặc định để trống để nghe tất cả các IP."
|
"panelListeningIPDesc" = "Mặc định để trống để nghe tất cả các IP."
|
||||||
"panelListeningDomain" = "Tên miền của nghe Bảng điều khiển"
|
"panelListeningDomain" = "Tên miền của nghe bảng điều khiển"
|
||||||
"panelListeningDomainDesc" = "Mặc định để trống để nghe tất cả các tên miền và IP"
|
"panelListeningDomainDesc" = "Mặc định để trống để nghe tất cả các tên miền và IP"
|
||||||
"panelPort" = "Cổng Bảng điều khiển"
|
"panelPort" = "Cổng bảng điều khiển"
|
||||||
"panelPortDesc" = "Cổng được sử dụng để hiển thị bảng điều khiển này"
|
"panelPortDesc" = "Cổng được sử dụng để kết nối với bảng điều khiển này"
|
||||||
"publicKeyPath" = "Đường dẫn tập tin khóa công khai Chứng chỉ Bảng điều khiển"
|
"publicKeyPath" = "Đường dẫn file chứng chỉ bảng điều khiển"
|
||||||
"publicKeyPathDesc" = "Điền vào đường dẫn tuyệt đối bắt đầu với."
|
"publicKeyPathDesc" = "Điền vào đường dẫn đầy đủ (bắt đầu từ '/')"
|
||||||
"privateKeyPath" = "Đường dẫn tập tin khóa riêng tư Chứng chỉ Bảng điều khiển"
|
"privateKeyPath" = "Đường dẫn file khóa của chứng chỉ bảng điều khiển"
|
||||||
"privateKeyPathDesc" = "Điền vào đường dẫn tuyệt đối bắt đầu với."
|
"privateKeyPathDesc" = "Điền vào đường dẫn đầy đủ (bắt đầu từ '/')"
|
||||||
"panelUrlPath" = "Đường dẫn gốc URL Bảng điều khiển"
|
"panelUrlPath" = "Đường dẫn gốc URL bảng điều khiển"
|
||||||
"panelUrlPathDesc" = "Phải bắt đầu bằng '/' và kết thúc bằng."
|
"panelUrlPathDesc" = "Phải bắt đầu và kết thúc bằng '/'"
|
||||||
"pageSize" = "Kích thước phân trang"
|
"pageSize" = "Kích thước phân trang"
|
||||||
"pageSizeDesc" = "Xác định kích thước trang cho bảng gửi đến. Đặt 0 để tắt"
|
"pageSizeDesc" = "Xác định kích thước trang cho bảng gửi đến. Đặt 0 để tắt"
|
||||||
"remarkModel" = "Ghi chú mô hình và ký tự phân tách"
|
"remarkModel" = "Ghi chú mô hình và ký tự phân tách"
|
||||||
"datepicker" = "bảng chọn ngày"
|
"datepicker" = "Kiểu lịch"
|
||||||
"datepickerDescription" = "Loại lịch chọn chỉ định ngày hết hạn"
|
"datepickerDescription" = "Tác vụ chạy theo lịch trình sẽ chạy theo kiểu lịch này."
|
||||||
"sampleRemark" = "Nhận xét mẫu"
|
"sampleRemark" = "Nhận xét mẫu"
|
||||||
"oldUsername" = "Tên người dùng hiện tại"
|
"oldUsername" = "Tên người dùng hiện tại"
|
||||||
"currentPassword" = "Mật khẩu hiện tại"
|
"currentPassword" = "Mật khẩu hiện tại"
|
||||||
|
@ -268,7 +268,7 @@
|
||||||
"tgNotifyBackupDesc" = "Bao gồm tệp sao lưu cơ sở dữ liệu với thông báo báo cáo."
|
"tgNotifyBackupDesc" = "Bao gồm tệp sao lưu cơ sở dữ liệu với thông báo báo cáo."
|
||||||
"tgNotifyLogin" = "Thông báo Đăng nhập"
|
"tgNotifyLogin" = "Thông báo Đăng nhập"
|
||||||
"tgNotifyLoginDesc" = "Hiển thị tên người dùng, địa chỉ IP và thời gian khi ai đó cố gắng đăng nhập vào bảng điều khiển của bạn."
|
"tgNotifyLoginDesc" = "Hiển thị tên người dùng, địa chỉ IP và thời gian khi ai đó cố gắng đăng nhập vào bảng điều khiển của bạn."
|
||||||
"sessionMaxAge" = "Tuổi tối đa của phiên"
|
"sessionMaxAge" = "Thời gian tối đa của phiên"
|
||||||
"sessionMaxAgeDesc" = "Thời gian của phiên đăng nhập (đơn vị: phút)"
|
"sessionMaxAgeDesc" = "Thời gian của phiên đăng nhập (đơn vị: phút)"
|
||||||
"expireTimeDiff" = "Ngưỡng hết hạn cho thông báo"
|
"expireTimeDiff" = "Ngưỡng hết hạn cho thông báo"
|
||||||
"expireTimeDiffDesc" = "Nhận thông báo về việc hết hạn tài khoản trước ngưỡng này (đơn vị: ngày)"
|
"expireTimeDiffDesc" = "Nhận thông báo về việc hết hạn tài khoản trước ngưỡng này (đơn vị: ngày)"
|
||||||
|
@ -278,29 +278,29 @@
|
||||||
"tgNotifyCpuDesc" = "Nhận thông báo nếu tỷ lệ sử dụng CPU vượt quá ngưỡng này (đơn vị: %)"
|
"tgNotifyCpuDesc" = "Nhận thông báo nếu tỷ lệ sử dụng CPU vượt quá ngưỡng này (đơn vị: %)"
|
||||||
"timeZone" = "Múi giờ"
|
"timeZone" = "Múi giờ"
|
||||||
"timeZoneDesc" = "Các tác vụ được lên lịch chạy theo thời gian trong múi giờ này."
|
"timeZoneDesc" = "Các tác vụ được lên lịch chạy theo thời gian trong múi giờ này."
|
||||||
"subSettings" = "Đăng ký"
|
"subSettings" = "Gói đăng ký"
|
||||||
"subEnable" = "Bật dịch vụ"
|
"subEnable" = "Bật dịch vụ"
|
||||||
"subEnableDesc" = "Tính năng đăng ký với cấu hình riêng"
|
"subEnableDesc" = "Tính năng gói đăng ký với cấu hình riêng"
|
||||||
"subListen" = "Listening IP"
|
"subListen" = "Listening IP"
|
||||||
"subListenDesc" = "Mặc định để trống để nghe tất cả các IP"
|
"subListenDesc" = "Mặc định để trống để nghe tất cả các IP"
|
||||||
"subPort" = "Cổng Đăng ký"
|
"subPort" = "Cổng gói đăng ký"
|
||||||
"subPortDesc" = "Số cổng dịch vụ đăng ký phải chưa được sử dụng trên máy chủ"
|
"subPortDesc" = "Số cổng dịch vụ đăng ký phải chưa được sử dụng trên máy chủ"
|
||||||
"subCertPath" = "Đường dẫn tập tin khóa công khai Chứng chỉ Đăng ký"
|
"subCertPath" = "Đường dẫn file chứng chỉ gói đăng ký"
|
||||||
"subCertPathDesc" = "Điền vào đường dẫn tuyệt đối bắt đầu với '/'"
|
"subCertPathDesc" = "Điền vào đường dẫn đầy đủ (bắt đầu với '/')"
|
||||||
"subKeyPath" = "Đường dẫn tập tin khóa riêng tư Chứng chỉ Đăng ký"
|
"subKeyPath" = "Đường dẫn file khóa của chứng chỉ gói đăng ký"
|
||||||
"subKeyPathDesc" = "Điền vào đường dẫn tuyệt đối bắt đầu với '/'"
|
"subKeyPathDesc" = "Điền vào đường dẫn đầy đủ (bắt đầu với '/')"
|
||||||
"subPath" = "Đường dẫn gốc URL Đăng ký"
|
"subPath" = "Đường dẫn gốc URL gói đăng ký"
|
||||||
"subPathDesc" = "Phải bắt đầu bằng '/' và kết thúc bằng '/'"
|
"subPathDesc" = "Phải bắt đầu và kết thúc bằng '/'"
|
||||||
"subDomain" = "Tên miền con"
|
"subDomain" = "Tên miền con"
|
||||||
"subDomainDesc" = "Mặc định để trống để nghe tất cả các tên miền và IP"
|
"subDomainDesc" = "Mặc định để trống để nghe tất cả các tên miền và IP"
|
||||||
"subUpdates" = "Khoảng thời gian cập nhật đăng ký"
|
"subUpdates" = "Khoảng thời gian cập nhật gói đăng ký"
|
||||||
"subUpdatesDesc" = "Số giờ giữa các cập nhật trong ứng dụng khách"
|
"subUpdatesDesc" = "Số giờ giữa các cập nhật trong ứng dụng khách"
|
||||||
"subEncrypt" = "Mã hóa cấu hình"
|
"subEncrypt" = "Mã hóa cấu hình"
|
||||||
"subEncryptDesc" = "Mã hóa các cấu hình được trả về trong đăng ký"
|
"subEncryptDesc" = "Mã hóa các cấu hình được trả về trong gói đăng ký"
|
||||||
"subShowInfo" = "Hiển thị thông tin sử dụng"
|
"subShowInfo" = "Hiển thị thông tin sử dụng"
|
||||||
"subShowInfoDesc" = "Hiển thị lưu lượng truy cập còn lại và ngày sau tên cấu hình"
|
"subShowInfoDesc" = "Hiển thị lưu lượng truy cập còn lại và ngày sau tên cấu hình"
|
||||||
"subURI" = "URI proxy ngược"
|
"subURI" = "URI proxy trung gian"
|
||||||
"subURIDesc" = "Thay đổi URI cơ sở của URL đăng ký để sử dụng ở phía sau proxy"
|
"subURIDesc" = "Thay đổi URI cơ sở của URL gói đăng ký để sử dụng cho proxy trung gian"
|
||||||
|
|
||||||
[pages.xray]
|
[pages.xray]
|
||||||
"title" = "Cài đặt Xray"
|
"title" = "Cài đặt Xray"
|
||||||
|
@ -422,7 +422,7 @@
|
||||||
"intercon" = "Kết nối"
|
"intercon" = "Kết nối"
|
||||||
|
|
||||||
[pages.xray.wireguard]
|
[pages.xray.wireguard]
|
||||||
"secretKey" = "Chìa khoá bí mật"
|
"secretKey" = "Khoá bí mật"
|
||||||
"publicKey" = "Khóa công khai"
|
"publicKey" = "Khóa công khai"
|
||||||
"allowedIPs" = "IP được phép"
|
"allowedIPs" = "IP được phép"
|
||||||
"endpoint" = "Điểm cuối"
|
"endpoint" = "Điểm cuối"
|
||||||
|
@ -434,8 +434,8 @@
|
||||||
"secret" = "Mã thông báo bí mật"
|
"secret" = "Mã thông báo bí mật"
|
||||||
"loginSecurity" = "Bảo mật đăng nhập"
|
"loginSecurity" = "Bảo mật đăng nhập"
|
||||||
"loginSecurityDesc" = "Bật bước bảo mật đăng nhập bổ sung cho người dùng"
|
"loginSecurityDesc" = "Bật bước bảo mật đăng nhập bổ sung cho người dùng"
|
||||||
"secretToken" = "Mã thông báo bí mật"
|
"secretToken" = "Mã bí mật"
|
||||||
"secretTokenDesc" = "Vui lòng sao chép và lưu trữ mã thông báo này một cách an toàn ở nơi an toàn. Mã thông báo này cần thiết để đăng nhập và không thể phục hồi từ công cụ lệnh x-ui."
|
"secretTokenDesc" = "Vui lòng sao chép và lưu trữ mã này một cách an toàn ở nơi an toàn. Mã này cần thiết để đăng nhập và không thể phục hồi từ công cụ lệnh x-ui."
|
||||||
|
|
||||||
[pages.settings.toasts]
|
[pages.settings.toasts]
|
||||||
"modifySettings" = "Chỉnh sửa cài đặt "
|
"modifySettings" = "Chỉnh sửa cài đặt "
|
||||||
|
@ -460,7 +460,7 @@
|
||||||
"hours" = "Giờ"
|
"hours" = "Giờ"
|
||||||
"unknown" = "Không rõ"
|
"unknown" = "Không rõ"
|
||||||
"inbounds" = "Vào"
|
"inbounds" = "Vào"
|
||||||
"clients" = "Các khách hàng"
|
"clients" = "Các người dùng"
|
||||||
"offline" = "🔴 Ngoại tuyến"
|
"offline" = "🔴 Ngoại tuyến"
|
||||||
"online" = "🟢 Trực tuyến"
|
"online" = "🟢 Trực tuyến"
|
||||||
|
|
||||||
|
|
|
@ -503,7 +503,7 @@
|
||||||
"port" = "🔌 端口:{{ .Port }}\r\n"
|
"port" = "🔌 端口:{{ .Port }}\r\n"
|
||||||
"expire" = "📅 过期日期:{{ .Time }}\r\n"
|
"expire" = "📅 过期日期:{{ .Time }}\r\n"
|
||||||
"expireIn" = "📅 剩余时间:{{ .Time }}\r\n"
|
"expireIn" = "📅 剩余时间:{{ .Time }}\r\n"
|
||||||
"active" = "💡 激活:✅\r\n"
|
"active" = "💡 激活:{{ .Enable }}\r\n"
|
||||||
"enabled" = "🚨 已启用:{{ .Enable }}\r\n"
|
"enabled" = "🚨 已启用:{{ .Enable }}\r\n"
|
||||||
"online" = "🌐 连接状态:{{ .Status }}\r\n"
|
"online" = "🌐 连接状态:{{ .Status }}\r\n"
|
||||||
"email" = "📧 邮箱:{{ .Email }}\r\n"
|
"email" = "📧 邮箱:{{ .Email }}\r\n"
|
||||||
|
|
6
x-ui.sh
6
x-ui.sh
|
@ -991,6 +991,12 @@ install_iplimit() {
|
||||||
echo -e "${red}Unsupported operating system. Please check the script and install the necessary packages manually.${plain}\n"
|
echo -e "${red}Unsupported operating system. Please check the script and install the necessary packages manually.${plain}\n"
|
||||||
exit 1 ;;
|
exit 1 ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
if ! command -v fail2ban-client &>/dev/null; then
|
||||||
|
echo -e "${red}Fail2ban installation failed.${plain}\n"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
echo -e "${green}Fail2ban installed successfully!${plain}\n"
|
echo -e "${green}Fail2ban installed successfully!${plain}\n"
|
||||||
else
|
else
|
||||||
echo -e "${yellow}Fail2ban is already installed.${plain}\n"
|
echo -e "${yellow}Fail2ban is already installed.${plain}\n"
|
||||||
|
|
Loading…
Reference in a new issue