diff --git a/plugins/caddy/check.sh b/plugins/caddy/check.sh
new file mode 100755
index 000000000..4cb2277cc
--- /dev/null
+++ b/plugins/caddy/check.sh
@@ -0,0 +1,35 @@
+#!/bin/bash
+PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin
+export PATH
+
+# OpenResty服务名称
+service_name="caddy"
+
+# 检查OpenResty是否正在运行
+if systemctl is-active --quiet "$service_name"; then
+ # 检查是否存在僵尸进程
+ zombie_processes=$(ps -ef | grep -i caddy | grep -v grep | awk '{print $2}' | xargs ps -o state= -p 2>/dev/null | grep -c Z)
+ if [ "$zombie_processes" -gt 0 ]; then
+ echo "kill caddy 僵尸进程"
+ ps -ef|grep caddy| grep -v grep| awk '{print $2}' | xargs kill -9
+ echo "检测到OpenResty僵尸进程,正在重启服务..."
+ systemctl restart "$service_name"
+ echo "服务已重启"
+ else
+ echo "OpenResty运行正常"
+ fi
+else
+ echo "kill caddy"
+ ps -ef|grep caddy| grep -v grep| awk '{print $2}' | xargs kill -9
+ echo "caddy未运行,正在启动服务..."
+ systemctl start "$service_name"
+ echo "服务已启动"
+fi
+
+NGINX_IDS=`ps -ef|grep caddy | grep -v grep| awk '{print $2}'`
+if [ "$NGINX_IDS" == "" ];then
+ ps -ef|grep caddy| grep -v grep| awk '{print $2}' | xargs kill -9
+ systemctl start "$service_name"
+ echo "caddy未运行,正在启动服务..."
+fi
+
diff --git a/plugins/caddy/conf/Caddyfile b/plugins/caddy/conf/Caddyfile
new file mode 100644
index 000000000..98594e3a2
--- /dev/null
+++ b/plugins/caddy/conf/Caddyfile
@@ -0,0 +1,13 @@
+:8080 {
+ # Set this path to your site's directory.
+ root * /tmp
+
+ # Enable the static file server.
+ file_server
+
+ # Another common task is to set up a reverse proxy:
+ # reverse_proxy localhost:8080
+
+ # Or serve a PHP site through php-fpm:
+ # php_fastcgi localhost:9000
+}
\ No newline at end of file
diff --git a/plugins/caddy/ico.png b/plugins/caddy/ico.png
new file mode 100644
index 000000000..91071011e
Binary files /dev/null and b/plugins/caddy/ico.png differ
diff --git a/plugins/caddy/index.html b/plugins/caddy/index.html
new file mode 100755
index 000000000..92cba9ba6
--- /dev/null
+++ b/plugins/caddy/index.html
@@ -0,0 +1,24 @@
+
+
+
\ No newline at end of file
diff --git a/plugins/caddy/index.py b/plugins/caddy/index.py
new file mode 100755
index 000000000..fdd445a91
--- /dev/null
+++ b/plugins/caddy/index.py
@@ -0,0 +1,442 @@
+# coding:utf-8
+
+import sys
+import io
+import os
+import time
+import threading
+import subprocess
+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 'caddy'
+
+
+def getPluginDir():
+ return mw.getPluginDir() + '/' + getPluginName()
+
+
+def getServerDir():
+ return mw.getServerDir() + '/' + getPluginName()
+
+
+def getInitDFile():
+ current_os = mw.getOs()
+ if current_os == 'darwin':
+ return '/tmp/' + getPluginName()
+
+ if current_os.startswith('freebsd'):
+ return '/etc/rc.d/' + getPluginName()
+
+ return '/etc/init.d/' + getPluginName()
+
+
+def getArgs():
+ args = sys.argv[2:]
+ # print(args)
+ tmp = {}
+ args_len = len(args)
+
+ if args_len == 1:
+ t = args[0].strip('{').strip('}')
+ t = t.split(':',2)
+ tmp[t[0]] = t[1]
+ elif args_len > 1:
+ for i in range(len(args)):
+ t = args[i].split(':',2)
+ tmp[t[0]] = t[1]
+ # print(tmp)
+ return tmp
+
+
+def checkArgs(data, ck=[]):
+ for i in range(len(ck)):
+ if not ck[i] in data:
+ return (False, mw.returnJson(False, '参数:(' + ck[i] + ')没有!'))
+ return (True, mw.returnJson(True, 'ok'))
+
+
+def getConf():
+ path = getServerDir() + "/Caddyfile"
+ return path
+
+
+def getConfTpl():
+ path = getPluginDir() + '/conf/Caddyfile'
+ return path
+
+
+def getInitDTpl():
+ path = getPluginDir() + "/init.d/caddy.tpl"
+ return path
+
+def initDreplace():
+ file_tpl = getInitDTpl()
+ service_path = mw.getServerDir()
+ initD_path = getServerDir() + '/init.d'
+
+ # init.d
+ file_bin = initD_path + '/' + getPluginName()
+
+ if not os.path.exists(initD_path):
+ os.mkdir(initD_path)
+
+ # initd replace
+ content = mw.readFile(file_tpl)
+ content = content.replace('{$SERVER_PATH}', service_path)
+ mw.writeFile(file_bin, content)
+ mw.execShell('chmod +x ' + file_bin)
+
+ caddy_file = getConf()
+ if not os.path.exists(caddy_file):
+ caddy_file_tpl = getConfTpl()
+ content = mw.readFile(systemServiceTpl)
+ content = content.replace('{$SERVER_PATH}', service_path)
+ mw.writeFile(caddy_file, content)
+
+ # systemd
+ # /usr/lib/systemd/system
+ systemDir = mw.systemdCfgDir()
+ systemService = systemDir + '/caddy.service'
+ if os.path.exists(systemDir) and not os.path.exists(systemService):
+ systemServiceTpl = getPluginDir() + '/init.d/caddy.service.tpl'
+ 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 status():
+ cmd = "ps -ef|grep 'caddy run' |grep -v grep | grep -v python | awk '{print $2}'"
+ data = mw.execShell(cmd)
+ if data[0] == '':
+ return 'stop'
+ return 'start'
+
+
+def caddyOp(method):
+ file = initDreplace()
+
+ current_os = mw.getOs()
+ if current_os == "darwin":
+ data = mw.execShell(file + ' ' + method)
+ if data[1] == '':
+ return 'ok'
+ return data[1]
+
+ if current_os.startswith("freebsd"):
+ data = mw.execShell('service caddy ' + method)
+ if data[1] == '':
+ return 'ok'
+ return data[1]
+
+ data = mw.execShell('systemctl ' + method + ' caddy')
+ if data[1] == '':
+ return 'ok'
+ return data[1]
+
+def start():
+ return caddyOp('start')
+
+
+def stop():
+ r = caddyOp('stop')
+ pid_file = getPidFile()
+ if os.path.exists(pid_file):
+ os.remove(pid_file)
+ return r
+
+
+def restart():
+ return restyOp_restart()
+
+
+def reload():
+ confReplace()
+ return caddyOp('reload')
+
+
+def initdStatus():
+ current_os = mw.getOs()
+ if current_os == 'darwin':
+ return "Apple Computer does not support"
+
+ if current_os.startswith('freebsd'):
+ initd_bin = getInitDFile()
+ if os.path.exists(initd_bin):
+ return 'ok'
+
+ shell_cmd = 'systemctl status caddy | grep loaded | grep "enabled;"'
+ data = mw.execShell(shell_cmd)
+ if data[0] == '':
+ return 'fail'
+ return 'ok'
+
+
+def initdInstall():
+ current_os = mw.getOs()
+ if current_os == 'darwin':
+ return "Apple Computer does not support"
+
+ # freebsd initd install
+ if current_os.startswith('freebsd'):
+ import shutil
+ source_bin = initDreplace()
+ initd_bin = getInitDFile()
+ shutil.copyfile(source_bin, initd_bin)
+ mw.execShell('chmod +x ' + initd_bin)
+ mw.execShell('sysrc ' + getPluginName() + '_enable="YES"')
+ return 'ok'
+
+ mw.execShell('systemctl enable caddy')
+ return 'ok'
+
+
+def initdUinstall():
+ current_os = mw.getOs()
+ if current_os == 'darwin':
+ return "Apple Computer does not support"
+
+ if current_os.startswith('freebsd'):
+ initd_bin = getInitDFile()
+ os.remove(initd_bin)
+ mw.execShell('sysrc ' + getPluginName() + '_enable="NO"')
+ return 'ok'
+
+ mw.execShell('systemctl disable caddy')
+ return 'ok'
+
+
+def runInfo():
+ op_status = status()
+ if op_status == 'stop':
+ return mw.returnJson(False, "未启动!")
+
+
+def errorLogPath():
+ return getServerDir() + '/nginx/logs/error.log'
+
+
+def getCfg():
+ cfg = getConf()
+ content = mw.readFile(cfg)
+
+ unitrep = "[kmgKMG]"
+ cfg_args = [
+ {"name": "worker_processes", "ps": "处理进程,auto表示自动,数字表示进程数", 'type': 2},
+ {"name": "worker_connections", "ps": "最大并发链接数", 'type': 2},
+ {"name": "keepalive_timeout", "ps": "连接超时时间", 'type': 2},
+ {"name": "zstd", "ps": "是否开启zstd压缩传输", 'type': 1},
+ {"name": "brotli", "ps": "是否开启brotli压缩传输", 'type': 1},
+ {"name": "gzip", "ps": "是否开启gzip压缩传输", 'type': 1},
+ {"name": "gzip_min_length", "ps": "最小压缩文件", 'type': 2},
+ {"name": "gzip_comp_level", "ps": "压缩率", 'type': 2},
+ {"name": "client_max_body_size", "ps": "最大上传文件", 'type': 2},
+ {"name": "server_names_hash_bucket_size",
+ "ps": "服务器名字的hash表大小", 'type': 2},
+ {"name": "client_header_buffer_size", "ps": "客户端请求头buffer大小", 'type': 2},
+ ]
+
+ # {"name": "client_body_buffer_size", "ps": "请求主体缓冲区"}
+ rdata = []
+ for i in cfg_args:
+ rep = r"(%s)\s+(\w+)" % i["name"]
+ k = re.search(rep, content)
+ if not k:
+ return mw.returnJson(False, "获取 key {} 失败".format(k))
+ k = k.group(1)
+ v = re.search(rep, content)
+ if not v:
+ return mw.returnJson(False, "获取 value {} 失败".format(v))
+ v = v.group(2)
+
+ if re.search(unitrep, v):
+ u = str.upper(v[-1])
+ v = v[:-1]
+ if len(u) == 1:
+ psstr = u + "B," + i["ps"]
+ else:
+ psstr = u + "," + i["ps"]
+ else:
+ u = ""
+
+ kv = {"name": k, "value": v, "unit": u,
+ "ps": i["ps"], "type": i["type"]}
+ rdata.append(kv)
+
+ return mw.returnJson(True, "ok", rdata)
+
+def replaceChar(value, index, new_char):
+ return value[:index] + new_char + value[index+1:]
+
+def makeWorkerCpuAffinity(val):
+ if val == "auto":
+ return "auto"
+
+ if mw.isNumber(val):
+ core_num = int(val)
+ default_core_str = "0"*core_num
+ core_num_arr = []
+ for x in range(core_num):
+ t = replaceChar(default_core_str, x , "1")
+ core_num_arr.append(t)
+ return " ".join(core_num_arr)
+
+ return 'auto'
+
+def setCfg():
+
+ args = getArgs()
+ data = checkArgs(args, [
+ 'worker_processes', 'worker_connections', 'keepalive_timeout','zstd','brotli',
+ 'gzip', 'gzip_min_length', 'gzip_comp_level', 'client_max_body_size',
+ 'server_names_hash_bucket_size', 'client_header_buffer_size'
+ ])
+ if not data[0]:
+ return data[1]
+
+ cfg = getConf()
+ mw.backFile(cfg)
+ content = mw.readFile(cfg)
+
+ unitrep = "[kmgKMG]"
+ cfg_args = [
+ {"name": "worker_processes", "ps": "处理进程,auto表示自动,数字表示进程数", 'type': 2},
+ {"name": "worker_connections", "ps": "最大并发链接数", 'type': 2},
+ {"name": "keepalive_timeout", "ps": "连接超时时间", 'type': 2},
+ {"name": "zstd", "ps": "是否开启zstd压缩传输", 'type': 1},
+ {"name": "brotli", "ps": "是否开启brotli压缩传输", 'type': 1},
+ {"name": "gzip", "ps": "是否开启压缩传输", 'type': 1},
+ {"name": "gzip_min_length", "ps": "最小压缩文件", 'type': 2},
+ {"name": "gzip_comp_level", "ps": "压缩率", 'type': 2},
+ {"name": "client_max_body_size", "ps": "最大上传文件", 'type': 2},
+ {"name": "server_names_hash_bucket_size",
+ "ps": "服务器名字的hash表大小", 'type': 2},
+ {"name": "client_header_buffer_size", "ps": "客户端请求头buffer大小", 'type': 2},
+ ]
+
+ # print(args)
+ for k, v in args.items():
+ # print(k, v)
+ rep = r"%s\s+[^kKmMgG\;\n]+" % k
+ if k == "worker_processes" or k == "gzip":
+ if not re.search(r"auto|on|off|\d+", v):
+ return mw.returnJson(False, '参数值错误')
+ elif k == "zstd" or k == "brotli":
+ if not re.search(r"auto|on|off|\d+", v):
+ return mw.returnJson(False, '参数值错误')
+ else:
+ if not re.search(r"\d+", v):
+ return mw.returnJson(False, '参数值错误,请输入数字整数')
+
+ if k == "worker_processes" :
+ k_wca = "worker_cpu_affinity"
+ rep_wca = r"%s\s+[^\;\n]+" % k_wca
+ v_wca = makeWorkerCpuAffinity(v)
+ newconf = "%s %s" % (k_wca, v_wca)
+ content = re.sub(rep_wca, newconf, content)
+
+
+ if re.search(rep, content):
+ newconf = "%s %s" % (k, v)
+ content = re.sub(rep, newconf, content)
+ elif re.search(rep, content):
+ newconf = "%s %s" % (k, v)
+ content = re.sub(rep, newconf, content)
+
+ mw.writeFile(cfg, content)
+ isError = mw.checkWebConfig()
+ if (isError != True):
+ mw.restoreFile(cfg)
+ return mw.returnJson(False, 'ERROR: 配置出错
' + isError.replace("\n", '
') + '')
+
+ mw.restartWeb()
+ return mw.returnJson(True, '设置成功')
+
+
+def cronAddCheck():
+ try:
+ import tool_task
+ tool_task.createBgTask()
+ return mw.returnJson(True, '添加检查任务成功')
+ except Exception as e:
+ return mw.returnJson(False, '添加检查任务失败:'+str(e))
+
+def cronDelCheck():
+ try:
+ import tool_task
+ tool_task.removeBgTask()
+ return mw.returnJson(True, '删除检查任务成功')
+ except Exception as e:
+ return mw.returnJson(False, '删除检查任务失败:'+str(e))
+
+def cronCheck():
+ return 'ok'
+
+
+def installPreInspection():
+ return 'ok'
+
+
+if __name__ == "__main__":
+
+ version = '1.27.1'
+ version_pl = getServerDir() + "/version.pl"
+ if os.path.exists(version_pl):
+ version = mw.readFile(version_pl)
+
+
+ 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(getConf())
+ elif func == 'get_os':
+ print(getOs())
+ elif func == 'run_info':
+ print(runInfo())
+ elif func == 'error_log':
+ print(errorLogPath())
+ elif func == 'get_cfg':
+ print(getCfg())
+ elif func == 'set_cfg':
+ print(setCfg())
+ elif func == 'check':
+ print(cronCheck())
+ elif func == 'cron_add_check':
+ print(cronAddCheck())
+ elif func == 'cron_del_check':
+ print(cronDelCheck())
+ else:
+ print('error')
diff --git a/plugins/caddy/info.json b/plugins/caddy/info.json
new file mode 100755
index 000000000..97a69c069
--- /dev/null
+++ b/plugins/caddy/info.json
@@ -0,0 +1,18 @@
+{
+ "sort": 0,
+ "title":"caddy",
+ "tip":"soft",
+ "name":"caddy",
+ "type":"其他插件",
+ "ps":"一款功能强大、企业级、开源 Web 服务器,具有用 Go 编写的自动 HTTPS",
+ "shell":"install.sh",
+ "install_pre_inspection":true,
+ "checks":"server/caddy",
+ "path":"server/caddy",
+ "author":"caddyserver",
+ "home":"https://caddyserver.com/",
+ "date":"2026-04-11",
+ "pid": "1",
+ "versions": ["2.11"],
+ "updates": ["2.11.2"]
+}
\ No newline at end of file
diff --git a/plugins/caddy/init.d/caddy.service.tpl b/plugins/caddy/init.d/caddy.service.tpl
new file mode 100644
index 000000000..724eb30d7
--- /dev/null
+++ b/plugins/caddy/init.d/caddy.service.tpl
@@ -0,0 +1,36 @@
+# caddy.service
+#
+# For using Caddy with a config file.
+#
+# Make sure the ExecStart and ExecReload commands are correct
+# for your installation.
+#
+# See https://caddyserver.com/docs/install for instructions.
+#
+# WARNING: This service does not use the --resume flag, so if you
+# use the API to make changes, they will be overwritten by the
+# Caddyfile next time the service is restarted. If you intend to
+# use Caddy's API to configure it, add the --resume flag to the
+# `caddy run` command or use the caddy-api.service file instead.
+
+[Unit]
+Description=Caddy
+Documentation=https://caddyserver.com/docs/
+After=network.target network-online.target
+Requires=network-online.target
+
+[Service]
+Type=notify
+User=caddy
+Group=caddy
+ExecStart={$SERVER_PATH}/caddy/bin/caddy run --environ --config {$SERVER_PATH}/caddy/Caddyfile
+ExecReload={$SERVER_PATH}/caddy/bin/caddy reload --config {$SERVER_PATH}/caddy/Caddyfile --force
+TimeoutStopSec=5s
+LimitNOFILE=1048576
+LimitNPROC=512
+PrivateTmp=true
+ProtectSystem=full
+AmbientCapabilities=CAP_NET_BIND_SERVICE
+
+[Install]
+WantedBy=multi-user.target
diff --git a/plugins/caddy/init.d/caddy.tpl b/plugins/caddy/init.d/caddy.tpl
new file mode 100644
index 000000000..e89186483
--- /dev/null
+++ b/plugins/caddy/init.d/caddy.tpl
@@ -0,0 +1,111 @@
+#!/bin/sh
+#
+# /etc/rc.d/init.d/caddy
+#
+# Runs the caddy
+#
+#
+# chkconfig: - 85 15
+#
+
+### BEGIN INIT INFO
+# Provides: caddy
+# Required-Start: $remote_fs $syslog
+# Required-Stop: $remote_fs $syslog
+# Should-Start: caddy
+# Should-Stop: caddy
+# Default-Start: 2 3 4 5
+# Default-Stop: 0 1 6
+# Short-Description: Start caddy at boot time.
+# Description: Control caddy.
+### END INIT INFO
+
+# Source function library.
+if [ -f /etc/init.d/functions ];then
+ . /etc/init.d/functions
+fi
+
+if [ -f /etc/rc.d/init.d/functions ];then
+ . /etc/rc.d/init.d/functions
+fi
+
+# Default values
+export HOME={$HOME_DIR}
+export USER={$RUN_USER}
+NAME=caddy
+CADDY_HOME={$SERVER_PATH}/caddy
+CADDY_PATH=${CADDY_HOME}/bin/$NAME
+CADDY_USER={$RUN_USER}
+SERVICENAME="caddy"
+LOCKFILE=/tmp/caddy.lock
+LOGPATH=${CADDY_HOME}/log
+LOGFILE=${LOGPATH}/caddy.log
+RETVAL=0
+
+if [ -d $LOGPATH ];then
+ mkdir -p $LOGPATH
+fi
+
+[ -r /etc/sysconfig/$NAME ] && . /etc/sysconfig/$NAME
+DAEMON_OPTS="--check $NAME"
+[ ! -z "$CADDY_USER" ] && DAEMON_OPTS="$DAEMON_OPTS --user=${CADDY_USER}"
+
+status(){
+ isStart=`ps -ef|grep 'caddy run' |grep -v grep|awk '{print $2}'`
+ if [ "$isStart" == '' ];then
+ echo -e "${SERVICENAME} not running"
+ else
+ echo -e "${SERVICENAME}(pid $(echo $isStart)) already running"
+ fi
+}
+
+start() {
+ isStart=`ps -ef | grep 'caddy run' | grep -v grep | awk '{print $2}'`
+ if [ "$isStart" != '' ];then
+ echo "${SERVICENAME}(pid $(echo $isStart)) already running"
+ return $RETVAL
+ fi
+
+ cd ${CADDY_HOME}
+ echo -e "starting ${SERVICENAME}: \c"
+ ${CADDY_PATH} run --environ --config ${CADDY_HOME}/Caddyfile > ${LOGFILE} 2>&1 &
+ RETVAL=$?
+ [ $RETVAL = 0 ] && touch ${LOCKFILE} && echo -e "\033[32mdone\033[0m"
+ return $RETVAL
+}
+
+stop() {
+ pids=`ps -ef | grep 'caddy run' | grep -v grep | awk '{print $2}'`
+ arr=($pids)
+ echo -e "stopping caddy... \c"
+ for p in ${arr[@]}
+ do
+ kill -9 $p
+ done
+ echo -e "\033[32mdone\033[0m"
+}
+
+case "$1" in
+ start)
+ start
+ ;;
+ stop)
+ stop
+ ;;
+ status)
+ status
+ ;;
+ restart)
+ stop
+ start
+ ;;
+ reload)
+ stop
+ start
+ ;;
+ *)
+ echo "Usage: ${NAME} {start|stop|status|restart}"
+ exit 1
+ ;;
+esac
+exit $RETVAL
diff --git a/plugins/caddy/install.sh b/plugins/caddy/install.sh
new file mode 100755
index 000000000..cf40b02da
--- /dev/null
+++ b/plugins/caddy/install.sh
@@ -0,0 +1,76 @@
+#!/bin/bash
+PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin
+export PATH
+
+# cd /Users/midoks/Desktop/mwdev/server/mdserver-web/plugins/caddy && bash install.sh install 1.21.4
+# cd /www/server/mdserver-web/plugins/caddy && bash install.sh install 1.21.4
+# cd /www/server/mdserver-web/plugins/caddy && bash install.sh install 1.29.2
+# cd /www/server/mdserver-web/plugins/caddy && bash install.sh upgrade 1.29.2
+
+# curl -I -H "Accept-Encoding: br" http://localhost
+# curl -I -H "Accept-Encoding: zstd" http://localhost
+# curl --http3 -v https://www.xxx.com
+
+# cd /www/server/mdserver-web && python3 plugins/caddy/index.py run_info
+
+curPath=`pwd`
+rootPath=$(dirname "$curPath")
+rootPath=$(dirname "$rootPath")
+serverPath=$(dirname "$rootPath")
+
+sysName=`uname`
+action=$1
+type=$2
+
+VERSION=$2
+openrestyDir=${serverPath}/source/caddy
+
+if id www &> /dev/null ;then
+ echo "www uid is `id -u www`"
+ echo "www shell is `grep "^www:" /etc/passwd |cut -d':' -f7 `"
+else
+ groupadd www
+ useradd -g www -s /bin/bash www
+fi
+
+if [ "${action}" == "upgrade" ];then
+ sh -x $curPath/versions/$2/install.sh $1
+
+ echo "${VERSION}" > $serverPath/caddy/version.pl
+
+ #初始化
+ cd ${rootPath} && python3 ${rootPath}/plugins/caddy/index.py start
+ cd ${rootPath} && python3 ${rootPath}/plugins/caddy/index.py initd_install
+ exit 0
+fi
+
+
+if [ "${2}" == "" ];then
+ echo '缺少安装脚本版本...'
+ exit 0
+fi
+
+if [ "${action}" == "uninstall" ];then
+ if [ -f /usr/lib/systemd/system/caddy.service ] || [ -f /lib/systemd/system/caddy.service ];then
+ systemctl stop caddy
+ rm -rf /usr/systemd/system/caddy.service
+ rm -rf /lib/systemd/system/caddy.service
+ systemctl daemon-reload
+ fi
+
+ if [ -f $serverPath/caddy/init.d/caddy ];then
+ $serverPath/caddy/init.d/caddy stop
+ fi
+
+ rm -rf $serverPath/caddy
+fi
+
+sh -x $curPath/versions/$2/install.sh $1
+
+if [ "${action}" == "install" ] && [ -d $serverPath/caddy ];then
+ echo "${VERSION}" > $serverPath/caddy/version.pl
+
+ #初始化
+ cd ${rootPath} && python3 ${rootPath}/plugins/caddy/index.py start
+ cd ${rootPath} && python3 ${rootPath}/plugins/caddy/index.py initd_install
+fi
diff --git a/plugins/caddy/js/caddy.js b/plugins/caddy/js/caddy.js
new file mode 100755
index 000000000..3eccb9fce
--- /dev/null
+++ b/plugins/caddy/js/caddy.js
@@ -0,0 +1,238 @@
+function caddyPost(method, args, callback){
+ var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
+ $.post('/plugins/run', {name:'caddy', func:method, args:JSON.stringify(args)}, function(data) {
+ layer.close(loadT);
+ if (!data.status){
+ layer.msg(data.msg,{icon:0,time:2000,shade: [0.3, '#000']});
+ return;
+ }
+
+ if(typeof(callback) == 'function'){
+ callback(data);
+ }
+ },'json');
+}
+
+function orPluginService(_name, version){
+ var data = {name:_name, func:'status'}
+ if ( typeof(version) != 'undefined' ){
+ data['version'] = version;
+ } else {
+ version = '';
+ }
+
+ caddyPost('status', data, function(data){
+ if (data.data == 'start'){
+ orPluginSetService(_name, true, version);
+ } else {
+ orPluginSetService(_name, false, version);
+ }
+ });
+}
+
+function orPluginSetService(_name ,status, version){
+ var serviceCon ='当前状态:'+(status ? '开启' : '关闭' )+
+ '
\
+ \
+ \
+ \
+
';
+ $(".soft-man-con").html(serviceCon);
+}
+
+
+function orPluginOpService(a, b, v,request_callback) {
+
+ var c = "name=" + a + "&func=" + b;
+ if(v != ''){
+ c = c + '&version='+v;
+ }
+
+ var d = "";
+
+ switch(b) {
+ case "stop":d = '停止';break;
+ case "start":d = '启动';break;
+ case "restart":d = '重启';break;
+ case "reload":d = '重载';break;
+ }
+ layer.confirm( msgTpl('您真的要{1}{2}{3}服务吗?', [d,a,v]), {icon:3,closeBtn: 2}, function() {
+ caddyPost('get_os',{},function(data){
+ var rdata = $.parseJSON(data.data);
+ if (!rdata['auth']){
+ layer.prompt({title: '检查到权限不足,需要输入密码!', formType: 1},function(pwd, index){
+
+ layer.close(index);
+ var data = {'pwd':pwd};
+ c += '&args='+JSON.stringify(data);
+ orPluginOpServiceOp(a,b,c,d,a,v,request_callback);
+ });
+ } else {
+ orPluginOpServiceOp(a,b,c,d,a,v,request_callback);
+
+ }
+ });
+ })
+}
+
+function orPluginOpServiceOp(a,b,c,d,a,v,request_callback){
+
+ var request_path = "/plugins/run";
+ if (request_callback == 'yes'){
+ request_path = "/plugins/callback";
+ }
+
+ var e = layer.msg(msgTpl('正在{1}{2}{3}服务,请稍候...',[d,a,v]), {icon: 16,time: 0});
+ $.post(request_path, c, function(g) {
+ layer.close(e);
+
+ var f = g.data == 'ok' ? msgTpl('{1}{2}服务已{3}',[a,v,d]) : msgTpl('{1}{2}服务{3}失败!',[a,v,d]);
+ layer.msg(f, {icon: g.data == 'ok' ? 1 : 2});
+
+ if( b != "reload" && g.data == 'ok' ) {
+ if ( b == 'start' ) {
+ orPluginSetService(a, true, v);
+ } else if ( b == 'stop' ){
+ orPluginSetService(a, false, v);
+ }
+ }
+
+ if( g.status && g.data != 'ok' ) {
+ layer.msg(g.data, {icon: 2,time: 10000,shade: 0.3});
+ }
+
+ },'json').error(function() {
+ layer.close(e);
+ layer.msg('操作异常!', {icon: 2});
+ });
+}
+
+
+//查看Nginx负载状态
+function getOpStatus() {
+ var loadT = layer.msg('正在处理,请稍后...', { icon: 16, time: 0, shade: 0.3 });
+ $.post('/plugins/run', {name:'openresty', func:'run_info'}, function(data) {
+ layer.close(loadT);
+ try {
+ var rdata = $.parseJSON(data.data);
+ if ('status' in rdata && !rdata.status){
+ showMsg(rdata.msg, function(){}, null,3000);
+ return;
+ }
+
+ var con = "\
+ | 活动连接(Active connections) | " + rdata.active + " |
\
+ | 总连接次数(accepts) | " + rdata.accepts + " |
\
+ | 总握手次数(handled) | " + rdata.handled + " |
\
+ | 总请求数(requests) | " + rdata.requests + " |
\
+ | 请求数(Reading) | " + rdata.Reading + " |
\
+ | 响应数(Writing) | " + rdata.Writing + " |
\
+ | 驻留进程(Waiting) | " + rdata.Waiting + " |
\
+
";
+ $(".soft-man-con").html(con);
+ }catch(err){
+ showMsg(data.data, function(){}, null,3000);
+ }
+ },'json');
+}
+
+
+function setOpCfg(){
+ caddyPost('get_cfg', {}, function(data){
+ var rdata = $.parseJSON(data.data);
+ var rdata = rdata.data;
+ // console.log(rdata);
+
+ var mlist = '';
+ for (var i = 0; i < rdata.length; i++) {
+ var w = '70'
+ var ibody = '';
+ switch (rdata[i].type) {
+ case 0:
+ var selected_1 = (rdata[i].value == 1) ? 'selected' : '';
+ var selected_0 = (rdata[i].value == 0) ? 'selected' : '';
+ ibody = '';
+ break;
+ case 1:
+ var selected_1 = (rdata[i].value == 'on') ? 'selected' : '';
+ var selected_0 = (rdata[i].value == 'off') ? 'selected' : '';
+ ibody = '';
+ break;
+ }
+ mlist += '' + rdata[i].name + '' + ibody + ""+rdata[i].unit+"" +', ' + rdata[i].ps + '
';
+ }
+ var con = '\
+ ' + mlist + '\
+
\
+ \
+ \
+
\
+
'
+ $(".soft-man-con").html(con);
+ });
+}
+
+function submitConf() {
+ var data = {
+ worker_processes: $("input[name='worker_processes']").val(),
+ worker_connections: $("input[name='worker_connections']").val(),
+ keepalive_timeout: $("input[name='keepalive_timeout']").val(),
+ zstd: $("select[name='zstd']").val() || 'on',
+ brotli: $("select[name='brotli']").val() || 'on',
+ gzip: $("select[name='gzip']").val() || 'on',
+ gzip_min_length: $("input[name='gzip_min_length']").val(),
+ gzip_comp_level: $("input[name='gzip_comp_level']").val(),
+ client_max_body_size: $("input[name='client_max_body_size']").val(),
+ server_names_hash_bucket_size: $("input[name='server_names_hash_bucket_size']").val(),
+ client_header_buffer_size: $("input[name='client_header_buffer_size']").val(),
+ };
+
+ // console.log(data);
+ caddyPost('set_cfg', data, function(rdata){
+ var rdata = $.parseJSON(rdata.data);
+ // console.log(rdata);
+ layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
+ });
+}
+
+function otherFunc(){
+ var con = '\
+ \
+ \
+
';
+ $(".soft-man-con").html(con);
+}
+
+function cronAddCheck(){
+ caddyPost('cron_add_check', {}, function(data){
+ var rdata = $.parseJSON(data.data);
+ layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
+ });
+}
+
+function cronDelCheck(){
+ caddyPost('cron_del_check', {}, function(data){
+ var rdata = $.parseJSON(data.data);
+ layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
+ });
+}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/plugins/caddy/tool_task.py b/plugins/caddy/tool_task.py
new file mode 100644
index 000000000..f20ba8348
--- /dev/null
+++ b/plugins/caddy/tool_task.py
@@ -0,0 +1,124 @@
+# coding:utf-8
+
+import sys
+import io
+import os
+import time
+import json
+
+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
+from utils.crontab import crontab as MwCrontab
+
+
+app_debug = False
+if mw.isAppleSystem():
+ app_debug = True
+
+
+def getPluginName():
+ return 'caddy'
+
+
+def getPluginDir():
+ return mw.getPluginDir() + '/' + getPluginName()
+
+
+def getServerDir():
+ return mw.getServerDir() + '/' + getPluginName()
+
+
+def getTaskConf():
+ conf = getServerDir() + "/task_config.json"
+ return conf
+
+
+def getConfigData():
+ conf = getTaskConf()
+ if os.path.exists(conf):
+ return json.loads(mw.readFile(getTaskConf()))
+ return {
+ "task_id": -1,
+ "period": "minute-n",
+ "where1": "3",
+ "hour": "0",
+ "minute": "0",
+ }
+
+
+def createBgTask():
+ removeBgTask()
+ createBgTaskByName(getPluginName())
+
+
+def createBgTaskByName(name):
+ args = getConfigData()
+ _name = "[caddy]检查任务"
+ res = mw.M("crontab").field("id, name").where("name=?", (_name,)).find()
+ if res:
+ return True
+
+ if "task_id" in args and args["task_id"] > 0:
+ res = mw.M("crontab").field("id, name").where(
+ "id=?", (args["task_id"],)).find()
+ if res and res["id"] == args["task_id"]:
+ print("计划任务已经存在!")
+ return True
+
+ mw_dir = mw.getPanelDir()
+ cmd = '''
+mw_dir=%s
+rname=%s
+plugin_path=%s
+script_path=%s
+''' % (mw_dir, name, getServerDir(), getPluginDir())
+ cmd += 'echo "bash $script_path/check.sh"' + "\n"
+ cmd += 'cd $mw_dir && bash $script_path/check.sh' + "\n"
+
+ params = {
+ 'name': _name,
+ 'type': args['period'],
+ 'week': "",
+ 'where1': args['where1'],
+ 'hour': args['hour'],
+ 'minute': args['minute'],
+ 'save': "",
+ 'backup_to': "",
+ 'stype': "toShell",
+ 'sname': '',
+ 'sbody': cmd,
+ 'url_address': '',
+ }
+
+ task_id = MwCrontab.instance().add(params)
+ if task_id > 0:
+ args["task_id"] = task_id
+ args["name"] = name
+ mw.writeFile(getTaskConf(), json.dumps(args))
+
+
+def removeBgTask():
+ cfg = getConfigData()
+ if "task_id" in cfg and cfg["task_id"] > 0:
+ res = mw.M("crontab").field("id, name").where(
+ "id=?", (cfg["task_id"],)).find()
+ if res and res["id"] == cfg["task_id"]:
+ data = MwCrontab.instance().delete(cfg["task_id"])
+ if data["status"]:
+ cfg["task_id"] = -1
+ mw.writeFile(getTaskConf(), json.dumps(cfg))
+ return True
+ return False
+
+
+if __name__ == "__main__":
+ if len(sys.argv) > 1:
+ action = sys.argv[1]
+ if action == "remove":
+ removeBgTask()
+ elif action == "add":
+ createBgTask()
diff --git a/plugins/caddy/versions/2.11/install.sh b/plugins/caddy/versions/2.11/install.sh
new file mode 100644
index 000000000..e97027b78
--- /dev/null
+++ b/plugins/caddy/versions/2.11/install.sh
@@ -0,0 +1,87 @@
+#!/bin/bash
+PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin
+export PATH
+
+# cd /Users/midoks/Desktop/mwdev/server/mdserver-web/plugins/caddy && bash install.sh install 2.11
+# cd /Users/midoks/Desktop/mwdev/server/mdserver-web/plugins/caddy && bash install.sh upgrade 2.11
+# cd /www/server/mdserver-web/plugins/caddy && bash install.sh install 2.11
+
+curPath=`pwd`
+rootPath=$(dirname "$curPath")
+rootPath=$(dirname "$rootPath")
+serverPath=$(dirname "$rootPath")
+
+sysName=`uname`
+action=$1
+type=$2
+
+OS=`uname`
+OSNAME=''
+case $(uname) in
+ Darwin) OSNAME="mac" ;;
+ Linux) OSNAME="linux" ;;
+esac
+
+ARCH=`uname -m`
+ARCH_NAME=''
+case $(uname -m) in
+ i386) ARCH_NAME="386" ;;
+ i686) ARCH_NAME="386" ;;
+ x86_64) ARCH_NAME="amd64" ;;
+ arm) ARCH_NAME="arm64" ;;
+ arm64) ARCH_NAME="arm64" ;;
+esac
+
+VERSION=2.11.2
+
+caddyDir=${serverPath}/source/caddy
+
+Install_App()
+{
+ if [ "${action}" == "install" ];then
+ if [ -d $serverPath/caddy ];then
+ exit 0
+ fi
+ fi
+
+ mkdir -p ${caddyDir}
+ # mkdir -p ${serverPath}/caddy
+ echo 'install scripts ...'
+
+ FILE_NAME="caddy_${VERSION}_${OSNAME}_${ARCH_NAME}.tar.gz"
+
+ if [ ! -f ${caddyDir}/${FILE_NAME} ];then
+ wget --no-check-certificate -O ${caddyDir}/${FILE_NAME} "https://github.com/caddyserver/caddy/releases/download/v${VERSION}/${FILE_NAME}"
+ fi
+
+
+ echo "cd $serverPath/source/caddy/caddy && tar -zxvf ${caddyDir}/$FILE_NAME"
+
+ mkdir -p cd $serverPath/source/caddy/caddy
+ cd $serverPath/source/caddy/caddy && tar -zxvf ${caddyDir}/$FILE_NAME
+ if [ "$OSNAME" == "mac" ];then
+ xattr -cr caddy
+ fi
+
+ if [ ! -f $serverPath/caddy/bin ];then
+ mkdir -p $serverPath/caddy/bin
+ mv $serverPath/source/caddy/caddy/* $serverPath/caddy/bin
+ chmod +x $serverPath/caddy/bin/caddy
+ fi
+
+ echo 'Installation of caddy completed'
+}
+
+Uninstall_App()
+{
+ echo 'Uninstalling caddy completed'
+}
+
+action=$1
+if [ "${1}" == "install" ];then
+ Install_App
+elif [ "${1}" == "upgrade" ];then
+ Install_App
+else
+ Uninstall_App
+fi