diff --git a/plugins/nezha/ico.png b/plugins/nezha/ico.png
new file mode 100644
index 000000000..6b5f8a3f2
Binary files /dev/null and b/plugins/nezha/ico.png differ
diff --git a/plugins/nezha/index.html b/plugins/nezha/index.html
new file mode 100755
index 000000000..eaa296235
--- /dev/null
+++ b/plugins/nezha/index.html
@@ -0,0 +1,22 @@
+
+
+
\ No newline at end of file
diff --git a/plugins/nezha/index.py b/plugins/nezha/index.py
new file mode 100755
index 000000000..9bf1763fc
--- /dev/null
+++ b/plugins/nezha/index.py
@@ -0,0 +1,202 @@
+# coding:utf-8
+
+import sys
+import io
+import os
+import time
+import re
+import socket
+import json
+
+from datetime import datetime
+
+sys.path.append(os.getcwd() + "/class/core")
+import mw
+
+app_debug = False
+if mw.isAppleSystem():
+ app_debug = True
+
+
+class App:
+ __setupPath = '/www/server/nezha'
+ __SR = ''
+
+ def __init__(self):
+ self.__setupPath = self.getServerDir()
+
+ self.__SR = '''#!/bin/bash
+ PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
+ export PATH
+ export USER=%s
+ export HOME=%s && ''' % ( self.getRunUser(), self.getHomeDir())
+
+ def getArgs(self):
+ args = sys.argv[3:]
+ 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 __release_port(self, port):
+ from collections import namedtuple
+ try:
+ import firewall_api
+ firewall_api.firewall_api().addAcceptPortArgs(port, 'nezha', 'port')
+ return port
+ except Exception as e:
+ return "Release failed {}".format(e)
+
+ def openPort(self):
+ for i in ["9527", "5555"]:
+ self.__release_port(i)
+ return True
+
+ def getPluginName(self):
+ return 'nezha'
+
+ def getPluginDir(self):
+ return mw.getPluginDir() + '/' + self.getPluginName()
+
+ def getServerDir(self):
+ return mw.getServerDir() + '/' + self.getPluginName()
+
+ def getInitdConfTpl(self):
+ path = self.getPluginDir() + "/init.d/nezha.tpl"
+ return path
+
+ def getHomeDir(self):
+ if mw.isAppleSystem():
+ user = mw.execShell(
+ "who | sed -n '2, 1p' |awk '{print $1}'")[0].strip()
+ return '/Users/' + user
+ else:
+ return '/root'
+
+ def getRunUser(self):
+ if mw.isAppleSystem():
+ user = mw.execShell(
+ "who | sed -n '2, 1p' |awk '{print $1}'")[0].strip()
+ return user
+ else:
+ return 'root'
+
+ def status(self):
+ cmd = "ps -ef|grep " + self.getPluginName() + \
+ " |grep -v grep | grep -v python | awk '{print $2}'"
+ data = mw.execShell(cmd)
+ if data[0] == '':
+ return 'stop'
+ return 'start'
+
+ def contentReplace(self, content):
+
+ service_path = mw.getServerDir()
+ content = content.replace('{$ROOT_PATH}', mw.getRootDir())
+ content = content.replace('{$SERVER_PATH}', service_path)
+ content = content.replace('{$RUN_USER}', self.getRunUser())
+ content = content.replace('{$HOME_DIR}', self.getHomeDir())
+
+ return content
+
+ def initDreplace(self):
+
+ file_tpl = self.getInitdConfTpl()
+ service_path = mw.getServerDir()
+
+ initD_path = self.getServerDir() + '/init.d'
+ if not os.path.exists(initD_path):
+ os.mkdir(initD_path)
+ self.openPort()
+
+ file_bin = initD_path + '/' + self.getPluginName()
+
+ if not os.path.exists(file_bin):
+ content = mw.readFile(file_tpl)
+ content = self.contentReplace(content)
+ mw.writeFile(file_bin, content)
+ mw.execShell('chmod +x ' + file_bin)
+
+ # systemd
+ systemDir = mw.systemdCfgDir()
+ systemService = systemDir + '/nezha.service'
+ systemServiceTpl = self.getPluginDir() + '/init.d/nezha.service.tpl'
+ 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 file_bin
+
+ def imOp(self, method):
+ file = self.initDreplace()
+
+ if not mw.isAppleSystem():
+ cmd = 'systemctl {} {}'.format(method, self.getPluginName())
+ data = mw.execShell(cmd)
+ if data[1] == '':
+ return 'ok'
+ return 'fail'
+
+ data = mw.execShell(self.__SR + file + ' ' + method)
+ if data[1] == '':
+ return 'ok'
+ return data[0]
+
+ def start(self):
+ return self.imOp('start')
+
+ def stop(self):
+ return self.imOp('stop')
+
+ def restart(self):
+ return self.imOp('restart')
+
+ def reload(self):
+ return self.imOp('reload')
+
+ def initd_status(self):
+ cmd = 'systemctl status nezha | grep loaded | grep "enabled;"'
+ data = mw.execShell(cmd)
+ if data[0] == '':
+ return 'fail'
+ return 'ok'
+
+ def initd_install(self):
+ mw.execShell('systemctl enable nezha')
+ return 'ok'
+
+ def initd_uinstall(self):
+ mw.execShell('systemctl disable nezha')
+ return 'ok'
+
+ def conf(self):
+ return self.getServerDir() + '/dashboard/data/config.yaml'
+
+ def run_log(self):
+ ilog = self.getServerDir() + '/logs/imail.log'
+ if not os.path.exists(ilog):
+ return mw.returnJson(False, "请先安装初始化!
默认地址:http://" + mw.getLocalIp() + ":1080")
+
+ return self.getServerDir() + '/logs/imail.log'
+
+
+if __name__ == "__main__":
+ func = sys.argv[1]
+ classApp = App()
+ try:
+ data = eval("classApp." + func + "()")
+ print(data)
+ except Exception as e:
+ print('error:' + str(e))
diff --git a/plugins/nezha/info.json b/plugins/nezha/info.json
new file mode 100755
index 000000000..2a9159425
--- /dev/null
+++ b/plugins/nezha/info.json
@@ -0,0 +1,17 @@
+{
+ "sort": 7,
+ "ps": "哪吒监控面板/改造版",
+ "name": "nezha",
+ "title": "哪吒监控",
+ "shell": "install.sh",
+ "versions":["0.15.2"],
+ "tip": "soft",
+ "checks": "server/nezha",
+ "path": "server/nezha",
+ "display": 1,
+ "author": "midoks",
+ "date": "2023-06-26",
+ "home": "https://github.com/midoks/nezha",
+ "type": 0,
+ "pid": "5"
+}
\ No newline at end of file
diff --git a/plugins/nezha/init.d/nezha-agent.service.tpl b/plugins/nezha/init.d/nezha-agent.service.tpl
new file mode 100644
index 000000000..ee2d5dc00
--- /dev/null
+++ b/plugins/nezha/init.d/nezha-agent.service.tpl
@@ -0,0 +1,30 @@
+[Unit]
+Description=Nezha Agent
+After=syslog.target
+#After=network.target
+#After=nezha-dashboard.service
+
+[Service]
+# Modify these two values and uncomment them if you have
+# repos with lots of files and get an HTTP error 500 because
+# of that
+###
+#LimitMEMLOCK=infinity
+#LimitNOFILE=65535
+Type=simple
+User=root
+Group=root
+WorkingDirectory=/opt/nezha/agent/
+ExecStart=/opt/nezha/agent/nezha-agent -s nz_grpc_host:nz_grpc_port -p nz_client_secret
+Restart=always
+#Environment=DEBUG=true
+
+# Some distributions may not support these hardening directives. If you cannot start the service due
+# to an unknown option, comment out the ones not supported by your version of systemd.
+#ProtectSystem=full
+#PrivateDevices=yes
+#PrivateTmp=yes
+#NoNewPrivileges=true
+
+[Install]
+WantedBy=multi-user.target
\ No newline at end of file
diff --git a/plugins/nezha/init.d/nezha.service.tpl b/plugins/nezha/init.d/nezha.service.tpl
new file mode 100644
index 000000000..02a9af58e
--- /dev/null
+++ b/plugins/nezha/init.d/nezha.service.tpl
@@ -0,0 +1,30 @@
+[Unit]
+Description=Nezha Dashborad
+After=syslog.target
+After=network.target
+After=mariadb.service mysqld.service postgresql.service memcached.service redis.service
+
+[Service]
+# Modify these two values and uncomment them if you have
+# repos with lots of files and get an HTTP error 500 because
+# of that
+###
+#LimitMEMLOCK=infinity
+#LimitNOFILE=65535
+Type=simple
+#User=root
+#Group=root
+WorkingDirectory=/opt/nezha/dashboard/
+ExecStart=/opt/nezha/dashboard/nezha web
+Restart=always
+#Environment=DEBUG=true
+
+# Some distributions may not support these hardening directives. If you cannot start the service due
+# to an unknown option, comment out the ones not supported by your version of systemd.
+ProtectSystem=full
+PrivateDevices=yes
+PrivateTmp=yes
+NoNewPrivileges=true
+
+[Install]
+WantedBy=multi-user.target
\ No newline at end of file
diff --git a/plugins/nezha/install.sh b/plugins/nezha/install.sh
new file mode 100755
index 000000000..04a563fe9
--- /dev/null
+++ b/plugins/nezha/install.sh
@@ -0,0 +1,25 @@
+#!/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")
+
+install_tmp=${rootPath}/tmp/mw_install.pl
+
+action=$1
+type=$2
+
+if [ "${2}" == "" ];then
+ echo '缺少安装脚本...' > $install_tmp
+ exit 0
+fi
+
+if [ ! -d $curPath/versions/$2 ];then
+ echo '缺少安装脚本2...' > $install_tmp
+ exit 0
+fi
+
+sh -x $curPath/versions/$2/install.sh $1
diff --git a/plugins/nezha/js/nezha.js b/plugins/nezha/js/nezha.js
new file mode 100755
index 000000000..8a0862bfc
--- /dev/null
+++ b/plugins/nezha/js/nezha.js
@@ -0,0 +1,95 @@
+var nezha = {
+ plugin_name: 'nezha',
+ init: function () {
+ var _this = this;
+ },
+
+ str2Obj:function(str){
+ var data = {};
+ kv = str.split('&');
+ for(i in kv){
+ v = kv[i].split('=');
+ data[v[0]] = v[1];
+ }
+ return data;
+ },
+
+ send:function(info){
+ var tips = info['tips'];
+ var method = info['method'];
+ var args = info['data'];
+ var callback = info['success'];
+
+ var loadT = layer.msg(tips, { icon: 16, time: 0, shade: 0.3 });
+
+ var data = {};
+ data['name'] = 'nezha';
+ data['func'] = method;
+ data['version'] = $('.plugin_version').attr('version');
+
+ if (typeof(args) == 'string'){
+ data['args'] = JSON.stringify(this.str2Obj(args));
+ } else {
+ data['args'] = JSON.stringify(args);
+ }
+
+ $.post('/plugins/run', data, function(res) {
+ layer.close(loadT);
+ if (!res.status){
+ layer.msg(res.msg,{icon:2,time:10000});
+ return;
+ }
+
+ var ret_data = $.parseJSON(res.data);
+ console.log("send:",ret_data);
+ // if (!ret_data.status){
+ // layer.msg(ret_data.msg,{icon:2,time:2000});
+ // return;
+ // }
+
+ // console.log("send2:",ret_data);
+
+ if(typeof(callback) == 'function'){
+ callback(ret_data);
+ }
+ },'json');
+ },
+ postCallback:function(info){
+ var tips = info['tips'];
+ var method = info['method'];
+ var args = info['data'];
+ var callback = info['success'];
+
+ var loadT = layer.msg(tips, { icon: 16, time: 0, shade: 0.3 });
+
+ var data = {};
+ data['name'] = 'nezha';
+ data['func'] = method;
+ data['version'] = $('.plugin_version').attr('version');
+
+ if (typeof(args) == 'string'){
+ data['args'] = JSON.stringify(this.str2Obj(args));
+ } else {
+ data['args'] = JSON.stringify(args);
+ }
+
+ $.post('/plugins/callback', data, function(res) {
+
+ layer.close(loadT);
+ if (!res.status){
+ layer.msg(res.msg,{icon:2,time:10000});
+ return;
+ }
+
+ var ret_data = $.parseJSON(res.data);
+ if (!ret_data.status){
+ layer.msg(ret_data.msg,{icon:2,time:2000});
+ return;
+ }
+
+ if(typeof(callback) == 'function'){
+ callback(res);
+ }
+ },'json');
+ }
+}
diff --git a/plugins/nezha/versions/0.15.2/install.sh b/plugins/nezha/versions/0.15.2/install.sh
new file mode 100755
index 000000000..f1e99e535
--- /dev/null
+++ b/plugins/nezha/versions/0.15.2/install.sh
@@ -0,0 +1,155 @@
+#!/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")
+
+install_tmp=${rootPath}/tmp/mw_install.pl
+VERSION=0.15.2
+
+# bash install.sh install 0.15.2
+# cd /www/server/mdserver-web/plugins/nezha && bash install.sh install 0.15.2
+# cd /Users/midoks/Desktop/mwdev/server/mdserver-web/plugins/nezha && bash install.sh install 0.15.2
+
+bash ${rootPath}/scripts/getos.sh
+OSNAME=`cat ${rootPath}/data/osname.pl`
+OSNAME_ID=`cat /etc/*-release | grep VERSION_ID | awk -F = '{print $2}' | awk -F "\"" '{print $2}'`
+
+
+ARCH="amd64"
+
+get_arch() {
+ TMP_ARCH=`arch`
+ if [ "$TMP_ARCH" == "x86_64" ];then
+ ARCH="amd64"
+ elif [ "$TMP_ARCH" == "aarch64" ];then
+ ARCH="arm64"
+ else
+ echo $ARCH
+ fi
+}
+
+load_vars() {
+ OS=$(uname | tr '[:upper:]' '[:lower:]')
+ TARGET_DIR="$serverPath/nezha/dashboard"
+
+
+ ## China_IP
+ if [[ -z "${CN}" ]]; then
+ if [[ $(curl -m 10 -s https://ipapi.co/json | grep 'China') != "" ]]; then
+ CN=true
+ fi
+ fi
+
+ if [[ -z "${CN}" ]]; then
+ GITHUB_RAW_URL="raw.githubusercontent.com/midoks/nezha/main"
+ GITHUB_URL="github.com"
+ else
+ GITHUB_RAW_URL="cdn.jsdelivr.net/gh/midoks/nezha@main"
+ GITHUB_URL="dn-dao-github-mirror.daocloud.io"
+ fi
+}
+
+# download file
+download_file() {
+ url="${1}"
+ destination="${2}"
+
+ printf "Fetching ${url} \n\n"
+
+ if test -x "$(command -v curl)"; then
+ code=$(curl --connect-timeout 15 -w '%{http_code}' -L "${url}" -o "${destination}")
+ elif test -x "$(command -v wget)"; then
+ code=$(wget -t2 -T15 -O "${destination}" --server-response "${url}" 2>&1 | awk '/^ HTTP/{print $2}' | tail -1)
+ else
+ printf "\e[1;31mNeither curl nor wget was available to perform http requests.\e[0m\n"
+ exit 1
+ fi
+
+ if [ "${code}" != 200 ]; then
+ printf "\e[1;31mRequest failed with code %s\e[0m\n" $code
+ exit 1
+ else
+ printf "\n\e[1;33mDownload succeeded\e[0m\n"
+ fi
+}
+
+
+Install_dashborad(){
+ echo '正在安装哪吒监控...' > $install_tmp
+ mkdir -p $serverPath/source
+
+
+ DOWNLOAD_URL="https://${GITHUB_URL}/midoks/nezha/releases/download/v${VERSION}/nezha-${OS}-${ARCH}.zip"
+
+ DOWNLOAD_FILE="$(mktemp).zip"
+ download_file $DOWNLOAD_URL $DOWNLOAD_FILE
+
+ if [ ! -d $TARGET_DIR ]; then
+ mkdir -p $TARGET_DIR
+ fi
+
+ if [ ! -f $TARGET_DIR/nezha ];then
+ unzip $DOWNLOAD_FILE -d $TARGET_DIR
+ rm -rf $DOWNLOAD_FILE
+ fi
+
+}
+
+Install_agent(){
+ echo -e "正在下载监控端" > $install_tmp
+ mkdir -p $serverPath/source
+
+ version=v0.15.1
+
+ AGENT_TARGET_DIR="$serverPath/nezha/agent"
+
+ DOWNLOAD_URL="https://${GITHUB_URL}/nezhahq/agent/releases/download/${version}/nezha-agent_${OS}_${ARCH}.zip"
+ DOWNLOAD_FILE="$(mktemp).zip"
+
+ download_file $DOWNLOAD_URL $DOWNLOAD_FILE
+
+ if [ ! -d $AGENT_TARGET_DIR ]; then
+ mkdir -p $AGENT_TARGET_DIR
+ fi
+
+ if [ ! -f $AGENT_TARGET_DIR/nezha-agent ];then
+ unzip $DOWNLOAD_FILE -d $AGENT_TARGET_DIR
+ rm -rf $DOWNLOAD_FILE
+ fi
+}
+
+Install_App()
+{
+ load_vars
+ get_arch
+
+ Install_dashborad
+ Install_agent
+
+ if [ -d $serverPath/nezha ];then
+ echo "$VERSION" > $serverPath/nezha/version.pl
+
+ cd ${rootPath} && python3 ${rootPath}/plugins/nezha/index.py start
+ cd ${rootPath} && python3 ${rootPath}/plugins/nezha/index.py initd_install
+ fi
+ echo 'install successful' > $install_tmp
+}
+
+Uninstall_App()
+{
+ cd ${rootPath} && python3 ${rootPath}/plugins/nezha/index.py initd_uninstall
+ cd ${rootPath} && python3 ${rootPath}/plugins/nezha/index.py stop
+ rm -rf $serverPath/nezha
+ echo "install fail" > $install_tmp
+}
+
+action=$1
+if [ "${1}" == 'install' ];then
+ Install_App
+else
+ Uninstall_App
+fi