Przeglądaj źródła

Fix SSL domain setup on reinstall: reuse existing certs and avoid false success/failure logs (#4004)

* perf: replace /dev/urandom | tr with openssl rand to fix CPU spike

* fix: add cron to default package installation and improve SSL certificate handling

* Reworked `--installcert` success criteria, cleanup behavior adjusted.
Yunheng Liu 3 dni temu
rodzic
commit
e02f78ac68
3 zmienionych plików z 156 dodań i 99 usunięć
  1. 59 38
      install.sh
  2. 60 39
      update.sh
  3. 37 22
      x-ui.sh

+ 59 - 38
install.sh

@@ -79,26 +79,26 @@ install_base() {
             apt-get update && apt-get install -y -q cron curl tar tzdata socat ca-certificates openssl
             apt-get update && apt-get install -y -q cron curl tar tzdata socat ca-certificates openssl
         ;;
         ;;
         fedora | amzn | virtuozzo | rhel | almalinux | rocky | ol)
         fedora | amzn | virtuozzo | rhel | almalinux | rocky | ol)
-            dnf -y update && dnf install -y -q curl tar tzdata socat ca-certificates openssl
+            dnf -y update && dnf install -y -q cronie curl tar tzdata socat ca-certificates openssl
         ;;
         ;;
         centos)
         centos)
             if [[ "${VERSION_ID}" =~ ^7 ]]; then
             if [[ "${VERSION_ID}" =~ ^7 ]]; then
-                yum -y update && yum install -y curl tar tzdata socat ca-certificates openssl
+                yum -y update && yum install -y cronie curl tar tzdata socat ca-certificates openssl
             else
             else
-                dnf -y update && dnf install -y -q curl tar tzdata socat ca-certificates openssl
+                dnf -y update && dnf install -y -q cronie curl tar tzdata socat ca-certificates openssl
             fi
             fi
         ;;
         ;;
         arch | manjaro | parch)
         arch | manjaro | parch)
-            pacman -Syu && pacman -Syu --noconfirm curl tar tzdata socat ca-certificates openssl
+            pacman -Syu && pacman -Syu --noconfirm cronie curl tar tzdata socat ca-certificates openssl
         ;;
         ;;
         opensuse-tumbleweed | opensuse-leap)
         opensuse-tumbleweed | opensuse-leap)
-            zypper refresh && zypper -q install -y curl tar timezone socat ca-certificates openssl
+            zypper refresh && zypper -q install -y cron curl tar timezone socat ca-certificates openssl
         ;;
         ;;
         alpine)
         alpine)
-            apk update && apk add curl tar tzdata socat ca-certificates openssl
+            apk update && apk add dcron curl tar tzdata socat ca-certificates openssl
         ;;
         ;;
         *)
         *)
-            apt-get update && apt-get install -y -q curl tar tzdata socat ca-certificates openssl
+            apt-get update && apt-get install -y -q cron curl tar tzdata socat ca-certificates openssl
         ;;
         ;;
     esac
     esac
 }
 }
@@ -379,15 +379,15 @@ ssl_cert_issue() {
         break
         break
     done
     done
     echo -e "${green}Your domain is: ${domain}, checking it...${plain}"
     echo -e "${green}Your domain is: ${domain}, checking it...${plain}"
-
-    # check if there already exists a certificate
-    local currentCert=$(~/.acme.sh/acme.sh --list | tail -1 | awk '{print $1}')
-    if [ "${currentCert}" == "${domain}" ]; then
-        local certInfo=$(~/.acme.sh/acme.sh --list)
-        echo -e "${red}System already has certificates for this domain. Cannot issue again.${plain}"
-        echo -e "${yellow}Current certificate details:${plain}"
-        echo "$certInfo"
-        return 1
+    SSL_ISSUED_DOMAIN="${domain}"
+
+    # detect existing certificate and reuse it if present
+    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}")
+        echo -e "${yellow}Existing certificate found for ${domain}, will reuse it.${plain}"
+        [[ -n "${certInfo}" ]] && echo "$certInfo"
     else
     else
         echo -e "${green}Your domain is ready for issuing certificates now...${plain}"
         echo -e "${green}Your domain is ready for issuing certificates now...${plain}"
     fi
     fi
@@ -414,16 +414,20 @@ ssl_cert_issue() {
     echo -e "${yellow}Stopping panel temporarily...${plain}"
     echo -e "${yellow}Stopping panel temporarily...${plain}"
     systemctl stop x-ui 2>/dev/null || rc-service x-ui stop 2>/dev/null
     systemctl stop x-ui 2>/dev/null || rc-service x-ui stop 2>/dev/null
 
 
-    # issue the certificate
-    ~/.acme.sh/acme.sh --set-default-ca --server letsencrypt --force
-    ~/.acme.sh/acme.sh --issue -d ${domain} --listen-v6 --standalone --httpport ${WebPort} --force
-    if [ $? -ne 0 ]; then
-        echo -e "${red}Issuing certificate failed, please check logs.${plain}"
-        rm -rf ~/.acme.sh/${domain}
-        systemctl start x-ui 2>/dev/null || rc-service x-ui start 2>/dev/null
-        return 1
+    if [[ ${cert_exists} -eq 0 ]]; then
+        # issue the certificate
+        ~/.acme.sh/acme.sh --set-default-ca --server letsencrypt --force
+        ~/.acme.sh/acme.sh --issue -d ${domain} --listen-v6 --standalone --httpport ${WebPort} --force
+        if [ $? -ne 0 ]; then
+            echo -e "${red}Issuing certificate failed, please check logs.${plain}"
+            rm -rf ~/.acme.sh/${domain}
+            systemctl start x-ui 2>/dev/null || rc-service x-ui start 2>/dev/null
+            return 1
+        else
+            echo -e "${green}Issuing certificate succeeded, installing certificates...${plain}"
+        fi
     else
     else
-        echo -e "${green}Issuing certificate succeeded, installing certificates...${plain}"
+        echo -e "${green}Using existing certificate, installing certificates...${plain}"
     fi
     fi
 
 
     # Setup reload command
     # Setup reload command
@@ -453,17 +457,27 @@ ssl_cert_issue() {
     fi
     fi
 
 
     # install the certificate
     # install the certificate
-    ~/.acme.sh/acme.sh --installcert -d ${domain} \
+    local installOutput=""
+    installOutput=$(~/.acme.sh/acme.sh --installcert -d ${domain} \
         --key-file /root/cert/${domain}/privkey.pem \
         --key-file /root/cert/${domain}/privkey.pem \
-        --fullchain-file /root/cert/${domain}/fullchain.pem --reloadcmd "${reloadCmd}"
+        --fullchain-file /root/cert/${domain}/fullchain.pem --reloadcmd "${reloadCmd}" 2>&1)
+    local installRc=$?
+    echo "${installOutput}"
 
 
-    if [ $? -ne 0 ]; then
+    local installWroteFiles=0
+    if echo "${installOutput}" | grep -q "Installing key to:" && echo "${installOutput}" | grep -q "Installing full chain to:"; then
+        installWroteFiles=1
+    fi
+
+    if [[ -f "/root/cert/${domain}/privkey.pem" && -f "/root/cert/${domain}/fullchain.pem" && ( ${installRc} -eq 0 || ${installWroteFiles} -eq 1 ) ]]; then
+        echo -e "${green}Installing certificate succeeded, enabling auto renew...${plain}"
+    else
         echo -e "${red}Installing certificate failed, exiting.${plain}"
         echo -e "${red}Installing certificate failed, exiting.${plain}"
-        rm -rf ~/.acme.sh/${domain}
+        if [[ ${cert_exists} -eq 0 ]]; then
+            rm -rf ~/.acme.sh/${domain}
+        fi
         systemctl start x-ui 2>/dev/null || rc-service x-ui start 2>/dev/null
         systemctl start x-ui 2>/dev/null || rc-service x-ui start 2>/dev/null
         return 1
         return 1
-    else
-        echo -e "${green}Installing certificate succeeded, enabling auto renew...${plain}"
     fi
     fi
 
 
     # enable auto-renew
     # enable auto-renew
@@ -536,14 +550,21 @@ prompt_and_setup_ssl() {
     1)
     1)
         # User chose Let's Encrypt domain option
         # User chose Let's Encrypt domain option
         echo -e "${green}Using Let's Encrypt for domain certificate...${plain}"
         echo -e "${green}Using Let's Encrypt for domain certificate...${plain}"
-        ssl_cert_issue
-        # Extract the domain that was used from the certificate
-        local cert_domain=$(~/.acme.sh/acme.sh --list 2>/dev/null | tail -1 | awk '{print $1}')
-        if [[ -n "${cert_domain}" ]]; then
-            SSL_HOST="${cert_domain}"
-            echo -e "${green}✓ SSL certificate configured successfully with domain: ${cert_domain}${plain}"
+        if ssl_cert_issue; then
+            local cert_domain="${SSL_ISSUED_DOMAIN}"
+            if [[ -z "${cert_domain}" ]]; then
+                cert_domain=$(~/.acme.sh/acme.sh --list 2>/dev/null | tail -1 | awk '{print $1}')
+            fi
+
+            if [[ -n "${cert_domain}" ]]; then
+                SSL_HOST="${cert_domain}"
+                echo -e "${green}✓ SSL certificate configured successfully with domain: ${cert_domain}${plain}"
+            else
+                echo -e "${yellow}SSL setup may have completed, but domain extraction failed${plain}"
+                SSL_HOST="${server_ip}"
+            fi
         else
         else
-            echo -e "${yellow}SSL setup may have completed, but domain extraction failed${plain}"
+            echo -e "${red}SSL certificate setup failed for domain mode.${plain}"
             SSL_HOST="${server_ip}"
             SSL_HOST="${server_ip}"
         fi
         fi
         ;;
         ;;

+ 60 - 39
update.sh

@@ -109,29 +109,29 @@ install_base() {
     echo -e "${green}Updating and install dependency packages...${plain}"
     echo -e "${green}Updating and install dependency packages...${plain}"
     case "${release}" in
     case "${release}" in
         ubuntu | debian | armbian)
         ubuntu | debian | armbian)
-            apt-get update >/dev/null 2>&1 && apt-get install -y -q curl tar tzdata socat openssl >/dev/null 2>&1
+            apt-get update >/dev/null 2>&1 && apt-get install -y -q cron curl tar tzdata socat openssl >/dev/null 2>&1
         ;;
         ;;
         fedora | amzn | virtuozzo | rhel | almalinux | rocky | ol)
         fedora | amzn | virtuozzo | rhel | almalinux | rocky | ol)
-            dnf -y update >/dev/null 2>&1 && dnf install -y -q curl tar tzdata socat openssl >/dev/null 2>&1
+            dnf -y update >/dev/null 2>&1 && dnf install -y -q cronie curl tar tzdata socat openssl >/dev/null 2>&1
         ;;
         ;;
         centos)
         centos)
             if [[ "${VERSION_ID}" =~ ^7 ]]; then
             if [[ "${VERSION_ID}" =~ ^7 ]]; then
-                yum -y update >/dev/null 2>&1 && yum install -y -q curl tar tzdata socat openssl >/dev/null 2>&1
+                yum -y update >/dev/null 2>&1 && yum install -y -q cronie curl tar tzdata socat openssl >/dev/null 2>&1
             else
             else
-                dnf -y update >/dev/null 2>&1 && dnf install -y -q curl tar tzdata socat openssl >/dev/null 2>&1
+                dnf -y update >/dev/null 2>&1 && dnf install -y -q cronie curl tar tzdata socat openssl >/dev/null 2>&1
             fi
             fi
         ;;
         ;;
         arch | manjaro | parch)
         arch | manjaro | parch)
-            pacman -Syu >/dev/null 2>&1 && pacman -Syu --noconfirm curl tar tzdata socat openssl >/dev/null 2>&1
+            pacman -Syu >/dev/null 2>&1 && pacman -Syu --noconfirm cronie curl tar tzdata socat openssl >/dev/null 2>&1
         ;;
         ;;
         opensuse-tumbleweed | opensuse-leap)
         opensuse-tumbleweed | opensuse-leap)
-            zypper refresh >/dev/null 2>&1 && zypper -q install -y curl tar timezone socat openssl >/dev/null 2>&1
+            zypper refresh >/dev/null 2>&1 && zypper -q install -y cron curl tar timezone socat openssl >/dev/null 2>&1
         ;;
         ;;
         alpine)
         alpine)
-            apk update >/dev/null 2>&1 && apk add curl tar tzdata socat openssl>/dev/null 2>&1
+            apk update >/dev/null 2>&1 && apk add dcron curl tar tzdata socat openssl>/dev/null 2>&1
         ;;
         ;;
         *)
         *)
-            apt-get update >/dev/null 2>&1 && apt install -y -q curl tar tzdata socat openssl >/dev/null 2>&1
+            apt-get update >/dev/null 2>&1 && apt install -y -q cron curl tar tzdata socat openssl >/dev/null 2>&1
         ;;
         ;;
     esac
     esac
 }
 }
@@ -402,15 +402,15 @@ ssl_cert_issue() {
         break
         break
     done
     done
     echo -e "${green}Your domain is: ${domain}, checking it...${plain}"
     echo -e "${green}Your domain is: ${domain}, checking it...${plain}"
-
-    # check if there already exists a certificate
-    local currentCert=$(~/.acme.sh/acme.sh --list | tail -1 | awk '{print $1}')
-    if [ "${currentCert}" == "${domain}" ]; then
-        local certInfo=$(~/.acme.sh/acme.sh --list)
-        echo -e "${red}System already has certificates for this domain. Cannot issue again.${plain}"
-        echo -e "${yellow}Current certificate details:${plain}"
-        echo "$certInfo"
-        return 1
+    SSL_ISSUED_DOMAIN="${domain}"
+
+    # detect existing certificate and reuse it if present
+    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}")
+        echo -e "${yellow}Existing certificate found for ${domain}, will reuse it.${plain}"
+        [[ -n "${certInfo}" ]] && echo "$certInfo"
     else
     else
         echo -e "${green}Your domain is ready for issuing certificates now...${plain}"
         echo -e "${green}Your domain is ready for issuing certificates now...${plain}"
     fi
     fi
@@ -437,16 +437,20 @@ ssl_cert_issue() {
     echo -e "${yellow}Stopping panel temporarily...${plain}"
     echo -e "${yellow}Stopping panel temporarily...${plain}"
     systemctl stop x-ui 2>/dev/null || rc-service x-ui stop 2>/dev/null
     systemctl stop x-ui 2>/dev/null || rc-service x-ui stop 2>/dev/null
 
 
-    # issue the certificate
-    ~/.acme.sh/acme.sh --set-default-ca --server letsencrypt --force
-    ~/.acme.sh/acme.sh --issue -d ${domain} --listen-v6 --standalone --httpport ${WebPort} --force
-    if [ $? -ne 0 ]; then
-        echo -e "${red}Issuing certificate failed, please check logs.${plain}"
-        rm -rf ~/.acme.sh/${domain}
-        systemctl start x-ui 2>/dev/null || rc-service x-ui start 2>/dev/null
-        return 1
+    if [[ ${cert_exists} -eq 0 ]]; then
+        # issue the certificate
+        ~/.acme.sh/acme.sh --set-default-ca --server letsencrypt --force
+        ~/.acme.sh/acme.sh --issue -d ${domain} --listen-v6 --standalone --httpport ${WebPort} --force
+        if [ $? -ne 0 ]; then
+            echo -e "${red}Issuing certificate failed, please check logs.${plain}"
+            rm -rf ~/.acme.sh/${domain}
+            systemctl start x-ui 2>/dev/null || rc-service x-ui start 2>/dev/null
+            return 1
+        else
+            echo -e "${green}Issuing certificate succeeded, installing certificates...${plain}"
+        fi
     else
     else
-        echo -e "${green}Issuing certificate succeeded, installing certificates...${plain}"
+        echo -e "${green}Using existing certificate, installing certificates...${plain}"
     fi
     fi
 
 
     # Setup reload command
     # Setup reload command
@@ -476,17 +480,27 @@ ssl_cert_issue() {
     fi
     fi
 
 
     # install the certificate
     # install the certificate
-    ~/.acme.sh/acme.sh --installcert -d ${domain} \
+    local installOutput=""
+    installOutput=$(~/.acme.sh/acme.sh --installcert -d ${domain} \
         --key-file /root/cert/${domain}/privkey.pem \
         --key-file /root/cert/${domain}/privkey.pem \
-        --fullchain-file /root/cert/${domain}/fullchain.pem --reloadcmd "${reloadCmd}"
+        --fullchain-file /root/cert/${domain}/fullchain.pem --reloadcmd "${reloadCmd}" 2>&1)
+    local installRc=$?
+    echo "${installOutput}"
 
 
-    if [ $? -ne 0 ]; then
+    local installWroteFiles=0
+    if echo "${installOutput}" | grep -q "Installing key to:" && echo "${installOutput}" | grep -q "Installing full chain to:"; then
+        installWroteFiles=1
+    fi
+
+    if [[ -f "/root/cert/${domain}/privkey.pem" && -f "/root/cert/${domain}/fullchain.pem" && ( ${installRc} -eq 0 || ${installWroteFiles} -eq 1 ) ]]; then
+        echo -e "${green}Installing certificate succeeded, enabling auto renew...${plain}"
+    else
         echo -e "${red}Installing certificate failed, exiting.${plain}"
         echo -e "${red}Installing certificate failed, exiting.${plain}"
-        rm -rf ~/.acme.sh/${domain}
+        if [[ ${cert_exists} -eq 0 ]]; then
+            rm -rf ~/.acme.sh/${domain}
+        fi
         systemctl start x-ui 2>/dev/null || rc-service x-ui start 2>/dev/null
         systemctl start x-ui 2>/dev/null || rc-service x-ui start 2>/dev/null
         return 1
         return 1
-    else
-        echo -e "${green}Installing certificate succeeded, enabling auto renew...${plain}"
     fi
     fi
 
 
     # enable auto-renew
     # enable auto-renew
@@ -556,14 +570,21 @@ prompt_and_setup_ssl() {
     1)
     1)
         # User chose Let's Encrypt domain option
         # User chose Let's Encrypt domain option
         echo -e "${green}Using Let's Encrypt for domain certificate...${plain}"
         echo -e "${green}Using Let's Encrypt for domain certificate...${plain}"
-        ssl_cert_issue
-        # Extract the domain that was used from the certificate
-        local cert_domain=$(~/.acme.sh/acme.sh --list 2>/dev/null | tail -1 | awk '{print $1}')
-        if [[ -n "${cert_domain}" ]]; then
-            SSL_HOST="${cert_domain}"
-            echo -e "${green}✓ SSL certificate configured successfully with domain: ${cert_domain}${plain}"
+        if ssl_cert_issue; then
+            local cert_domain="${SSL_ISSUED_DOMAIN}"
+            if [[ -z "${cert_domain}" ]]; then
+                cert_domain=$(~/.acme.sh/acme.sh --list 2>/dev/null | tail -1 | awk '{print $1}')
+            fi
+
+            if [[ -n "${cert_domain}" ]]; then
+                SSL_HOST="${cert_domain}"
+                echo -e "${green}✓ SSL certificate configured successfully with domain: ${cert_domain}${plain}"
+            else
+                echo -e "${yellow}SSL setup may have completed, but domain extraction failed${plain}"
+                SSL_HOST="${server_ip}"
+            fi
         else
         else
-            echo -e "${yellow}SSL setup may have completed, but domain extraction failed${plain}"
+            echo -e "${red}SSL certificate setup failed for domain mode.${plain}"
             SSL_HOST="${server_ip}"
             SSL_HOST="${server_ip}"
         fi
         fi
         ;;
         ;;

+ 37 - 22
x-ui.sh

@@ -1371,14 +1371,15 @@ ssl_cert_issue() {
         break
         break
     done
     done
     LOGD "Your domain is: ${domain}, checking it..."
     LOGD "Your domain is: ${domain}, checking it..."
-
-    # check if there already exists a certificate
-    local currentCert=$(~/.acme.sh/acme.sh --list | tail -1 | awk '{print $1}')
-    if [ "${currentCert}" == "${domain}" ]; then
-        local certInfo=$(~/.acme.sh/acme.sh --list)
-        LOGE "System already has certificates for this domain. Cannot issue again. Current certificate details:"
-        LOGI "$certInfo"
-        exit 1
+    SSL_ISSUED_DOMAIN="${domain}"
+
+    # detect existing certificate and reuse it if present
+    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
     else
         LOGI "Your domain is ready for issuing certificates now..."
         LOGI "Your domain is ready for issuing certificates now..."
     fi
     fi
@@ -1401,15 +1402,19 @@ ssl_cert_issue() {
     fi
     fi
     LOGI "Will use port: ${WebPort} to issue certificates. Please make sure this port is open."
     LOGI "Will use port: ${WebPort} to issue certificates. Please make sure this port is open."
 
 
-    # issue the certificate
-    ~/.acme.sh/acme.sh --set-default-ca --server letsencrypt --force
-    ~/.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}
-        exit 1
+    if [[ ${cert_exists} -eq 0 ]]; then
+        # issue the certificate
+        ~/.acme.sh/acme.sh --set-default-ca --server letsencrypt --force
+        ~/.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}
+            exit 1
+        else
+            LOGE "Issuing certificate succeeded, installing certificates..."
+        fi
     else
     else
-        LOGE "Issuing certificate succeeded, installing certificates..."
+        LOGI "Using existing certificate, installing certificates..."
     fi
     fi
 
 
     reloadCmd="x-ui restart"
     reloadCmd="x-ui restart"
@@ -1439,16 +1444,26 @@ ssl_cert_issue() {
     fi
     fi
 
 
     # install the certificate
     # install the certificate
-    ~/.acme.sh/acme.sh --installcert -d ${domain} \
+    local installOutput=""
+    installOutput=$(~/.acme.sh/acme.sh --installcert -d ${domain} \
         --key-file /root/cert/${domain}/privkey.pem \
         --key-file /root/cert/${domain}/privkey.pem \
-        --fullchain-file /root/cert/${domain}/fullchain.pem --reloadcmd "${reloadCmd}"
+        --fullchain-file /root/cert/${domain}/fullchain.pem --reloadcmd "${reloadCmd}" 2>&1)
+    local installRc=$?
+    echo "${installOutput}"
 
 
-    if [ $? -ne 0 ]; then
+    local installWroteFiles=0
+    if echo "${installOutput}" | grep -q "Installing key to:" && echo "${installOutput}" | grep -q "Installing full chain to:"; then
+        installWroteFiles=1
+    fi
+
+    if [[ -f "/root/cert/${domain}/privkey.pem" && -f "/root/cert/${domain}/fullchain.pem" && ( ${installRc} -eq 0 || ${installWroteFiles} -eq 1 ) ]]; then
+        LOGI "Installing certificate succeeded, enabling auto renew..."
+    else
         LOGE "Installing certificate failed, exiting."
         LOGE "Installing certificate failed, exiting."
-        rm -rf ~/.acme.sh/${domain}
+        if [[ ${cert_exists} -eq 0 ]]; then
+            rm -rf ~/.acme.sh/${domain}
+        fi
         exit 1
         exit 1
-    else
-        LOGI "Installing certificate succeeded, enabling auto renew..."
     fi
     fi
 
 
     # enable auto-renew
     # enable auto-renew