v2.6.2
This commit is contained in:
心隨緣動 2025-07-22 21:05:43 +08:00 committed by GitHub
parent 6e90054f3c
commit a67830f4a4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

542
x-ui.sh
View File

@ -753,237 +753,429 @@ update_geo() {
} }
install_acme() { install_acme() {
cd ~ # 检查是否已安装 acme.sh
LOGI "install acme..." if command -v ~/.acme.sh/acme.sh &>/dev/null; then
curl https://get.acme.sh | sh LOGI "acme.sh 已经安装。"
return 0
fi
LOGI "正在安装 acme.sh..."
cd ~ || return 1 # 确保可以切换到主目录
curl -s `https://get.acme.sh` | sh
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
LOGE "安装 acme 失败" LOGE "安装 acme.sh 失败"
return 1 return 1
else else
LOGI "安装 acme 成功" LOGI "安装 acme.sh 成功"
fi fi
return 0 return 0
} }
ssl_cert_issue_main() { ssl_cert_issue_main() {
echo -e "${green}\t1.${plain} 获取 SSL 证书" echo -e "${green}\t1.${plain} 获取 SSL 证书"
echo -e "${green}\t2.${plain} 吊销证书" echo -e "${green}\t2.${plain} 撤销证书"
echo -e "${green}\t3.${plain} 续签证书" echo -e "${green}\t3.${plain} 强制更新证书"
echo -e "${green}\t4.${plain} 显示现有域名"
echo -e "${green}\t5.${plain} 为面板设置证书路径"
echo -e "${green}\t0.${plain} 返回主菜单" echo -e "${green}\t0.${plain} 返回主菜单"
read -p "请输入选项: " choice
read -rp "请选择一个选项:" choice
case "$choice" in case "$choice" in
0) 0)
show_menu show_menu
;; ;;
1) 1)
ssl_cert_issue ssl_cert_issue
ssl_cert_issue_main
;; ;;
2) 2)
local domain="" local domains=$(find /root/cert/ -mindepth 1 -maxdepth 1 -type d -exec basename {} \;)
read -p "请输入您的域名以吊销证书: " domain if [ -z "$domains" ]; then
~/.acme.sh/acme.sh --revoke -d ${domain} echo "未找到可撤销的证书。"
LOGI "证书吊销成功" else
echo "现有域名:"
echo "$domains"
read -rp "请从列表中输入要撤销证书的域名:" domain
if echo "$domains" | grep -qw "$domain"; then
~/.acme.sh/acme.sh --revoke -d ${domain}
LOGI "已撤销域名的证书:$domain"
else
echo "输入的域名无效。"
fi
fi
ssl_cert_issue_main
;; ;;
3) 3)
local domain="" local domains=$(find /root/cert/ -mindepth 1 -maxdepth 1 -type d -exec basename {} \;)
read -p "请输入您的域名以续签 SSL 证书: " domain if [ -z "$domains" ]; then
~/.acme.sh/acme.sh --renew -d ${domain} --force echo "未找到可更新的证书。"
else
echo "现有域名:"
echo "$domains"
read -rp "请从列表中输入要强制更新 SSL 证书的域名:" domain
if echo "$domains" | grep -qw "$domain"; then
~/.acme.sh/acme.sh --renew -d ${domain} --force
LOGI "已强制更新域名的证书:$domain"
else
echo "输入的域名无效。"
fi
fi
ssl_cert_issue_main
;;
4)
local domains=$(find /root/cert/ -mindepth 1 -maxdepth 1 -type d -exec basename {} \;)
if [ -z "$domains" ]; then
echo "未找到证书。"
else
echo "现有域名及其路径:"
for domain in $domains; do
local cert_path="/root/cert/${domain}/fullchain.pem"
local key_path="/root/cert/${domain}/privkey.pem"
if [[ -f "${cert_path}" && -f "${key_path}" ]]; then
echo -e "域名:${domain}"
echo -e "\t证书路径${cert_path}"
echo -e "\t私钥路径${key_path}"
else
echo -e "域名:${domain} - 证书或私钥文件缺失。"
fi
done
fi
ssl_cert_issue_main
;;
5)
local domains=$(find /root/cert/ -mindepth 1 -maxdepth 1 -type d -exec basename {} \;)
if [ -z "$domains" ]; then
echo "未找到证书。"
else
echo "可用域名:"
echo "$domains"
read -rp "请选择要为面板设置路径的域名:" domain
if echo "$domains" | grep -qw "$domain"; then
local webCertFile="/root/cert/${domain}/fullchain.pem"
local webKeyFile="/root/cert/${domain}/privkey.pem"
if [[ -f "${webCertFile}" && -f "${webKeyFile}" ]]; then
/usr/local/x-ui/x-ui cert -webCert "$webCertFile" -webCertKey "$webKeyFile"
echo "已为域名设置面板路径:$domain"
echo " - 证书文件:$webCertFile"
echo " - 私钥文件:$webKeyFile"
restart
else
echo "未找到域名的证书或私钥:$domain"
fi
else
echo "输入的域名无效。"
fi
fi
ssl_cert_issue_main
;;
*)
echo -e "${red}无效选项。请选择有效的数字。${plain}\n"
ssl_cert_issue_main
;; ;;
*) echo "无效选项" ;;
esac esac
} }
ssl_cert_issue() { ssl_cert_issue() {
# check for acme.sh first local existing_webBasePath=$(/usr/local/x-ui/x-ui setting -show true | grep -Eo 'webBasePath: .+' | awk '{print $2}')
local existing_port=$(/usr/local/x-ui/x-ui setting -show true | grep -Eo 'port: .+' | awk '{print $2}')
# 首先检查 acme.sh
if ! command -v ~/.acme.sh/acme.sh &>/dev/null; then if ! command -v ~/.acme.sh/acme.sh &>/dev/null; then
echo "未找到 acme.sh, 正在安装" echo "未找到 acme.sh,将进行安装"
install_acme install_acme
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
LOGE "安装 acme 失败,请检查日志" LOGE "安装 acme 失败,请检查日志"
exit 1 exit 1
fi fi
fi fi
# install socat second
# 安装 socat
case "${release}" in case "${release}" in
ubuntu | debian | armbian) ubuntu | debian | armbian)
apt update && apt install socat -y apt update && apt install socat -y
;; ;;
centos | almalinux | rocky | oracle) centos | rhel | almalinux | rocky | ol)
yum -y update && yum -y install socat yum -y update && yum -y install socat
;; ;;
fedora) fedora | amzn | virtuozzo)
dnf -y update && dnf -y install socat dnf -y update && dnf -y install socat
;; ;;
arch | manjaro) arch | manjaro | parch)
pacman -Sy --noconfirm socat pacman -Sy --noconfirm socat
;; ;;
*) *)
echo -e "${red}不支持的操作系统,请检查脚本并手动安装必要的软件包。${plain}\n" echo -e "${red}不支持的操作系统请检查脚本并手动安装必要的软件包。${plain}\n"
exit 1 exit 1
;; ;;
esac esac
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
LOGE "安装 socat 失败,请检查日志" LOGE "安装 socat 失败,请检查日志"
exit 1 exit 1
else else
LOGI "安装 socat 成功..." LOGI "安装 socat 成功..."
fi fi
# get the domain here,and we need verify it # 在这里获取域名,我们需要验证它
local domain="" local domain=""
read -p "请输入您的域名:" domain read -rp "请输入您的域名: " domain
LOGD "您的域名是:${domain},正在检查..." LOGD "您的域名是: ${domain}, 正在检查..."
# here we need to judge whether there exists cert already
local currentCert=$(~/.acme.sh/acme.sh --list | tail -1 | awk '{print $1}')
if [ ${currentCert} == ${domain} ]; then # 检查是否已存在证书
local certInfo=$(~/.acme.sh/acme.sh --list) local currentCert=$(~/.acme.sh/acme.sh --list | tail -1 | awk '{print $1}')
LOGE "系统已经有证书,无法再次颁发,当前证书详细信息:" if [ "${currentCert}" == "${domain}" ]; then
LOGI "$certInfo" local certInfo=$(~/.acme.sh/acme.sh --list)
echo "" LOGE "系统已存在此域名的证书。无法再次签发。当前证书详情:"
echo -e "${green}如果要申请安装证书并每3个月自动续签证书请确保${red} 80 ${green}${red}443 ${green}端口已打开放行${plain}" LOGI "$certInfo"
exit 1 exit 1
else else
LOGI "您的域现在已准备好颁发证书..." LOGI "您的域名现在可以签发证书了..."
fi fi
# create a directory for install cert # 为证书创建一个目录
certPath="/root/cert/${domain}" certPath="/root/cert/${domain}"
if [ ! -d "$certPath" ]; then if [ ! -d "$certPath" ]; then
mkdir -p "$certPath" mkdir -p "$certPath"
else else
rm -rf "$certPath" rm -rf "$certPath"
mkdir -p "$certPath" mkdir -p "$certPath"
fi fi
# get needed port here # 获取独立服务器的端口号
local WebPort=80 local WebPort=80
read -p "请选择您使用的端口,默认为 80 端口:" WebPort read -rp "请选择要使用的端口 (默认为 80): " WebPort
if [[ ${WebPort} -gt 65535 || ${WebPort} -lt 1 ]]; then if [[ ${WebPort} -gt 65535 || ${WebPort} -lt 1 ]]; then
LOGE "您输入的端口 ${WebPort} 无效,将使用默认端口" LOGE "您输入的 ${WebPort} 无效,将使用默认端口 80。"
fi WebPort=80
LOGI "将使用端口:${WebPort} 来颁发证书,请确保该端口已开启..." fi
# NOTE:This should be handled by user LOGI "将使用端口: ${WebPort} 来签发证书。请确保此端口已开放。"
# open the port and kill the occupied progress
~/.acme.sh/acme.sh --set-default-ca --server letsencrypt
~/.acme.sh/acme.sh --issue -d ${domain} --listen-v6 --standalone --httpport ${WebPort}
if [ $? -ne 0 ]; then
LOGE "颁发证书失败,请检查日志"
rm -rf ~/.acme.sh/${domain}
exit 1
else
LOGE "颁发证书成功,安装证书..."
fi
# install cert
~/.acme.sh/acme.sh --installcert -d ${domain} \
--key-file /root/cert/${domain}/privkey.pem \
--fullchain-file /root/cert/${domain}/fullchain.pem
if [ $? -ne 0 ]; then # 签发证书
LOGE "安装证书失败" ~/.acme.sh/acme.sh --set-default-ca --server letsencrypt
rm -rf ~/.acme.sh/${domain} ~/.acme.sh/acme.sh --issue -d ${domain} --listen-v6 --standalone --httpport ${WebPort} --force
exit 1 if [ $? -ne 0 ]; then
else LOGE "签发证书失败,请检查日志。"
LOGI "安装证书成功,启用自动续订..." rm -rf ~/.acme.sh/${domain}
echo "" exit 1
echo -e "${green}如果要申请安装证书并每3个月自动续签证书请确保${red} 80 ${green}${red}443 ${green}端口已打开放行${plain}" else
fi LOGE "签发证书成功,正在安装证书..."
fi
~/.acme.sh/acme.sh --upgrade --auto-upgrade reloadCmd="x-ui restart"
if [ $? -ne 0 ]; then
LOGE "自动续订失败,证书详细信息:"
ls -lah cert/*
chmod 755 $certPath/*
exit 1
else
LOGI "自动续订成功,证书详细信息:"
ls -lah cert/*
chmod 755 $certPath/*
echo ""
echo -e "${green}如果要申请安装证书并每3个月自动续签证书请确保${red} 80 ${green}${red}443 ${green}端口已打开放行${plain}"
fi
}
LOGI "ACME 的默认 --reloadcmd 是: ${yellow}x-ui restart"
LOGI "此命令将在每次证书签发和续订时运行。"
read -rp "您想修改 ACME 的 --reloadcmd 吗? (y/n): " setReloadcmd
if [[ "$setReloadcmd" == "y" || "$setReloadcmd" == "Y" ]]; then
echo -e "\n${green}\t1.${plain} 预设: systemctl reload nginx ; x-ui restart"
echo -e "${green}\t2.${plain} 输入您自己的命令"
echo -e "${green}\t0.${plain} 保留默认的 reloadcmd"
read -rp "请选择一个选项: " choice
case "$choice" in
1)
LOGI "Reloadcmd 是: systemctl reload nginx ; x-ui restart"
reloadCmd="systemctl reload nginx ; x-ui restart"
;;
2)
LOGD "建议将 x-ui restart 放在末尾,这样如果其他服务失败,它不会引发错误"
read -rp "请输入您的 reloadcmd (例如: systemctl reload nginx ; x-ui restart): " reloadCmd
LOGI "您的 reloadcmd 是: ${reloadCmd}"
;;
*)
LOGI "保留默认的 reloadcmd"
;;
esac
fi
# 安装证书
~/.acme.sh/acme.sh --installcert -d ${domain} \
--key-file /root/cert/${domain}/privkey.pem \
--fullchain-file /root/cert/${domain}/fullchain.pem --reloadcmd "${reloadCmd}"
if [ $? -ne 0 ]; then
LOGE "安装证书失败,正在退出。"
rm -rf ~/.acme.sh/${domain}
exit 1
else
LOGI "安装证书成功,正在启用自动续订..."
fi
# 启用自动续订
~/.acme.sh/acme.sh --upgrade --auto-upgrade
if [ $? -ne 0 ]; then
LOGE "自动续订失败,证书详情:"
ls -lah cert/*
chmod 755 $certPath/*
exit 1
else
LOGI "自动续订成功,证书详情:"
ls -lah cert/*
chmod 755 $certPath/*
fi
# 成功安装证书后提示用户设置面板路径
read -rp "您想为面板设置此证书吗? (y/n): " setPanel
if [[ "$setPanel" == "y" || "$setPanel" == "Y" ]]; then
local webCertFile="/root/cert/${domain}/fullchain.pem"
local webKeyFile="/root/cert/${domain}/privkey.pem"
if [[ -f "$webCertFile" && -f "$webKeyFile" ]]; then
/usr/local/x-ui/x-ui cert -webCert "$webCertFile" -webCertKey "$webKeyFile"
LOGI "已为域名设置面板路径: $domain"
LOGI " - 证书文件: $webCertFile"
LOGI " - 私钥文件: $webKeyFile"
echo -e "${green}访问 URL: https://${domain}:${existing_port}${existing_webBasePath}${plain}"
restart
else
LOGE "错误:未找到域名的证书或私钥文件: $domain"
fi
else
LOGI "跳过面板路径设置。"
fi
}
ssl_cert_issue_CF() { ssl_cert_issue_CF() {
echo -E "" local existing_webBasePath=$(/usr/local/x-ui/x-ui setting -show true | grep -Eo 'webBasePath: .+' | awk '{print $2}')
LOGD "******使用说明******" local existing_port=$(/usr/local/x-ui/x-ui setting -show true | grep -Eo 'port: .+' | awk '{print $2}')
LOGI "此 Acme 脚本需要以下数据:" LOGI "****** 使用说明 ******"
LOGI "1. Cloudflare 注册邮箱" LOGI "请按照以下步骤完成操作:"
LOGI "2. Cloudflare 全局 API 密钥" LOGI "1. 准备好在 Cloudflare 注册的电子邮箱。"
LOGI "3. Cloudflare 已解析 dns 到当前服务器的域名" LOGI "2. 准备好 Cloudflare Global API 密钥。"
LOGI "4. 脚本申请证书,默认安装路径为 /root/cert " LOGI "3. 准备好域名。"
confirm "确认申请? [y/n]" "y" LOGI "4. 证书颁发后,系统将提示您为面板设置证书(可选)。"
if [ $? -eq 0 ]; then LOGI "5. 安装后,脚本还支持自动续订 SSL 证书。"
# check for acme.sh first
if ! command -v ~/.acme.sh/acme.sh &>/dev/null; then confirm "您确认信息并希望继续吗?[y/n]" "y"
echo "未找到 acme.sh, 正在安装"
install_acme if [ $? -eq 0 ]; then
if [ $? -ne 0 ]; then # 首先检查 acme.sh
LOGE "安装 acme 失败,请检查日志" if ! command -v ~/.acme.sh/acme.sh &>/dev/null; then
exit 1 echo "未找到 acme.sh。我们将为您安装。"
fi install_acme
fi if [ $? -ne 0 ]; then
CF_Domain="" LOGE "安装 acme 失败,请检查日志。"
CF_GlobalKey="" exit 1
CF_AccountEmail="" fi
certPath=/root/cert fi
if [ ! -d "$certPath" ]; then
mkdir $certPath CF_Domain=""
else
rm -rf $certPath LOGD "请设置一个域名:"
mkdir $certPath read -rp "在此输入您的域名: " CF_Domain
fi LOGD "您的域名设置为:${CF_Domain}"
LOGD "请设置域名:"
read -p "在此输入您的域名:" CF_Domain # 设置 Cloudflare API 详细信息
LOGD "您的域名为: ${CF_Domain}" CF_GlobalKey=""
LOGD "请设置 CF Global API Key:" CF_AccountEmail=""
read -p "在此输入您的 API Key:" CF_GlobalKey LOGD "请设置 API 密钥:"
LOGD "您的 API 密钥是: ${CF_GlobalKey}" read -rp "在此输入您的密钥: " CF_GlobalKey
LOGD "请设置注册邮箱:" LOGD "您的 API 密钥是:${CF_GlobalKey}"
read -p "在此输入您的邮箱:" CF_AccountEmail
LOGD "您的账号邮箱地址是: ${CF_AccountEmail}" LOGD "请设置注册的电子邮箱:"
~/.acme.sh/acme.sh --set-default-ca --server letsencrypt read -rp "在此输入您的电子邮箱: " CF_AccountEmail
if [ $? -ne 0 ]; then LOGD "您注册的电子邮箱地址是:${CF_AccountEmail}"
LOGE "默认 CA: Lets'Encrypt 失败,脚本退出..."
exit 1 # 将默认 CA 设置为 Let's Encrypt
fi ~/.acme.sh/acme.sh --set-default-ca --server letsencrypt
export CF_Key="${CF_GlobalKey}" if [ $? -ne 0 ]; then
export CF_Email=${CF_AccountEmail} LOGE "设置默认 CA 为 Let's Encrypt 失败,脚本正在退出..."
~/.acme.sh/acme.sh --issue --dns dns_cf -d ${CF_Domain} -d *.${CF_Domain} --log exit 1
if [ $? -ne 0 ]; then fi
LOGE "证书颁发失败,脚本退出..."
exit 1 export CF_Key="${CF_GlobalKey}"
else export CF_Email="${CF_AccountEmail}"
LOGI "证书颁发成功,正在安装..."
fi # 使用 Cloudflare DNS 颁发证书
~/.acme.sh/acme.sh --installcert -d ${CF_Domain} -d *.${CF_Domain} --ca-file /root/cert/ca.cer \ ~/.acme.sh/acme.sh --issue --dns dns_cf -d ${CF_Domain} -d *.${CF_Domain} --log --force
--cert-file /root/cert/${CF_Domain}.cer --key-file /root/cert/${CF_Domain}.key \ if [ $? -ne 0 ]; then
--fullchain-file /root/cert/fullchain.cer LOGE "证书颁发失败,脚本正在退出..."
if [ $? -ne 0 ]; then exit 1
LOGE "证书安装失败,脚本退出..." else
exit 1 LOGI "证书颁发成功,正在安装..."
else fi
LOGI "证书安装成功,开启自动更新..." # 安装证书
echo "" certPath="/root/cert/${CF_Domain}"
echo -e "${green}如果要申请安装证书并每3个月自动续签证书请确保${red} 80 ${green}${red}443 ${green}端口已打开放行${plain}" if [ -d "$certPath" ]; then
fi rm -rf ${certPath}
~/.acme.sh/acme.sh --upgrade --auto-upgrade fi
if [ $? -ne 0 ]; then
LOGE "自动更新设置失败,脚本退出..." mkdir -p ${certPath}
ls -lah cert if [ $? -ne 0 ]; then
chmod 755 $certPath LOGE "创建目录失败: ${certPath}"
exit 1 exit 1
else fi
LOGI "证书已安装并开启自动续订,具体信息如下:"
ls -lah cert reloadCmd="x-ui restart"
chmod 755 $certPath
echo "" LOGI "ACME 的默认 --reloadcmd 是: ${yellow}x-ui restart"
echo -e "${green}如果要申请安装证书并每3个月自动续签证书请确保${red} 80 ${green}${red}443 ${green}端口已打开放行${plain}" LOGI "此命令将在每次证书颁发和续订时运行。"
fi read -rp "您想修改 ACME 的 --reloadcmd 吗? (y/n): " setReloadcmd
else if [[ "$setReloadcmd" == "y" || "$setReloadcmd" == "Y" ]]; then
show_menu echo -e "\n${green}\t1.${plain} 预设: systemctl reload nginx ; x-ui restart"
fi echo -e "${green}\t2.${plain} 输入您自己的命令"
} echo -e "${green}\t0.${plain} 保留默认的 reloadcmd"
read -rp "请选择一个选项: " choice
case "$choice" in
1)
LOGI "Reloadcmd 是: systemctl reload nginx ; x-ui restart"
reloadCmd="systemctl reload nginx ; x-ui restart"
;;
2)
LOGD "建议将 x-ui restart 放在末尾,这样如果其他服务失败,它不会引发错误"
read -rp "请输入您的 reloadcmd (例如: systemctl reload nginx ; x-ui restart): " reloadCmd
LOGI "您的 reloadcmd 是: ${reloadCmd}"
;;
*)
LOGI "保留默认的 reloadcmd"
;;
esac
fi
~/.acme.sh/acme.sh --installcert -d ${CF_Domain} -d *.${CF_Domain} \
--key-file ${certPath}/privkey.pem \
--fullchain-file ${certPath}/fullchain.pem --reloadcmd "${reloadCmd}"
if [ $? -ne 0 ]; then
LOGE "证书安装失败,脚本正在退出..."
exit 1
else
LOGI "证书安装成功,正在开启自动更新..."
fi
# 启用自动更新
~/.acme.sh/acme.sh --upgrade --auto-upgrade
if [ $? -ne 0 ]; then
LOGE "自动更新设置失败,脚本正在退出..."
exit 1
else
LOGI "证书已安装并开启自动续订。具体信息如下:"
ls -lah ${certPath}/*
chmod 755 ${certPath}/*
fi
# 成功安装证书后提示用户设置面板路径
read -rp "您想为面板设置此证书吗? (y/n): " setPanel
if [[ "$setPanel" == "y" || "$setPanel" == "Y" ]]; then
local webCertFile="${certPath}/fullchain.pem"
local webKeyFile="${certPath}/privkey.pem"
if [[ -f "$webCertFile" && -f "$webKeyFile" ]]; then
/usr/local/x-ui/x-ui cert -webCert "$webCertFile" -webCertKey "$webKeyFile"
LOGI "已为域名设置面板路径: $CF_Domain"
LOGI " - 证书文件: $webCertFile"
LOGI " - 私钥文件: $webKeyFile"
echo -e "${green}访问 URL: https://${CF_Domain}:${existing_port}${existing_webBasePath}${plain}"
restart
else
LOGE "错误:未找到域名的证书或私钥文件: $CF_Domain"
fi
else
LOGI "跳过面板路径设置。"
fi
else
show_menu
fi
}
warp_cloudflare() { warp_cloudflare() {
echo -e "${green}\t1.${plain} 安装 WARP socks5 代理" echo -e "${green}\t1.${plain} 安装 WARP socks5 代理"