下载 Caddy
由于OpenWrt官方软件库中没有Caddy软件包,故去Caddy官网下载软件,并放到 /usr/bin 下,一定要选择Caddy自定义插件中的“aksdb/caddy-cgi/v2”,其他可根据情况选择
创建配置文件
mkdir /etc/caddy
touch /etc/caddy/Caddyfile
touch /etc/caddy/ubus.sh
chmod +x /etc/caddy/ubus.sh
vim /etc/caddy/Caddyfile
vim /etc/caddy/ubus.sh
Caddyfile写入以下内容:
{
order cgi before respond
}
localhost, 192.168.1.1, router, router.home {
tls internal
root * /www
file_server
cgi /cgi-bin/cgi-backup* /www/cgi-bin/cgi-backup {
script_name /cgi-bin/cgi-backup
}
cgi /cgi-bin/cgi-download* /www/cgi-bin/cgi-download {
script_name /cgi-bin/cgi-download
}
cgi /cgi-bin/cgi-exec* /www/cgi-bin/cgi-exec {
script_name /cgi-bin/cgi-exec
}
cgi /cgi-bin/cgi-upload* /www/cgi-bin/cgi-upload {
script_name /cgi-bin/cgi-upload
}
cgi /cgi-bin/luci* /www/cgi-bin/luci {
script_name /cgi-bin/luci
}
cgi /ubus* /etc/caddy/ubus.sh {
script_name /ubus
}
}
ubus.sh写入以下内容:
#!/bin/sh
[ "$REQUEST_METHOD" != "POST" ] && printf 'Status: 405\r\n\r\n' && exit
access() {
local sid=$1
local obj=$2
local fun=$3
local req=$(printf '{ "ubus_rpc_session": "%s", "scope": "ubus", "object": "%s", "function": "%s" }' "$sid" "$obj" "$fun")
local res=$(ubus call session access "$req" | jsonfilter -e '@.access')
[ "$res" = "true" ]
}
error() {
local code=$1
local mesg=$2
printf '{ "jsonrpc": "2.0", "id": "%s", "error": { "code": %d, "message": "%s" } }' \
"${RPC_ID:-null}" "$code" "$mesg"
exit 1
}
process() {
local request=$1
# - use `VAR=expr` notation to let it create shell compatible export statements
# - eval result to import variables
eval $(jsonfilter -s "$request" \
-e 'RPC_ID=@.id' \
-e 'RPC_VERSION=@.jsonrpc' \
-e 'RPC_METHOD=@.method' \
-e 'RPC_SESSION_ARG=@.params[3].ubus_rpc_session' \
-e 'UBUS_SID=@.params[0]' \
-e 'UBUS_SERVICE=@.params[1]' \
-e 'UBUS_CMD=@.params[2]')
# verify JSON-RPC framing
if [ -z "$RPC_ID" ] || [ "$RPC_VERSION" != "2.0" ]; then
error -32600 "Invalid request"
fi
# reject invalid values to prevent shell injection
case "$RPC_ID$UBUS_SID$UBUS_SERVICE$UBUS_CMD" in
*[^a-zA-Z0-9_.-]*) error -32600 "Invalid request" ;;
esac
case "$RPC_METHOD" in
call)
UBUS_PAYLOAD=$(jsonfilter -s "$request" -e '@.params[3]')
# ensure that payload is a dictionary or empty
case "$UBUS_PAYLOAD" in
""|{*}) : ;;
*) error -32602 "Invalid parameters" ;;
esac
# merge ubus_rpc_session parameter
if [ -z "$UBUS_PAYLOAD" ] || [ "$UBUS_PAYLOAD" = "" ]; then
UBUS_PAYLOAD=$(printf '{ "ubus_rpc_session": "%s" }' "$UBUS_SID")
else
UBUS_PAYLOAD=$(printf '{ "ubus_rpc_session": "%s", %s' "$UBUS_SID" "${UBUS_PAYLOAD#\")
fi
# reject requests with embedded ubus_rpc_session
if [ -n "$RPC_SESSION_ARG" ]; then
error -32602 "Invalid parameters"
fi
# check access
if ! access "$UBUS_SID" "$UBUS_SERVICE" "$UBUS_CMD"; then
error -32002 "Access denied"
fi
ubus_reply=$(ubus call "$UBUS_SERVICE" "$UBUS_CMD" "$UBUS_PAYLOAD")
ubus_status=$?
printf '{ "jsonrpc": "2.0", "id": "%s", "result": [ %d, %s ] }' \
"$RPC_ID" "$ubus_status" "${ubus_reply:-null}"
;;
list)
RPC_PARAMS=$(jsonfilter -s "$request" -e '@.params')
# ensure that payload is an array or empty
case "${RPC_PARAMS:-[ ]}" in
\[*\]) : ;;
*) error -32602 "Invalid parameters" ;;
esac
# empty payload should result in list of services
if [ "${RPC_PARAMS:-[ ]}" = "[ ]" ]; then
services=''
for service in $(ubus list); do
services="${services:+$services, }\"$service\""
done
printf '{ "jsonrpc": "2.0", "id": "%s", "result": [ %s ] }' \
"$RPC_ID" "$services"
# list of services should result in { service => { method => signature } } replies
else
signatures=''
eval $(jsonfilter -s "$RPC_PARAMS" -e 'indexes=@')
for i in $indexes; do
service=$(jsonfilter -s "$RPC_PARAMS" -e "@[$i]")
signature=''
IFS=$'\n\t'
for line in $(ubus -v list "$service" | tail -n +2); do
signature="${signature:+$signature, }$line"
done
IFS=$' \n\t'
signatures="${signatures:+$signatures, }\"$service\": { $signature }"
done
printf '{ "jsonrpc": "2.0", "id": "%s", "result": { %s } }' \
"$RPC_ID" "$signatures"
fi
;;
*)
error -32601 "Method not found"
;;
esac
}
# - read body from stdin (either an object or array)
# - process each item if it is an array
body=$(cat)
type=$(jsonfilter -s "$body" -t '@')
printf 'Content-Type: application/json\r\n\r\n'
if [ "$type" = "array" ]; then
first=true
printf '['
jsonfilter -s "$body" -e '@.*' | while read request ; do
# join response with ',' and the first should be omitted
if ! $first; then
printf ','
else
first=false
fi
# process each request
process "$request"
done
printf ']'
else
process "$body"
fi
配置系统服务
touch /etc/init.d/caddy
chmod +x /etc/init.d/caddy
vim /etc/init.d/caddy
caddy写入以下内容:
#!/bin/sh /etc/rc.common
PROG=/usr/bin/caddy
USE_PROCD=1
# starts after network starts
START=21
# stops before networking stops
STOP=89
start_service() {
procd_open_instance
procd_set_param command "$PROG" run --config /etc/caddy/Caddyfile --adapter caddyfile
procd_set_param stdout 1
procd_set_param stderr 1
procd_close_instance
}
设置开机自启
# 停止并删除uhttpd服务
service uhttpd stop
service uhttpd disable
# 添加并启动Caddy服务
service caddy enable
service caddy start
# 查看Caddy服务状态
netstat -lnpt | grep -e 80 -e 443
卸载uhttpd软件包(可选)
opkg remove uhttpd --force-removal-of-dependent-packages