mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-09-24 18:56:36 +08:00
fix(ssl): clean ECC state, guard cert reuse, register renew hook (#4875)
- Cleanup on issuance/install failure now also removes the acme.sh
${domain}_ecc (and ${ip}_ecc) directory, not just ${domain}, so a
failed run no longer leaves partial state behind.
- The 'existing certificate' check only reuses a cert when its
fullchain.cer and key files are actually present and non-empty;
otherwise the broken state is removed and issuance proceeds. This
fixes the 0-byte fullchain.pem produced by reusing failed state.
- Menu option 5 (set cert paths) now registers the acme.sh --installcert
hook with --reloadcmd 'x-ui restart' when acme.sh knows the domain, so
auto-renewal copies the renewed cert and reloads the panel.
This commit is contained in:
@@ -1269,6 +1269,16 @@ ssl_cert_issue_main() {
|
||||
echo "Panel paths set for domain: $domain"
|
||||
echo " - Certificate File: $webCertFile"
|
||||
echo " - Private Key File: $webKeyFile"
|
||||
# Register the acme.sh install-cert hook so auto-renewal copies the
|
||||
# renewed cert to these paths and reloads the panel. Without it acme.sh
|
||||
# renews but never updates /root/cert, silently serving a stale cert.
|
||||
if command -v ~/.acme.sh/acme.sh &> /dev/null && ~/.acme.sh/acme.sh --list 2> /dev/null | awk '{print $1}' | grep -Fxq "${domain}"; then
|
||||
~/.acme.sh/acme.sh --installcert -d "${domain}" \
|
||||
--key-file "${webKeyFile}" \
|
||||
--fullchain-file "${webCertFile}" \
|
||||
--reloadcmd "x-ui restart" 2>&1 || true
|
||||
echo "Registered acme.sh auto-renewal hook for ${domain}."
|
||||
fi
|
||||
restart
|
||||
else
|
||||
echo "Certificate or private key not found for domain: $domain."
|
||||
@@ -1448,8 +1458,8 @@ ssl_cert_issue_for_ip() {
|
||||
LOGE "Failed to issue certificate for IP: ${server_ip}"
|
||||
LOGE "Make sure port ${WebPort} is open and the server is accessible from the internet"
|
||||
# Cleanup acme.sh data for both IPv4 and IPv6 if specified
|
||||
rm -rf ~/.acme.sh/${server_ip} 2> /dev/null
|
||||
[[ -n "$ipv6_addr" ]] && rm -rf ~/.acme.sh/${ipv6_addr} 2> /dev/null
|
||||
rm -rf ~/.acme.sh/${server_ip} ~/.acme.sh/${server_ip}_ecc 2> /dev/null
|
||||
[[ -n "$ipv6_addr" ]] && rm -rf ~/.acme.sh/${ipv6_addr} ~/.acme.sh/${ipv6_addr}_ecc 2> /dev/null
|
||||
rm -rf ${certPath} 2> /dev/null
|
||||
return 1
|
||||
else
|
||||
@@ -1468,8 +1478,8 @@ ssl_cert_issue_for_ip() {
|
||||
if [[ ! -f "${certPath}/fullchain.pem" || ! -f "${certPath}/privkey.pem" ]]; then
|
||||
LOGE "Certificate files not found after installation"
|
||||
# Cleanup acme.sh data for both IPv4 and IPv6 if specified
|
||||
rm -rf ~/.acme.sh/${server_ip} 2> /dev/null
|
||||
[[ -n "$ipv6_addr" ]] && rm -rf ~/.acme.sh/${ipv6_addr} 2> /dev/null
|
||||
rm -rf ~/.acme.sh/${server_ip} ~/.acme.sh/${server_ip}_ecc 2> /dev/null
|
||||
[[ -n "$ipv6_addr" ]] && rm -rf ~/.acme.sh/${ipv6_addr} ~/.acme.sh/${ipv6_addr}_ecc 2> /dev/null
|
||||
rm -rf ${certPath} 2> /dev/null
|
||||
return 1
|
||||
fi
|
||||
@@ -1576,14 +1586,30 @@ ssl_cert_issue() {
|
||||
LOGD "Your domain is: ${domain}, checking it..."
|
||||
SSL_ISSUED_DOMAIN="${domain}"
|
||||
|
||||
# detect existing certificate and reuse it if present
|
||||
# detect existing certificate and reuse it only if its files are actually
|
||||
# present and non-empty. acme.sh stores ECC certs under ${domain}_ecc and RSA
|
||||
# certs under ${domain}; a failed issuance can leave a domain entry in --list
|
||||
# with no usable cert files, which must not be reused (it produces a 0-byte
|
||||
# fullchain.pem). Broken partial state is cleaned up so issuance can proceed.
|
||||
local cert_exists=0
|
||||
if ~/.acme.sh/acme.sh --list 2> /dev/null | awk '{print $1}' | grep -Fxq "${domain}"; then
|
||||
cert_exists=1
|
||||
local certInfo=$(~/.acme.sh/acme.sh --list 2> /dev/null | grep -F "${domain}")
|
||||
LOGI "Existing certificate found for ${domain}, will reuse it."
|
||||
[[ -n "${certInfo}" ]] && LOGI "${certInfo}"
|
||||
else
|
||||
local acmeCertDir=""
|
||||
if [[ -s ~/.acme.sh/${domain}_ecc/fullchain.cer && -s ~/.acme.sh/${domain}_ecc/${domain}.key ]]; then
|
||||
acmeCertDir=~/.acme.sh/${domain}_ecc
|
||||
elif [[ -s ~/.acme.sh/${domain}/fullchain.cer && -s ~/.acme.sh/${domain}/${domain}.key ]]; then
|
||||
acmeCertDir=~/.acme.sh/${domain}
|
||||
fi
|
||||
if [[ -n "${acmeCertDir}" ]]; then
|
||||
cert_exists=1
|
||||
local certInfo=$(~/.acme.sh/acme.sh --list 2> /dev/null | grep -F "${domain}")
|
||||
LOGI "Existing certificate found for ${domain}, will reuse it."
|
||||
[[ -n "${certInfo}" ]] && LOGI "${certInfo}"
|
||||
else
|
||||
LOGW "Found incomplete acme.sh state for ${domain} (no valid certificate files); cleaning it up and re-issuing."
|
||||
rm -rf ~/.acme.sh/${domain} ~/.acme.sh/${domain}_ecc
|
||||
fi
|
||||
fi
|
||||
if [[ ${cert_exists} -eq 0 ]]; then
|
||||
LOGI "Your domain is ready for issuing certificates now..."
|
||||
fi
|
||||
|
||||
@@ -1611,7 +1637,7 @@ ssl_cert_issue() {
|
||||
~/.acme.sh/acme.sh --issue -d ${domain} --listen-v6 --standalone --httpport ${WebPort} --force
|
||||
if [ $? -ne 0 ]; then
|
||||
LOGE "Issuing certificate failed, please check logs."
|
||||
rm -rf ~/.acme.sh/${domain}
|
||||
rm -rf ~/.acme.sh/${domain} ~/.acme.sh/${domain}_ecc
|
||||
exit 1
|
||||
else
|
||||
LOGE "Issuing certificate succeeded, installing certificates..."
|
||||
@@ -1664,7 +1690,7 @@ ssl_cert_issue() {
|
||||
else
|
||||
LOGE "Installing certificate failed, exiting."
|
||||
if [[ ${cert_exists} -eq 0 ]]; then
|
||||
rm -rf ~/.acme.sh/${domain}
|
||||
rm -rf ~/.acme.sh/${domain} ~/.acme.sh/${domain}_ecc
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user