This commit is contained in:
Alireza Ahmadi
2023-03-17 12:37:49 +01:00
parent 48554ab497
commit 6b8ca0c321
6 changed files with 115 additions and 36 deletions

View File

@@ -11,6 +11,7 @@ xray panel supporting multi-protocol, **Multi-lang (English,Farsi,Chinese)**
| Features | Enable? |
| ------------- |:-------------:|
| Multi-lang | :heavy_check_mark: |
| Dark/Light Theme | :heavy_check_mark: |
| Search in deep | :heavy_check_mark: |
| Inbound Multi User | :heavy_check_mark: |
| Multi User Traffic & Expiration time | :heavy_check_mark: |
@@ -24,6 +25,7 @@ xray panel supporting multi-protocol, **Multi-lang (English,Farsi,Chinese)**
- System Status Monitoring
- Search within all inbounds and clients
- Support Dark/Light theme UI
- Support multi-user multi-protocol, web page visualization operation
- Supported protocols: vmess, vless, trojan, shadowsocks, dokodemo-door, socks, http
- Support for configuring more transport configurations
@@ -36,6 +38,7 @@ xray panel supporting multi-protocol, **Multi-lang (English,Farsi,Chinese)**
# Screenshot from Inbouds page
![inbounds](./media/inbounds.png)
![Dark inbounds](./media/inbounds-dark.png)
# Install & Upgrade
@@ -65,8 +68,6 @@ systemctl restart x-ui
## Install using docker
> This docker tutorial and docker image are provided by [alireza0](https://github.com/alireza0)
1. install docker
```shell
@@ -77,7 +78,9 @@ curl -fsSL https://get.docker.com | sh
```shell
mkdir x-ui && cd x-ui
docker run -itd --network=host \
docker run -itd \
-p 54321:54321 -p 443:443 -p 80:80 \
-e XRAY_VMESS_AEAD_FORCED=false \
-v $PWD/db/:/etc/x-ui/ \
-v $PWD/cert/:/root/cert/ \
--name x-ui --restart=unless-stopped \
@@ -113,8 +116,8 @@ certbot certonly --standalone --register-unsafely-without-email --non-interactiv
X-UI supports daily traffic notification, panel login reminder and other functions through the Tg robot. To use the Tg robot, you need to apply for the specific application tutorial. You can refer to the [blog](https://coderfan.net/how-to-use-telegram-bot-to-alarm-you-when-someone-login-into-your-vps.html)
Set the robot-related parameters in the panel background, including:
- Tg Robot Token
- Tg Robot ChatId
- Tg robot Token
- Tg robot ChatId
- Tg robot cycle runtime, in crontab syntax
- Tg robot Expiration threshold
- Tg robot Traffic threshold
@@ -135,8 +138,9 @@ Reference syntax:
- CPU threshold notification
- Threshold for Expiration time and Traffic to report in advance
- Support client report if client's telegram username is added to the end of `email` like 'test123@telegram_username'
- Support telegram traffic report searched with UID (VMESS/VLESS) or Password (TROJAN) - anonymously
- Menu based bot
- Search client by email
- Search client by email ( only admin )
- Check all inbounds
- Check server status
- Check Exhausted users

View File

@@ -1 +1 @@
0.4.0
0.4.1

BIN
media/inbounds-dark.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 115 KiB

After

Width:  |  Height:  |  Size: 107 KiB

View File

@@ -92,6 +92,12 @@ const UTLS_FINGERPRINT = {
UTLS_RANDOMIZED: "randomized",
};
const ALPN_OPTION = {
H2: "h2",
HTTP1: "http/1.1",
BOTH: "h2,http/1.1",
};
Object.freeze(Protocols);
Object.freeze(VmessMethods);
Object.freeze(SSMethods);
@@ -101,6 +107,7 @@ Object.freeze(XTLS_FLOW_CONTROL);
Object.freeze(TLS_FLOW_CONTROL);
Object.freeze(TLS_VERSION_OPTION);
Object.freeze(TLS_CIPHER_OPTION);
Object.freeze(ALPN_OPTION);
class XrayCommonClass {
@@ -471,7 +478,8 @@ class TlsStreamSettings extends XrayCommonClass {
maxVersion = TLS_VERSION_OPTION.TLS13,
cipherSuites = '',
certificates=[new TlsStreamSettings.Cert()],
alpn=["h2", "http/1.1"]) {
alpn=[''],
settings=[new TlsStreamSettings.Settings()]) {
super();
this.server = serverName;
this.minVersion = minVersion;
@@ -479,6 +487,7 @@ class TlsStreamSettings extends XrayCommonClass {
this.cipherSuites = cipherSuites;
this.certs = certificates;
this.alpn = alpn;
this.settings = settings;
}
addCert(cert) {
@@ -491,17 +500,23 @@ class TlsStreamSettings extends XrayCommonClass {
static fromJson(json={}) {
let certs;
let settings;
if (!ObjectUtil.isEmpty(json.certificates)) {
certs = json.certificates.map(cert => TlsStreamSettings.Cert.fromJson(cert));
}
if (!ObjectUtil.isEmpty(json.settings)) {
let values = json.settings[0];
settings = [new TlsStreamSettings.Settings(values.allowInsecure , values.fingerprint, values.serverName)];
}
return new TlsStreamSettings(
json.serverName,
json.minVersion,
json.maxVersion,
json.cipherSuites,
certs,
json.alpn
json.alpn,
settings,
);
}
@@ -512,7 +527,8 @@ class TlsStreamSettings extends XrayCommonClass {
maxVersion: this.maxVersion,
cipherSuites: this.cipherSuites,
certificates: TlsStreamSettings.toJsonArray(this.certs),
alpn: this.alpn
alpn: this.alpn,
settings: TlsStreamSettings.toJsonArray(this.settings),
};
}
}
@@ -558,6 +574,29 @@ TlsStreamSettings.Cert = class extends XrayCommonClass {
}
};
TlsStreamSettings.Settings = class extends XrayCommonClass {
constructor(insecure = false, fingerprint = '', serverName = '') {
super();
this.inSecure = insecure;
this.fingerprint = fingerprint;
this.serverName = serverName;
}
static fromJson(json = {}) {
return new TlsStreamSettings.Settings(
json.allowInsecure,
json.fingerprint,
json.servername,
);
}
toJson() {
return {
allowInsecure: this.inSecure,
fingerprint: this.fingerprint,
serverName: this.serverName,
};
}
};
class StreamSettings extends XrayCommonClass {
constructor(network='tcp',
security='none',
@@ -920,7 +959,7 @@ class Inbound extends XrayCommonClass {
}
}
//this is used for xtls-rprx-vison
//this is used for xtls-rprx-vision
canEnableTlsFlow() {
if ((this.stream.security === 'tls') && (this.network === "tcp")) {
switch (this.protocol) {
@@ -1053,6 +1092,7 @@ class Inbound extends XrayCommonClass {
const type = this.stream.network;
const params = new Map();
params.set("type", this.stream.network);
params.set("security", this.stream.security);
if (this.xtls) {
params.set("security", "xtls");
address = this.stream.tls.server;
@@ -1107,13 +1147,29 @@ class Inbound extends XrayCommonClass {
if (this.stream.security === 'tls') {
if (!ObjectUtil.isEmpty(this.stream.tls.server)) {
address = this.stream.tls.server;
params.set("sni", address);
}
params.set("flow", this.settings.vlesses[clientIndex].flow);
params.set("fp" , this.stream.tls.settings[0]['fingerprint']);
params.set("alpn", this.stream.tls.alpn[0]);
if (this.stream.tls.settings[0]['serverName'] !== ''){
params.set("sni", this.stream.tls.settings[0]['serverName']);
}
else{
params.set("sni", address);
}
if (type === "tcp" && this.settings.vlesses[clientIndex].flow.length > 0) {
params.set("flow", this.settings.vlesses[clientIndex].flow);
}
}
}
if (this.xtls) {
params.set("flow", this.settings.vlesses[clientIndex].flow);
if (this.stream.security === 'xtls') {
if (!ObjectUtil.isEmpty(this.stream.tls.server)) {
address = this.stream.tls.server;
if (type === "tcp") {
params.set("flow", this.settings.vlesses[clientIndex].flow);
}
}
}
}
const link = `vless://${uuid}@${address}:${port}`;
@@ -1144,12 +1200,6 @@ class Inbound extends XrayCommonClass {
const port = this.port;
const type = this.stream.network;
const params = new Map();
params.set("type", this.stream.network);
if (this.xtls) {
params.set("security", "xtls");
} else {
params.set("security", this.stream.security);
}
switch (type) {
case "tcp":
const tcp = this.stream.tcp;
@@ -1198,13 +1248,26 @@ class Inbound extends XrayCommonClass {
if (this.stream.security === 'tls') {
if (!ObjectUtil.isEmpty(this.stream.tls.server)) {
address = this.stream.tls.server;
params.set("sni", address);
}
params.set("flow", this.settings.trojans[clientIndex].flow);
params.set("fp" , this.stream.tls.settings[0]['fingerprint']);
params.set("alpn", this.stream.tls.alpn[0]);
if (this.stream.tls.settings[0]['serverName'] !== ''){
params.set("sni", this.stream.tls.settings[0]['serverName']);
}
else{
params.set("sni", address);
}
}
}
if (this.xtls) {
params.set("flow", this.settings.trojans[clientIndex].flow);
if (this.stream.security === 'xtls') {
if (!ObjectUtil.isEmpty(this.stream.tls.server)) {
address = this.stream.tls.server;
if (type === "tcp" && this.settings.trojans[clientIndex].flow.length > 0) {
params.set("flow", this.settings.trojans[clientIndex].flow);
}
}
}
const link = `trojan://${settings.trojans[clientIndex].password}@${address}:${this.port}#${encodeURIComponent(remark)}`;
const url = new URL(link);
for (const [key, value] of params) {

View File

@@ -12,6 +12,15 @@
<!-- tls settings -->
<a-form v-if="inbound.tls || inbound.xtls" layout="inline">
<a-form-item label="SNI" placeholder="Server Name Indication" v-if="inbound.tls">
<a-input v-model.trim="inbound.stream.tls.settings[0].serverName"></a-input>
</a-form-item>
<a-form-item label="CipherSuites">
<a-select v-model="inbound.stream.tls.cipherSuites" style="width: 300px">
<a-select-option value="">auto</a-select-option>
<a-select-option v-for="key in TLS_CIPHER_OPTION" :value="key">[[ key ]]</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="MinVersion">
<a-select v-model="inbound.stream.tls.minVersion" style="width: 60px" :dropdown-class-name="siderDrawer.isDarkTheme ? 'ant-card-dark' : ''">
<a-select-option v-for="key in TLS_VERSION_OPTION" :value="key">[[ key ]]</a-select-option>
@@ -22,17 +31,20 @@
<a-select-option v-for="key in TLS_VERSION_OPTION" :value="key">[[ key ]]</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="CipherSuites">
<a-select v-model="inbound.stream.tls.cipherSuites" style="width: 300px" :dropdown-class-name="siderDrawer.isDarkTheme ? 'ant-card-dark' : ''">
<a-select-option value="">auto</a-select-option>
<a-select-option v-for="key in TLS_CIPHER_OPTION" :value="key">[[ key ]]</a-select-option>
<a-form-item label="uTLS" v-if="inbound.tls" >
<a-select v-model="inbound.stream.tls.settings[0].fingerprint" style="width: 135px">
<a-select-option value=''>None</a-select-option>
<a-select-option v-for="key in UTLS_FINGERPRINT" :value="key">[[ key ]]</a-select-option>
</a-select>
</a-form-item>
<a-form-item label='{{ i18n "domainName" }}'>
<a-input v-model.trim="inbound.stream.tls.server"></a-input>
</a-form-item>
<a-form-item label="alpn" placeholder="http/1.1,h2">
<a-input v-model.trim="inbound.stream.tls.alpn"></a-input>
<a-form-item label="Alpn" v-if="inbound.tls">
<a-select v-model="inbound.stream.tls.alpn[0]" style="width:200px">
<a-select-option value=''>auto</a-select-option>
<a-select-option v-for="key in ALPN_OPTION" :value="key">[[ key ]]</a-select-option>
</a-select>
</a-form-item>
<a-form-item label='{{ i18n "certificate" }}'>
<a-radio-group v-model="inbound.stream.tls.certs[0].useFile" button-style="solid">
@@ -42,18 +54,18 @@
</a-form-item>
<template v-if="inbound.stream.tls.certs[0].useFile">
<a-form-item label='{{ i18n "pages.inbounds.publicKeyPath" }}'>
<a-input v-model.trim="inbound.stream.tls.certs[0].certFile"></a-input>
<a-input v-model.trim="inbound.stream.tls.certs[0].certFile" style="width:300px;"></a-input>
</a-form-item>
<a-form-item label='{{ i18n "pages.inbounds.keyPath" }}'>
<a-input v-model.trim="inbound.stream.tls.certs[0].keyFile"></a-input>
<a-input v-model.trim="inbound.stream.tls.certs[0].keyFile" style="width:300px;"></a-input>
</a-form-item>
</template>
<template v-else>
<a-form-item label='{{ i18n "pages.inbounds.publicKeyContent" }}'>
<a-input type="textarea" :rows="2" v-model="inbound.stream.tls.certs[0].cert"></a-input>
<a-input type="textarea" :rows="3" style="width:300px;" v-model="inbound.stream.tls.certs[0].cert"></a-input>
</a-form-item>
<a-form-item label='{{ i18n "pages.inbounds.keyContent" }}'>
<a-input type="textarea" :rows="2" v-model="inbound.stream.tls.certs[0].key"></a-input>
<a-input type="textarea" :rows="3" style="width:300px;" v-model="inbound.stream.tls.certs[0].key"></a-input>
</a-form-item>
</template>
</a-form>