@aaricchen1991/n2-cli 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +92 -0
- package/assets/deploy/deploy.sh +172 -0
- package/assets/deploy/domains.yaml +18 -0
- package/assets/deploy/lib/common.sh +62 -0
- package/assets/deploy/nginx/n2.conf +162 -0
- package/assets/deploy/server-setup.sh +285 -0
- package/assets/deploy/ssl/README.md +320 -0
- package/assets/deploy/ssl/check-and-setup-ssl.sh +222 -0
- package/assets/deploy/ssl/domains.txt +3 -0
- package/assets/deploy/ssl/renew-ssl.sh +236 -0
- package/assets/deploy/ssl/setup-ssl.sh +474 -0
- package/dist/cli.d.ts +7 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +186 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/config.d.ts +29 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +134 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/config.test.d.ts +2 -0
- package/dist/commands/config.test.d.ts.map +1 -0
- package/dist/commands/config.test.js +215 -0
- package/dist/commands/config.test.js.map +1 -0
- package/dist/commands/init.d.ts +10 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +106 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/init.test.d.ts +2 -0
- package/dist/commands/init.test.d.ts.map +1 -0
- package/dist/commands/init.test.js +70 -0
- package/dist/commands/init.test.js.map +1 -0
- package/dist/commands/nginx.d.ts +10 -0
- package/dist/commands/nginx.d.ts.map +1 -0
- package/dist/commands/nginx.js +72 -0
- package/dist/commands/nginx.js.map +1 -0
- package/dist/commands/nginx.test.d.ts +2 -0
- package/dist/commands/nginx.test.d.ts.map +1 -0
- package/dist/commands/nginx.test.js +75 -0
- package/dist/commands/nginx.test.js.map +1 -0
- package/dist/commands/ssl-logs.d.ts +17 -0
- package/dist/commands/ssl-logs.d.ts.map +1 -0
- package/dist/commands/ssl-logs.js +55 -0
- package/dist/commands/ssl-logs.js.map +1 -0
- package/dist/commands/ssl-logs.test.d.ts +2 -0
- package/dist/commands/ssl-logs.test.d.ts.map +1 -0
- package/dist/commands/ssl-logs.test.js +54 -0
- package/dist/commands/ssl-logs.test.js.map +1 -0
- package/dist/commands/ssl.d.ts +16 -0
- package/dist/commands/ssl.d.ts.map +1 -0
- package/dist/commands/ssl.js +105 -0
- package/dist/commands/ssl.js.map +1 -0
- package/dist/commands/ssl.test.d.ts +2 -0
- package/dist/commands/ssl.test.d.ts.map +1 -0
- package/dist/commands/ssl.test.js +95 -0
- package/dist/commands/ssl.test.js.map +1 -0
- package/dist/lib/config-store.d.ts +14 -0
- package/dist/lib/config-store.d.ts.map +1 -0
- package/dist/lib/config-store.js +111 -0
- package/dist/lib/config-store.js.map +1 -0
- package/dist/lib/config-store.test.d.ts +2 -0
- package/dist/lib/config-store.test.d.ts.map +1 -0
- package/dist/lib/config-store.test.js +173 -0
- package/dist/lib/config-store.test.js.map +1 -0
- package/dist/lib/domains.d.ts +37 -0
- package/dist/lib/domains.d.ts.map +1 -0
- package/dist/lib/domains.js +134 -0
- package/dist/lib/domains.js.map +1 -0
- package/dist/lib/domains.test.d.ts +2 -0
- package/dist/lib/domains.test.d.ts.map +1 -0
- package/dist/lib/domains.test.js +141 -0
- package/dist/lib/domains.test.js.map +1 -0
- package/dist/lib/logger.d.ts +19 -0
- package/dist/lib/logger.d.ts.map +1 -0
- package/dist/lib/logger.js +58 -0
- package/dist/lib/logger.js.map +1 -0
- package/dist/lib/nginx.d.ts +7 -0
- package/dist/lib/nginx.d.ts.map +1 -0
- package/dist/lib/nginx.js +86 -0
- package/dist/lib/nginx.js.map +1 -0
- package/dist/lib/nginx.test.d.ts +2 -0
- package/dist/lib/nginx.test.d.ts.map +1 -0
- package/dist/lib/nginx.test.js +46 -0
- package/dist/lib/nginx.test.js.map +1 -0
- package/dist/lib/paths.d.ts +13 -0
- package/dist/lib/paths.d.ts.map +1 -0
- package/dist/lib/paths.js +36 -0
- package/dist/lib/paths.js.map +1 -0
- package/dist/lib/paths.test.d.ts +2 -0
- package/dist/lib/paths.test.d.ts.map +1 -0
- package/dist/lib/paths.test.js +52 -0
- package/dist/lib/paths.test.js.map +1 -0
- package/package.json +34 -0
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# SSL 证书检查和设置脚本
|
|
3
|
+
# 用于 GitHub Actions 中自动检查并申请/续期证书
|
|
4
|
+
# 如果证书不存在或即将到期(30天内),则自动申请/续期
|
|
5
|
+
# 域名列表从 domains.txt 读取(由 n2-deploy 根据配置生成)
|
|
6
|
+
|
|
7
|
+
set -e
|
|
8
|
+
|
|
9
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
10
|
+
if [ -f "/opt/ssl/common.sh" ]; then
|
|
11
|
+
. /opt/ssl/common.sh
|
|
12
|
+
elif [ -f "$SCRIPT_DIR/common.sh" ]; then
|
|
13
|
+
. "$SCRIPT_DIR/common.sh"
|
|
14
|
+
elif [ -f "$SCRIPT_DIR/../lib/common.sh" ]; then
|
|
15
|
+
. "$SCRIPT_DIR/../lib/common.sh"
|
|
16
|
+
else
|
|
17
|
+
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m'
|
|
18
|
+
log() { echo -e "${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} $1"; }
|
|
19
|
+
error() { echo -e "${RED}[ERROR]${NC} $1" >&2; }
|
|
20
|
+
warning() { echo -e "${YELLOW}[WARNING]${NC} $1"; }
|
|
21
|
+
get_domains_file() { [ -n "$DOMAINS_FILE" ] && [ -f "$DOMAINS_FILE" ] && { echo "$DOMAINS_FILE"; return 0; }; [ -f "/opt/ssl/domains.txt" ] && { echo "/opt/ssl/domains.txt"; return 0; }; [ -f "$SCRIPT_DIR/domains.txt" ] && { echo "$SCRIPT_DIR/domains.txt"; return 0; }; return 1; }
|
|
22
|
+
read_domains_list() { local f; f=$(get_domains_file) || return 1; while IFS= read -r line || [ -n "$line" ]; do line=$(echo "$line" | tr -d '\r'); [ -z "$line" ] && continue; echo "$line" | grep -q '^#' && continue; echo "$line"; done < "$f"; }
|
|
23
|
+
fi
|
|
24
|
+
|
|
25
|
+
# 检查是否以 root 权限运行
|
|
26
|
+
if [ "$EUID" -ne 0 ]; then
|
|
27
|
+
error "请使用 sudo 运行此脚本"
|
|
28
|
+
exit 1
|
|
29
|
+
fi
|
|
30
|
+
|
|
31
|
+
# 确保在有效目录下执行,避免 getcwd 报错(例如从已被删除的 /tmp/server-init 调用时)
|
|
32
|
+
cd /
|
|
33
|
+
|
|
34
|
+
# 阿里云 API 凭证
|
|
35
|
+
ALI_KEY=""
|
|
36
|
+
ALI_SECRET=""
|
|
37
|
+
|
|
38
|
+
# 调试模式
|
|
39
|
+
DEBUG_MODE=false
|
|
40
|
+
|
|
41
|
+
# 解析命令行参数
|
|
42
|
+
while [[ $# -gt 0 ]]; do
|
|
43
|
+
case $1 in
|
|
44
|
+
--ali-key)
|
|
45
|
+
if [ -n "$2" ]; then
|
|
46
|
+
ALI_KEY="$2"
|
|
47
|
+
shift 2
|
|
48
|
+
else
|
|
49
|
+
shift
|
|
50
|
+
fi
|
|
51
|
+
;;
|
|
52
|
+
--ali-secret)
|
|
53
|
+
if [ -n "$2" ]; then
|
|
54
|
+
ALI_SECRET="$2"
|
|
55
|
+
shift 2
|
|
56
|
+
else
|
|
57
|
+
shift
|
|
58
|
+
fi
|
|
59
|
+
;;
|
|
60
|
+
--debug)
|
|
61
|
+
DEBUG_MODE=true
|
|
62
|
+
set -x # 启用 bash 调试模式,显示所有执行的命令
|
|
63
|
+
shift
|
|
64
|
+
;;
|
|
65
|
+
*)
|
|
66
|
+
shift
|
|
67
|
+
;;
|
|
68
|
+
esac
|
|
69
|
+
done
|
|
70
|
+
|
|
71
|
+
# 检查证书是否需要申请或续期的函数
|
|
72
|
+
check_cert_needs_action() {
|
|
73
|
+
local domain=$1
|
|
74
|
+
local cert_file="/etc/nginx/ssl/${domain}.crt"
|
|
75
|
+
|
|
76
|
+
# 如果证书文件不存在,需要申请
|
|
77
|
+
if [ ! -f "$cert_file" ]; then
|
|
78
|
+
echo "missing"
|
|
79
|
+
return 0
|
|
80
|
+
fi
|
|
81
|
+
|
|
82
|
+
# 检查证书到期时间
|
|
83
|
+
local expiry_date=$(openssl x509 -in "$cert_file" -noout -enddate 2>/dev/null | cut -d= -f2)
|
|
84
|
+
if [ -z "$expiry_date" ]; then
|
|
85
|
+
warning "无法读取证书到期时间: $cert_file"
|
|
86
|
+
echo "expired"
|
|
87
|
+
return 0
|
|
88
|
+
fi
|
|
89
|
+
|
|
90
|
+
# 计算剩余天数(兼容不同系统的 date 命令)
|
|
91
|
+
local expiry_timestamp=""
|
|
92
|
+
# 尝试 GNU date 格式(Linux)
|
|
93
|
+
expiry_timestamp=$(date -d "$expiry_date" +%s 2>/dev/null)
|
|
94
|
+
# 如果失败,尝试 BSD date 格式(macOS)
|
|
95
|
+
if [ -z "$expiry_timestamp" ]; then
|
|
96
|
+
# 解析格式: "Jan 5 12:00:00 2025 GMT"
|
|
97
|
+
expiry_timestamp=$(date -j -f "%b %d %H:%M:%S %Y %Z" "$expiry_date" +%s 2>/dev/null)
|
|
98
|
+
fi
|
|
99
|
+
|
|
100
|
+
local current_timestamp=$(date +%s)
|
|
101
|
+
|
|
102
|
+
if [ -z "$expiry_timestamp" ]; then
|
|
103
|
+
warning "无法解析证书到期时间: $expiry_date"
|
|
104
|
+
echo "expired"
|
|
105
|
+
return 0
|
|
106
|
+
fi
|
|
107
|
+
|
|
108
|
+
local days_remaining=$(( ($expiry_timestamp - $current_timestamp) / 86400 ))
|
|
109
|
+
|
|
110
|
+
if [ $days_remaining -lt 0 ]; then
|
|
111
|
+
echo "expired"
|
|
112
|
+
elif [ $days_remaining -lt 30 ]; then
|
|
113
|
+
echo "renew"
|
|
114
|
+
else
|
|
115
|
+
echo "ok"
|
|
116
|
+
fi
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
log "开始检查 SSL 证书状态..."
|
|
120
|
+
|
|
121
|
+
# 检查阿里云 API 凭证(优先使用参数,其次使用环境变量)
|
|
122
|
+
if [ -z "$ALI_KEY" ]; then
|
|
123
|
+
ALI_KEY="$Ali_Key"
|
|
124
|
+
fi
|
|
125
|
+
if [ -z "$ALI_SECRET" ]; then
|
|
126
|
+
ALI_SECRET="$Ali_Secret"
|
|
127
|
+
fi
|
|
128
|
+
|
|
129
|
+
if [ -z "$ALI_KEY" ] || [ -z "$ALI_SECRET" ]; then
|
|
130
|
+
warning "未设置阿里云 API 凭证,跳过 SSL 证书设置"
|
|
131
|
+
warning "如需配置 SSL 证书,请通过参数传递:"
|
|
132
|
+
warning " --ali-key \"your_access_key_id\" --ali-secret \"your_access_key_secret\""
|
|
133
|
+
warning "或者设置环境变量:"
|
|
134
|
+
warning " export Ali_Key=\"your_access_key_id\""
|
|
135
|
+
warning " export Ali_Secret=\"your_access_key_secret\""
|
|
136
|
+
exit 0
|
|
137
|
+
fi
|
|
138
|
+
|
|
139
|
+
# 设置环境变量供后续脚本使用
|
|
140
|
+
export Ali_Key="$ALI_KEY"
|
|
141
|
+
export Ali_Secret="$ALI_SECRET"
|
|
142
|
+
|
|
143
|
+
# 检查 SSL 脚本是否存在
|
|
144
|
+
SSL_SETUP_SCRIPT=""
|
|
145
|
+
SSL_RENEW_SCRIPT=""
|
|
146
|
+
|
|
147
|
+
# 按优先级查找脚本
|
|
148
|
+
if [ -f "/tmp/server-init/ssl/setup-ssl.sh" ]; then
|
|
149
|
+
SSL_SETUP_SCRIPT="/tmp/server-init/ssl/setup-ssl.sh"
|
|
150
|
+
SSL_RENEW_SCRIPT="/tmp/server-init/ssl/renew-ssl.sh"
|
|
151
|
+
elif [ -f "/opt/ssl/setup-ssl.sh" ]; then
|
|
152
|
+
SSL_SETUP_SCRIPT="/opt/ssl/setup-ssl.sh"
|
|
153
|
+
SSL_RENEW_SCRIPT="/opt/ssl/renew-ssl.sh"
|
|
154
|
+
elif [ -f "/opt/deploy/../ssl/setup-ssl.sh" ]; then
|
|
155
|
+
SSL_SETUP_SCRIPT="/opt/deploy/../ssl/setup-ssl.sh"
|
|
156
|
+
SSL_RENEW_SCRIPT="/opt/deploy/../ssl/renew-ssl.sh"
|
|
157
|
+
else
|
|
158
|
+
# 尝试从当前目录查找
|
|
159
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
160
|
+
if [ -f "$SCRIPT_DIR/setup-ssl.sh" ]; then
|
|
161
|
+
SSL_SETUP_SCRIPT="$SCRIPT_DIR/setup-ssl.sh"
|
|
162
|
+
SSL_RENEW_SCRIPT="$SCRIPT_DIR/renew-ssl.sh"
|
|
163
|
+
fi
|
|
164
|
+
fi
|
|
165
|
+
|
|
166
|
+
if [ -z "$SSL_SETUP_SCRIPT" ] || [ ! -f "$SSL_SETUP_SCRIPT" ]; then
|
|
167
|
+
error "无法找到 setup-ssl.sh 脚本"
|
|
168
|
+
error "请确保 SSL 脚本已上传到服务器"
|
|
169
|
+
exit 1
|
|
170
|
+
fi
|
|
171
|
+
|
|
172
|
+
# 从 domains.txt 读取域名列表(api + admin + tenant + client)
|
|
173
|
+
DOMAINS_FILE_PATH=$(get_domains_file 2>/dev/null) || true
|
|
174
|
+
if [ -z "$DOMAINS_FILE_PATH" ] || [ ! -f "$DOMAINS_FILE_PATH" ]; then
|
|
175
|
+
error "无法找到域名列表 domains.txt,请先执行 n2-deploy init 或 n2-deploy ssl 根据配置生成"
|
|
176
|
+
exit 1
|
|
177
|
+
fi
|
|
178
|
+
|
|
179
|
+
# 检查并申请所有域名的证书
|
|
180
|
+
while IFS= read -r DOM || [ -n "$DOM" ]; do
|
|
181
|
+
DOM=$(echo "$DOM" | tr -d '\r')
|
|
182
|
+
[ -z "$DOM" ] && continue
|
|
183
|
+
echo "$DOM" | grep -q '^#' && continue
|
|
184
|
+
log "检查 $DOM 证书..."
|
|
185
|
+
CERT_STATUS=$(check_cert_needs_action "$DOM")
|
|
186
|
+
if [ "$CERT_STATUS" = "missing" ] || [ "$CERT_STATUS" = "expired" ]; then
|
|
187
|
+
log "$DOM 证书不存在或已过期,开始申请..."
|
|
188
|
+
if [ -f "$SSL_SETUP_SCRIPT" ]; then
|
|
189
|
+
bash "$SSL_SETUP_SCRIPT" --domains "$DOM" --ali-key "$ALI_KEY" --ali-secret "$ALI_SECRET" $([ "$DEBUG_MODE" = true ] && echo "--debug") || {
|
|
190
|
+
error "$DOM 证书申请失败"
|
|
191
|
+
exit 1
|
|
192
|
+
}
|
|
193
|
+
else
|
|
194
|
+
error "无法找到 setup-ssl.sh 脚本"
|
|
195
|
+
exit 1
|
|
196
|
+
fi
|
|
197
|
+
elif [ "$CERT_STATUS" = "renew" ]; then
|
|
198
|
+
log "$DOM 证书即将到期,开始续期..."
|
|
199
|
+
if [ -f "$SSL_RENEW_SCRIPT" ]; then
|
|
200
|
+
if ! bash "$SSL_RENEW_SCRIPT" --ali-key "$ALI_KEY" --ali-secret "$ALI_SECRET" $([ "$DEBUG_MODE" = true ] && echo "--debug"); then
|
|
201
|
+
# 续期失败常见原因:证书不是 acme.sh 签发(如占位证书),acme.sh 会报 "is not an issued domain"
|
|
202
|
+
# 此时改为申请新证书
|
|
203
|
+
log "$DOM 续期失败(可能为占位证书),改为申请新证书..."
|
|
204
|
+
if [ -f "$SSL_SETUP_SCRIPT" ]; then
|
|
205
|
+
bash "$SSL_SETUP_SCRIPT" --domains "$DOM" --ali-key "$ALI_KEY" --ali-secret "$ALI_SECRET" $([ "$DEBUG_MODE" = true ] && echo "--debug") || {
|
|
206
|
+
error "$DOM 证书申请失败"
|
|
207
|
+
exit 1
|
|
208
|
+
}
|
|
209
|
+
else
|
|
210
|
+
warning "$DOM 证书续期失败,且无法找到 setup-ssl.sh,跳过"
|
|
211
|
+
fi
|
|
212
|
+
fi
|
|
213
|
+
else
|
|
214
|
+
warning "无法找到 renew-ssl.sh 脚本,跳过续期"
|
|
215
|
+
fi
|
|
216
|
+
else
|
|
217
|
+
log "$DOM 证书有效,无需操作"
|
|
218
|
+
fi
|
|
219
|
+
done < <(read_domains_list)
|
|
220
|
+
|
|
221
|
+
log "SSL 证书检查完成"
|
|
222
|
+
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# SSL 证书续期脚本
|
|
3
|
+
# 检查并续期即将到期的 Let's Encrypt 证书
|
|
4
|
+
# 域名列表从 domains.txt 读取(由 n2-deploy 根据配置生成)
|
|
5
|
+
# 使用方法: renew-ssl.sh [--force]
|
|
6
|
+
|
|
7
|
+
set -e
|
|
8
|
+
|
|
9
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
10
|
+
if [ -f "/opt/ssl/common.sh" ]; then
|
|
11
|
+
. /opt/ssl/common.sh
|
|
12
|
+
elif [ -f "$SCRIPT_DIR/common.sh" ]; then
|
|
13
|
+
. "$SCRIPT_DIR/common.sh"
|
|
14
|
+
elif [ -f "$SCRIPT_DIR/../lib/common.sh" ]; then
|
|
15
|
+
. "$SCRIPT_DIR/../lib/common.sh"
|
|
16
|
+
else
|
|
17
|
+
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m'
|
|
18
|
+
log() { echo -e "${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} $1"; }
|
|
19
|
+
error() { echo -e "${RED}[ERROR]${NC} $1" >&2; }
|
|
20
|
+
warning() { echo -e "${YELLOW}[WARNING]${NC} $1"; }
|
|
21
|
+
get_domains_file() { [ -n "$DOMAINS_FILE" ] && [ -f "$DOMAINS_FILE" ] && { echo "$DOMAINS_FILE"; return 0; }; [ -f "/opt/ssl/domains.txt" ] && { echo "/opt/ssl/domains.txt"; return 0; }; [ -f "$SCRIPT_DIR/domains.txt" ] && { echo "$SCRIPT_DIR/domains.txt"; return 0; }; return 1; }
|
|
22
|
+
read_domains_list() { local f; f=$(get_domains_file) || return 1; while IFS= read -r line || [ -n "$line" ]; do line=$(echo "$line" | tr -d '\r'); [ -z "$line" ] && continue; echo "$line" | grep -q '^#' && continue; echo "$line"; done < "$f"; }
|
|
23
|
+
fi
|
|
24
|
+
|
|
25
|
+
# 检查是否以 root 权限运行
|
|
26
|
+
if [ "$EUID" -ne 0 ]; then
|
|
27
|
+
error "请使用 sudo 运行此脚本"
|
|
28
|
+
exit 1
|
|
29
|
+
fi
|
|
30
|
+
|
|
31
|
+
# 确保在有效目录下执行,避免 getcwd 报错
|
|
32
|
+
cd /
|
|
33
|
+
|
|
34
|
+
# 检查是否强制续期
|
|
35
|
+
FORCE_RENEW=false
|
|
36
|
+
|
|
37
|
+
# 阿里云 API 凭证
|
|
38
|
+
ALI_KEY=""
|
|
39
|
+
ALI_SECRET=""
|
|
40
|
+
|
|
41
|
+
# 解析命令行参数
|
|
42
|
+
while [[ $# -gt 0 ]]; do
|
|
43
|
+
case $1 in
|
|
44
|
+
--force)
|
|
45
|
+
FORCE_RENEW=true
|
|
46
|
+
log "强制续期模式"
|
|
47
|
+
shift
|
|
48
|
+
;;
|
|
49
|
+
--ali-key)
|
|
50
|
+
if [ -n "$2" ]; then
|
|
51
|
+
ALI_KEY="$2"
|
|
52
|
+
shift 2
|
|
53
|
+
else
|
|
54
|
+
shift
|
|
55
|
+
fi
|
|
56
|
+
;;
|
|
57
|
+
--ali-secret)
|
|
58
|
+
if [ -n "$2" ]; then
|
|
59
|
+
ALI_SECRET="$2"
|
|
60
|
+
shift 2
|
|
61
|
+
else
|
|
62
|
+
shift
|
|
63
|
+
fi
|
|
64
|
+
;;
|
|
65
|
+
*)
|
|
66
|
+
shift
|
|
67
|
+
;;
|
|
68
|
+
esac
|
|
69
|
+
done
|
|
70
|
+
|
|
71
|
+
# 检查阿里云 API 凭证(优先使用参数,其次使用环境变量)
|
|
72
|
+
if [ -z "$ALI_KEY" ]; then
|
|
73
|
+
ALI_KEY="$Ali_Key"
|
|
74
|
+
fi
|
|
75
|
+
if [ -z "$ALI_SECRET" ]; then
|
|
76
|
+
ALI_SECRET="$Ali_Secret"
|
|
77
|
+
fi
|
|
78
|
+
|
|
79
|
+
# 如果提供了凭证,设置环境变量供 acme.sh 使用
|
|
80
|
+
if [ -n "$ALI_KEY" ] && [ -n "$ALI_SECRET" ]; then
|
|
81
|
+
export Ali_Key="$ALI_KEY"
|
|
82
|
+
export Ali_Secret="$ALI_SECRET"
|
|
83
|
+
fi
|
|
84
|
+
|
|
85
|
+
# 检查 acme.sh 是否安装
|
|
86
|
+
ACME_SH_HOME="$HOME/.acme.sh"
|
|
87
|
+
if [ ! -f "$ACME_SH_HOME/acme.sh" ]; then
|
|
88
|
+
error "acme.sh 未安装,请先运行 setup-ssl.sh"
|
|
89
|
+
exit 1
|
|
90
|
+
fi
|
|
91
|
+
|
|
92
|
+
# 确保 acme.sh 在 PATH 中
|
|
93
|
+
export PATH="$HOME/.acme.sh:$PATH"
|
|
94
|
+
|
|
95
|
+
# 检查 acme.sh 是否可用
|
|
96
|
+
if ! command -v acme.sh >/dev/null 2>&1; then
|
|
97
|
+
ACME_CMD="$ACME_SH_HOME/acme.sh"
|
|
98
|
+
else
|
|
99
|
+
ACME_CMD="acme.sh"
|
|
100
|
+
fi
|
|
101
|
+
|
|
102
|
+
# 检查证书到期时间的函数
|
|
103
|
+
check_cert_expiry() {
|
|
104
|
+
local domain=$1
|
|
105
|
+
local cert_file="/etc/nginx/ssl/${domain}.crt"
|
|
106
|
+
|
|
107
|
+
if [ ! -f "$cert_file" ]; then
|
|
108
|
+
warning "证书文件不存在: $cert_file"
|
|
109
|
+
return 1
|
|
110
|
+
fi
|
|
111
|
+
|
|
112
|
+
# 获取证书到期时间(Unix 时间戳)
|
|
113
|
+
local expiry_timestamp=$(openssl x509 -in "$cert_file" -noout -enddate 2>/dev/null | cut -d= -f2 | xargs -I {} date -d {} +%s 2>/dev/null || openssl x509 -in "$cert_file" -noout -enddate 2>/dev/null | cut -d= -f2 | xargs -I {} date -j -f "%b %d %H:%M:%S %Y %Z" {} +%s 2>/dev/null)
|
|
114
|
+
|
|
115
|
+
if [ -z "$expiry_timestamp" ]; then
|
|
116
|
+
warning "无法读取证书到期时间: $cert_file"
|
|
117
|
+
return 1
|
|
118
|
+
fi
|
|
119
|
+
|
|
120
|
+
# 当前时间戳
|
|
121
|
+
local current_timestamp=$(date +%s)
|
|
122
|
+
|
|
123
|
+
# 计算剩余天数
|
|
124
|
+
local days_remaining=$(( ($expiry_timestamp - $current_timestamp) / 86400 ))
|
|
125
|
+
|
|
126
|
+
echo "$days_remaining"
|
|
127
|
+
return 0
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
# 续期证书的函数
|
|
131
|
+
renew_cert() {
|
|
132
|
+
local domain=$1
|
|
133
|
+
local cert_file="/etc/nginx/ssl/${domain}.crt"
|
|
134
|
+
|
|
135
|
+
log "检查 $domain 证书..."
|
|
136
|
+
|
|
137
|
+
if [ ! -f "$cert_file" ]; then
|
|
138
|
+
warning "证书文件不存在: $cert_file,跳过续期"
|
|
139
|
+
return 1
|
|
140
|
+
fi
|
|
141
|
+
|
|
142
|
+
# 检查证书到期时间
|
|
143
|
+
local days_remaining=$(check_cert_expiry "$domain")
|
|
144
|
+
|
|
145
|
+
if [ -z "$days_remaining" ] || [ "$days_remaining" -lt 0 ]; then
|
|
146
|
+
warning "$domain 证书已过期或无法读取,尝试续期..."
|
|
147
|
+
elif [ "$days_remaining" -gt 30 ] && [ "$FORCE_RENEW" = false ]; then
|
|
148
|
+
log "$domain 证书还有 $days_remaining 天到期,无需续期(使用 --force 强制续期)"
|
|
149
|
+
return 0
|
|
150
|
+
elif [ "$days_remaining" -gt 30 ] && [ "$FORCE_RENEW" = true ]; then
|
|
151
|
+
log "$domain 证书还有 $days_remaining 天到期,强制续期..."
|
|
152
|
+
else
|
|
153
|
+
log "$domain 证书还有 $days_remaining 天到期,开始续期..."
|
|
154
|
+
fi
|
|
155
|
+
|
|
156
|
+
# 执行续期
|
|
157
|
+
if [ -f "$ACME_SH_HOME/acme.sh" ]; then
|
|
158
|
+
"$ACME_SH_HOME/acme.sh" --renew -d "$domain" --force
|
|
159
|
+
else
|
|
160
|
+
$ACME_CMD --renew -d "$domain" --force
|
|
161
|
+
fi
|
|
162
|
+
|
|
163
|
+
if [ $? -eq 0 ]; then
|
|
164
|
+
log "$domain 证书续期成功"
|
|
165
|
+
|
|
166
|
+
# 重新安装证书到 nginx(确保使用最新的证书)
|
|
167
|
+
log "重新安装 $domain 证书到 nginx..."
|
|
168
|
+
if [ -f "$ACME_SH_HOME/acme.sh" ]; then
|
|
169
|
+
"$ACME_SH_HOME/acme.sh" --install-cert \
|
|
170
|
+
-d "$domain" \
|
|
171
|
+
--key-file /etc/nginx/ssl/${domain}.key \
|
|
172
|
+
--fullchain-file /etc/nginx/ssl/${domain}.crt \
|
|
173
|
+
--reloadcmd "systemctl reload nginx || true"
|
|
174
|
+
else
|
|
175
|
+
$ACME_CMD --install-cert \
|
|
176
|
+
-d "$domain" \
|
|
177
|
+
--key-file /etc/nginx/ssl/${domain}.key \
|
|
178
|
+
--fullchain-file /etc/nginx/ssl/${domain}.crt \
|
|
179
|
+
--reloadcmd "systemctl reload nginx || true"
|
|
180
|
+
fi
|
|
181
|
+
|
|
182
|
+
# 设置证书文件权限
|
|
183
|
+
chmod 600 /etc/nginx/ssl/${domain}.key
|
|
184
|
+
chmod 644 /etc/nginx/ssl/${domain}.crt
|
|
185
|
+
chown root:root /etc/nginx/ssl/${domain}.key
|
|
186
|
+
chown root:root /etc/nginx/ssl/${domain}.crt
|
|
187
|
+
|
|
188
|
+
return 0
|
|
189
|
+
else
|
|
190
|
+
error "$domain 证书续期失败"
|
|
191
|
+
return 1
|
|
192
|
+
fi
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
log "开始检查证书续期..."
|
|
196
|
+
|
|
197
|
+
# 从 domains.txt 读取域名列表
|
|
198
|
+
DOMAINS_FILE_PATH=$(get_domains_file 2>/dev/null) || true
|
|
199
|
+
if [ -z "$DOMAINS_FILE_PATH" ] || [ ! -f "$DOMAINS_FILE_PATH" ]; then
|
|
200
|
+
error "无法找到域名列表 domains.txt,请先执行 n2-deploy init 或 n2-deploy ssl 根据配置生成"
|
|
201
|
+
exit 1
|
|
202
|
+
fi
|
|
203
|
+
|
|
204
|
+
# 续期所有域名证书(证书不存在时跳过)
|
|
205
|
+
# 任一失败则脚本以非零退出,便于上层 fallback 到申请新证书
|
|
206
|
+
RENEW_FAILED=0
|
|
207
|
+
while IFS= read -r domain || [ -n "$domain" ]; do
|
|
208
|
+
domain=$(echo "$domain" | tr -d '\r')
|
|
209
|
+
[ -z "$domain" ] && continue
|
|
210
|
+
echo "$domain" | grep -q '^#' && continue
|
|
211
|
+
renew_cert "$domain" || RENEW_FAILED=1
|
|
212
|
+
done < <(read_domains_list)
|
|
213
|
+
|
|
214
|
+
# 测试 nginx 配置
|
|
215
|
+
log "测试 nginx 配置..."
|
|
216
|
+
if nginx -t; then
|
|
217
|
+
log "Nginx 配置验证成功"
|
|
218
|
+
# 重新加载 nginx
|
|
219
|
+
if systemctl is-active --quiet nginx 2>/dev/null; then
|
|
220
|
+
log "重新加载 Nginx..."
|
|
221
|
+
systemctl reload nginx || warning "Nginx 重新加载失败,请手动检查"
|
|
222
|
+
fi
|
|
223
|
+
else
|
|
224
|
+
error "Nginx 配置验证失败,请检查配置文件"
|
|
225
|
+
exit 1
|
|
226
|
+
fi
|
|
227
|
+
|
|
228
|
+
log ""
|
|
229
|
+
log "证书续期检查完成!"
|
|
230
|
+
log ""
|
|
231
|
+
log "提示:"
|
|
232
|
+
log " - acme.sh 已自动配置 cron 任务,证书将在到期前 30 天自动续期"
|
|
233
|
+
log " - 可以通过 'crontab -l' 查看续期任务"
|
|
234
|
+
log " - 使用 '--force' 参数可以强制续期所有证书"
|
|
235
|
+
|
|
236
|
+
exit $RENEW_FAILED
|