diff --git a/plugins/xui/conf/mt.toml b/plugins/xui/conf/mt.toml
new file mode 100644
index 000000000..495d45a3e
--- /dev/null
+++ b/plugins/xui/conf/mt.toml
@@ -0,0 +1,23 @@
+debug = false
+
+secret = "{$SECRET}"
+bind-to = "0.0.0.0:{$PORT}"
+
+concurrency = 256
+prefer-ip = "prefer-ipv4"
+domain-fronting-port = 443
+tolerate-time-skewness = "10s"
+
+[network]
+doh-ip = "9.9.9.9"
+
+[network.timeout]
+tcp = "5s"
+http = "10s"
+idle = "1m"
+
+[defense.anti-replay]
+enabled = true
+max-size = "1mib"
+error-rate = 0.001
+
diff --git a/plugins/xui/ico.png b/plugins/xui/ico.png
new file mode 100644
index 000000000..b7f2362c5
Binary files /dev/null and b/plugins/xui/ico.png differ
diff --git a/plugins/xui/index.html b/plugins/xui/index.html
new file mode 100755
index 000000000..9d1fe8f8a
--- /dev/null
+++ b/plugins/xui/index.html
@@ -0,0 +1,23 @@
+
+
\ No newline at end of file
diff --git a/plugins/xui/index.py b/plugins/xui/index.py
new file mode 100755
index 000000000..15e476d70
--- /dev/null
+++ b/plugins/xui/index.py
@@ -0,0 +1,257 @@
+# coding:utf-8
+
+import sys
+import io
+import os
+import time
+import re
+
+web_dir = os.getcwd() + "/web"
+if os.path.exists(web_dir):
+ sys.path.append(web_dir)
+ os.chdir(web_dir)
+
+import core.mw as mw
+
+app_debug = False
+if mw.isAppleSystem():
+ app_debug = True
+
+
+def getPluginName():
+ return 'xui'
+
+
+def getPluginDir():
+ return mw.getPluginDir() + '/' + getPluginName()
+
+
+def getServerDir():
+ return mw.getServerDir() + '/' + getPluginName()
+
+
+def getServiceTpl():
+ path = getPluginDir() + "/init.d/" + getPluginName() + ".service.tpl"
+ return path
+
+
+def getConfEnvTpl():
+ path = getPluginDir() + "/conf/mt.toml"
+ return path
+
+
+def getConfEnv():
+ path = getServerDir() + "/mt.toml"
+ return path
+
+
+def getArgs():
+ args = sys.argv[2:]
+ tmp = {}
+ args_len = len(args)
+
+ if args_len == 1:
+ t = args[0].strip('{').strip('}')
+ t = t.split(':')
+ tmp[t[0]] = t[1]
+ elif args_len > 1:
+ for i in range(len(args)):
+ t = args[i].split(':')
+ tmp[t[0]] = t[1]
+
+ return tmp
+
+def status():
+ cmd = "ps -ef|grep mtproxy| grep mtg |grep -v grep | grep -v python | awk '{print $2}'"
+ data = mw.execShell(cmd)
+ if data[0] == '':
+ return 'stop'
+ return 'start'
+
+
+def getServiceFile():
+ systemDir = mw.systemdCfgDir()
+ return systemDir + '/mtproxy.service'
+
+
+def getMtproxyPort():
+ return '8349'
+
+
+def __release_port(port):
+ from collections import namedtuple
+ try:
+ from utils.firewall import Firewall as MwFirewall
+ MwFirewall.instance().addAcceptPort(port, 'mtproxy', 'port')
+ return port
+ except Exception as e:
+ return "Release failed {}".format(e)
+
+def __delete_port(port):
+ from collections import namedtuple
+ try:
+ from utils.firewall import Firewall as MwFirewall
+ MwFirewall.instance().delAcceptPortCmd(port, 'tcp')
+ return port
+ except Exception as e:
+ return "Delete failed {}".format(e)
+
+def openPort():
+ port = getMtproxyPort()
+ for i in [port]:
+ __release_port(i)
+ return True
+
+def delPort():
+ port = getMtproxyPort()
+ for i in [port]:
+ __delete_port(i)
+ return True
+
+
+def initDreplace():
+
+ envTpl = getConfEnvTpl()
+ dstEnv = getConfEnv()
+ cmd = getServerDir() + '/mtg/mtg generate-secret `head -c 16 /dev/urandom | xxd -ps`'
+ secret = mw.execShell(cmd)
+ if not os.path.exists(dstEnv):
+ env_content = mw.readFile(envTpl)
+ env_content = env_content.replace('{$PORT}', getMtproxyPort())
+ env_content = env_content.replace('{$SECRET}', secret[0].strip())
+ mw.writeFile(dstEnv, env_content)
+ openPort()
+
+ # systemd
+ systemDir = mw.systemdCfgDir()
+ systemService = systemDir + '/mtproxy.service'
+ systemServiceTpl = getServiceTpl()
+ if os.path.exists(systemDir) and not os.path.exists(systemService):
+ service_path = mw.getServerDir()
+ se_content = mw.readFile(systemServiceTpl)
+ se_content = se_content.replace('{$SERVER_PATH}', service_path)
+ mw.writeFile(systemService, se_content)
+ mw.execShell('systemctl daemon-reload')
+
+ return 'ok'
+
+
+def mtOp(method):
+ file = initDreplace()
+
+ if not mw.isAppleSystem():
+ mw.execShell('systemctl daemon-reload')
+ data = mw.execShell('systemctl ' + method + ' mtproxy')
+ if data[1] == '':
+ return 'ok'
+ return data[1]
+
+ return 'fail'
+
+
+def start():
+ return mtOp('start')
+
+
+def stop():
+ return mtOp('stop')
+
+
+def restart():
+ return mtOp('restart')
+
+
+def reload():
+ return redisOp('reload')
+
+
+def initdStatus():
+ if mw.isAppleSystem():
+ return "Apple Computer does not support"
+
+ shell_cmd = 'systemctl status mtproxy | grep loaded | grep "enabled;"'
+ data = mw.execShell(shell_cmd)
+ if data[0] == '':
+ return 'fail'
+ return 'ok'
+
+def initdInstall():
+ if mw.isAppleSystem():
+ return "Apple Computer does not support"
+ mw.execShell('systemctl enable mtproxy')
+ return 'ok'
+
+
+def initdUinstall():
+ if mw.isAppleSystem():
+ return "Apple Computer does not support"
+ mw.execShell('systemctl disable mtproxy')
+ return 'ok'
+
+def getMtproxyUrl():
+ conf = getConfEnv()
+ content = mw.readFile(conf)
+
+
+ rep = r'bind-to\s*=\s*(.*)'
+ tmp = re.search(rep, content)
+ bind_to = tmp.groups()[0].strip()
+ bind_to = bind_to.strip('"')
+
+ rep = r'secret\s*=\s*(.*)'
+ tmp = re.search(rep, content)
+ secret = tmp.groups()[0].strip()
+ secret = secret.strip('"')
+
+ info = bind_to.split(":")
+
+ ip = mw.getLocalIp()
+
+ url = 'tg://proxy?server={0}&port={1}&secret={2}'.format(ip, info[1], secret)
+ return mw.returnJson(True, 'ok', url)
+
+def installPreInspection():
+ sys = mw.execShell("cat /etc/*-release | grep PRETTY_NAME |awk -F = '{print $2}' | awk -F '\"' '{print $2}'| awk '{print $1}'")
+
+ if sys[1] != '':
+ return '不支持该系统'
+
+ sys_id = mw.execShell("cat /etc/*-release | grep VERSION_ID | awk -F = '{print $2}' | awk -F '\"' '{print $2}'")
+
+ sysName = sys[0].strip().lower()
+ sysId = sys_id[0].strip()
+
+ if sysName in ('opensuse'):
+ return '不支持该系统'
+
+ return 'ok'
+
+
+if __name__ == "__main__":
+ func = sys.argv[1]
+ if func == 'status':
+ print(status())
+ elif func == 'start':
+ print(start())
+ elif func == 'stop':
+ print(stop())
+ elif func == 'restart':
+ print(restart())
+ elif func == 'reload':
+ print(reload())
+ elif func == 'initd_status':
+ print(initdStatus())
+ elif func == 'initd_install':
+ print(initdInstall())
+ elif func == 'initd_uninstall':
+ print(initdUinstall())
+ elif func == 'install_pre_inspection':
+ print(installPreInspection())
+ elif func == 'conf':
+ print(getServiceFile())
+ elif func == 'conf_env':
+ print(getConfEnv())
+ elif func == 'url':
+ print(getMtproxyUrl())
+ else:
+ print('error')
diff --git a/plugins/xui/info.json b/plugins/xui/info.json
new file mode 100755
index 000000000..4959bfc54
--- /dev/null
+++ b/plugins/xui/info.json
@@ -0,0 +1,19 @@
+{
+ "sort": 7,
+ "ps": "支持多协议多用户的xray面板",
+ "install_pre_inspection":true,
+ "name": "xui",
+ "title": "xui",
+ "shell": "install.sh",
+ "versions":["1.0"],
+ "updates":["1.0"],
+ "tip": "soft",
+ "checks": "server/xui",
+ "path": "server/xui",
+ "display": 1,
+ "author": "FranzKafkaYu",
+ "date": "2024-12-03",
+ "home": "https://github.com/FranzKafkaYu/x-ui",
+ "type": 0,
+ "pid": "5"
+}
\ No newline at end of file
diff --git a/plugins/xui/init.d/xui.service.tpl b/plugins/xui/init.d/xui.service.tpl
new file mode 100644
index 000000000..03ad10760
--- /dev/null
+++ b/plugins/xui/init.d/xui.service.tpl
@@ -0,0 +1,14 @@
+[Unit]
+Description=MTProxy
+After=network.target
+
+[Service]
+Type=simple
+WorkingDirectory={$SERVER_PATH}/mtproxy
+ExecStart={$SERVER_PATH}/mtproxy/mtg/mtg run {$SERVER_PATH}/mtproxy/mt.toml
+RestartSec=3
+Restart=on-failure
+AmbientCapabilities=CAP_NET_BIND_SERVICE
+
+[Install]
+WantedBy=multi-user.target
\ No newline at end of file
diff --git a/plugins/xui/install.sh b/plugins/xui/install.sh
new file mode 100755
index 000000000..e34900719
--- /dev/null
+++ b/plugins/xui/install.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
+export PATH
+
+curPath=`pwd`
+rootPath=$(dirname "$curPath")
+rootPath=$(dirname "$rootPath")
+serverPath=$(dirname "$rootPath")
+
+sysArch=`arch`
+sysName=`uname`
+
+
+# cd /www/server/mdserver-web && python3 plugins/mtproxy/index.py url
+# cd /www/server/mdserver-web/plugins/xui && /bin/bash install.sh install 1.0
+
+
+Install_app()
+{
+ echo '安装完成'
+}
+
+Uninstall_app()
+{
+ echo '卸载完成'
+}
+
+action=$1
+if [ "${1}" == 'install' ];then
+ Install_app $2
+else
+ Uninstall_app $2
+fi
diff --git a/plugins/xui/js/xui.js b/plugins/xui/js/xui.js
new file mode 100644
index 000000000..748e2db60
--- /dev/null
+++ b/plugins/xui/js/xui.js
@@ -0,0 +1,61 @@
+function mtPost(method, version, args,callback){
+ var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
+
+ var req_data = {};
+ req_data['name'] = 'mtproxy';
+ req_data['func'] = method;
+ req_data['version'] = version;
+
+ if (typeof(args) == 'string'){
+ req_data['args'] = JSON.stringify(toArrayObject(args));
+ } else {
+ req_data['args'] = JSON.stringify(args);
+ }
+
+ $.post('/plugins/run', req_data, function(data) {
+ layer.close(loadT);
+ if (!data.status){
+ //错误展示10S
+ layer.msg(data.msg,{icon:0,time:2000,shade: [10, '#000']});
+ return;
+ }
+
+ if(typeof(callback) == 'function'){
+ callback(data);
+ }
+ },'json');
+}
+
+function mtCommonFunc(){
+ var con = '
\
+ \
+
';
+
+ $(".soft-man-con").html(con);
+
+ $('#mtproxy_url').click(function(){
+ mtPost('url', '', {}, function(rdata){
+ var data = $.parseJSON(rdata.data);
+
+ layer.open({
+ title: "mtproxy代理信息",
+ area: ['600px', '180px'],
+ type:1,
+ closeBtn: 1,
+ shadeClose: false,
+ btn:["复制","取消"],
+ content: '',
+ success:function(){
+ copyText(data.data);
+ },
+ yes:function(){
+ copyText(data.data);
+ }
+ });
+ });
+ });
+}
\ No newline at end of file