Skip to content

Commit e4a48e9

Browse files
salehsaleh
authored andcommitted
fix: handle acme.sh 'Domains not changed' skip (reuse existing cert or force re-issue)
1 parent 2a33192 commit e4a48e9

1 file changed

Lines changed: 72 additions & 25 deletions

File tree

Deploy-Ubuntu.sh

Lines changed: 72 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -105,33 +105,36 @@ info() { echo -e "${C_GRAY} $1${C_RESET}"; }
105105
spin() {
106106
local label="$1"; shift
107107
[[ "$1" == "--" ]] && shift
108-
local frames='|/-\\' i=0 start now elapsed
108+
local frames='|/-\' i=0 start now elapsed
109109
start=$(date +%s)
110110

111111
# Run command in background, redirect output to a log so spinner can paint
112112
local logfile; logfile=$(mktemp)
113113
( "$@" >"$logfile" 2>&1 ) &
114114
local pid=$!
115115

116+
# Real escape character (not the literal \033 backslash-zero-three-three)
117+
local ESC=$'\033'
116118
# Hide cursor
117-
printf '\033[?25l'
119+
printf '%s[?25l' "$ESC"
118120
while kill -0 "$pid" 2>/dev/null; do
119121
now=$(date +%s); elapsed=$(( now - start ))
120122
local frame="${frames:i++%${#frames}:1}"
121-
printf "\r ${C_CYAN}${frame}${C_RESET} %s ${C_GRAY}(%ds elapsed)${C_RESET} " "$label" "$elapsed"
123+
printf '\r %s[1;36m%s%s[0m %s %s[0;90m(%ds elapsed)%s[0m ' \
124+
"$ESC" "$frame" "$ESC" "$label" "$ESC" "$elapsed" "$ESC"
122125
sleep 0.2
123126
done
124127
wait "$pid"; local rc=$?
125128
now=$(date +%s); elapsed=$(( now - start ))
126-
# Restore cursor and clear spinner line
127-
printf '\r\033[K\033[?25h'
129+
# Clear spinner line and restore cursor
130+
printf '\r%s[2K%s[?25h' "$ESC" "$ESC"
128131

129132
if [[ $rc -eq 0 ]]; then
130-
ok "$label ${C_GRAY}(${elapsed}s)${C_RESET}"
133+
echo -e " ${C_GREEN}${C_RESET} ${label} ${C_GRAY}(${elapsed}s)${C_RESET}"
131134
else
132-
fail "$label — exit ${rc} (${elapsed}s)"
133-
echo -e " ${C_GRAY}── last 10 lines of output ──${C_RESET}"
134-
tail -10 "$logfile" 2>/dev/null | while IFS= read -r l; do echo -e " ${C_GRAY} $l${C_RESET}"; done
135+
echo -e " ${C_RED}${C_RESET} ${label} ${C_RED}— exit ${rc}${C_RESET} ${C_GRAY}(${elapsed}s)${C_RESET}"
136+
echo -e " ${C_GRAY}── last 10 lines of output ──${C_RESET}"
137+
tail -10 "$logfile" 2>/dev/null | while IFS= read -r l; do echo -e " ${C_GRAY}$l${C_RESET}"; done
135138
fi
136139
rm -f "$logfile"
137140
return $rc
@@ -386,17 +389,23 @@ phase2_install_all() {
386389

387390
local netlify_ok=false
388391

389-
# ── Attempt 1: standard npm global install ───────────
390-
if spin "Installing Netlify CLI via npm (~1-2min, ~100MB)" -- \
391-
bash -c 'npm install -g netlify-cli --prefer-online'; then
392+
# Common npm flags to speed up installs:
393+
# --no-audit / --no-fund → skips post-install network calls
394+
# --no-progress → suppresses progress bar (much faster on slow terms)
395+
# --prefer-offline → use cache if available
396+
local NPM_FAST="--no-audit --no-fund --no-progress --prefer-offline"
397+
398+
# ── Attempt 1: fast npm global install ───────────────
399+
if spin "Installing Netlify CLI via npm (~30-60s)" -- \
400+
bash -c "npm install -g netlify-cli ${NPM_FAST}"; then
392401
command -v netlify &>/dev/null && netlify_ok=true
393402
fi
394403

395404
# ── Attempt 2: npm with lower max-old-space (low-RAM VPS) ─
396405
if [[ "$netlify_ok" != "true" ]]; then
397406
warn "Attempt 1 failed — retrying with 512MB memory limit..."
398407
if spin "Installing Netlify CLI (low-mem mode)" -- \
399-
bash -c 'NODE_OPTIONS="--max-old-space-size=512" npm install -g netlify-cli'; then
408+
bash -c "NODE_OPTIONS='--max-old-space-size=512' npm install -g netlify-cli ${NPM_FAST}"; then
400409
command -v netlify &>/dev/null && netlify_ok=true
401410
fi
402411
fi
@@ -406,7 +415,7 @@ phase2_install_all() {
406415
warn "Attempt 2 failed — cleaning npm cache and retrying..."
407416
npm cache clean --force >/dev/null 2>&1 || true
408417
if spin "Installing Netlify CLI (after cache clean)" -- \
409-
bash -c 'npm install -g netlify-cli'; then
418+
bash -c "npm install -g netlify-cli ${NPM_FAST}"; then
410419
command -v netlify &>/dev/null && netlify_ok=true
411420
fi
412421
fi
@@ -472,7 +481,8 @@ NPXWRAP
472481
if command -v vercel &>/dev/null; then
473482
ok "Vercel CLI already installed ($(vercel --version 2>/dev/null | head -1))"
474483
else
475-
spin "Installing Vercel CLI via npm (~30s, ~50MB)" -- bash -c 'npm install -g vercel'
484+
spin "Installing Vercel CLI via npm (~20-40s)" -- \
485+
bash -c 'npm install -g vercel --no-audit --no-fund --no-progress --prefer-offline'
476486
fi
477487

478488
# ── 2d. xray-knife ──────────────────────────────────────
@@ -673,26 +683,40 @@ phase4a_ssl() {
673683
grep -iE "register|already|account" | head -3 || true
674684

675685
# ── Helper: run acme.sh --issue and capture full output ────
686+
# $1: mode (standalone | webroot)
687+
# $2: extra flags (e.g. "--force")
676688
_run_acme_issue() {
677-
local mode="$1" # "standalone" | "webroot"
678-
info "Running: acme.sh --issue -d ${CFG_DOMAIN} --${mode} --keylength ec-256 --listen-v4"
689+
local mode="$1" extra="${2:-}"
690+
info "Running: acme.sh --issue -d ${CFG_DOMAIN} --${mode} --keylength ec-256 --listen-v4 ${extra}"
679691
local out rc
680692
if [[ "$mode" == "webroot" ]]; then
681693
mkdir -p /var/www/html
682694
out=$("$ACME_CMD" --issue -d "$CFG_DOMAIN" --webroot /var/www/html \
683-
--keylength ec-256 --listen-v4 --server letsencrypt 2>&1) || rc=$?
695+
--keylength ec-256 --listen-v4 --server letsencrypt $extra 2>&1) || rc=$?
684696
else
685697
out=$("$ACME_CMD" --issue -d "$CFG_DOMAIN" --standalone \
686-
--keylength ec-256 --listen-v4 --server letsencrypt 2>&1) || rc=$?
698+
--keylength ec-256 --listen-v4 --server letsencrypt $extra 2>&1) || rc=$?
687699
fi
688700
rc=${rc:-0}
701+
# Save full output for later inspection
702+
LAST_ACME_OUT="$out"
689703
# Show last 25 lines so user can see the real error
690704
echo "$out" | tail -25 | while IFS= read -r l; do echo -e " ${C_GRAY}${l}${C_RESET}"; done
691705
return $rc
692706
}
693707

708+
# ── Check if a valid cert already exists on disk (covers both ECC and RSA) ─
709+
local acme_cert_path="$HOME/.acme.sh/${CFG_DOMAIN}_ecc/${CFG_DOMAIN}.cer"
710+
local acme_cert_path_rsa="$HOME/.acme.sh/${CFG_DOMAIN}/${CFG_DOMAIN}.cer"
711+
if [[ -f "$acme_cert_path" ]]; then
712+
info "Found existing EC cert at ${acme_cert_path} — will reuse"
713+
elif [[ -f "$acme_cert_path_rsa" ]]; then
714+
info "Found existing RSA cert at ${acme_cert_path_rsa} — will reuse"
715+
acme_cert_path="$acme_cert_path_rsa"
716+
fi
717+
694718
# ── Issue certificate ──────────────────────────────────────
695-
local issue_rc=0
719+
local issue_rc=0 LAST_ACME_OUT=""
696720
if [[ "$port80_used" == "true" ]]; then
697721
if command -v nginx &>/dev/null && [[ -d /var/www/html ]]; then
698722
_run_acme_issue webroot || issue_rc=$?
@@ -708,8 +732,30 @@ phase4a_ssl() {
708732
_run_acme_issue standalone || issue_rc=$?
709733
fi
710734

735+
# ── Handle "Skipping. Next renewal time" — cert already exists & valid ───
736+
# acme.sh exits 2 in this case; treat as success if the cer file is there.
737+
if [[ $issue_rc -ne 0 ]] && echo "$LAST_ACME_OUT" | grep -qiE "Domains not changed|Skipping.*Next renewal"; then
738+
if [[ -f "$acme_cert_path" ]]; then
739+
info "acme.sh: existing cert still valid — using it as-is"
740+
issue_rc=0
741+
else
742+
# The 'skip' message lied (no cert on disk) — force re-issue
743+
warn "acme.sh says 'skip' but no cert file found — forcing re-issue with --force"
744+
issue_rc=0
745+
if [[ "$port80_used" == "true" ]] && ! { command -v nginx &>/dev/null && [[ -d /var/www/html ]]; }; then
746+
systemctl stop xray 2>/dev/null || true
747+
sleep 2
748+
_run_acme_issue standalone "--force" || issue_rc=$?
749+
systemctl start xray 2>/dev/null || true
750+
elif [[ "$port80_used" == "true" ]]; then
751+
_run_acme_issue webroot "--force" || issue_rc=$?
752+
else
753+
_run_acme_issue standalone "--force" || issue_rc=$?
754+
fi
755+
fi
756+
fi
757+
711758
# ── Verify the cert file actually exists before installcert ─
712-
local acme_cert_path="$HOME/.acme.sh/${CFG_DOMAIN}_ecc/${CFG_DOMAIN}.cer"
713759
if [[ $issue_rc -ne 0 ]] || [[ ! -f "$acme_cert_path" ]]; then
714760
fail "acme.sh --issue failed (exit ${issue_rc}). No cert at ${acme_cert_path}"
715761
info "Common causes:"
@@ -722,12 +768,13 @@ phase4a_ssl() {
722768
return 1
723769
fi
724770

725-
ok "acme.sh issued certificate (ec-256)"
771+
ok "acme.sh certificate ready"
726772

727773
# ── Install certificate to target dir ──────────────────────
728-
# --ecc is REQUIRED when --installcert references an EC key (matches the
729-
# ${domain}_ecc directory acme.sh created during --issue).
730-
"$ACME_CMD" --installcert -d "$CFG_DOMAIN" --ecc \
774+
# --ecc selects the EC-key cert directory (${domain}_ecc/). Omit it for RSA.
775+
local ecc_flag="--ecc"
776+
[[ "$acme_cert_path" == *"${CFG_DOMAIN}/${CFG_DOMAIN}.cer" ]] && ecc_flag=""
777+
"$ACME_CMD" --installcert -d "$CFG_DOMAIN" $ecc_flag \
731778
--cert-file "${SSL_DIR}/cert.pem" \
732779
--key-file "${SSL_KEY}" \
733780
--fullchain-file "${SSL_CERT}" \

0 commit comments

Comments
 (0)