原因
vps 的宝塔的 Let’s encrypt 证书三个月后无法自动续签。不知道是原因。算了, 手工搭建, 然后 acme.sh 自动续签证书。
acme.sh 申请证书
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
| #!/bin/bash
# 设置 acme.sh 路径变量
ACME_SCRIPT="/root/.acme.sh/acme.sh"
# 设置 Cloudflare API 凭据
export CF_Token="" # 我的个人资料 -> API 令牌 -> 创建令牌
export CF_Account_ID="" # 进入域 -> 右下角的 "帐户ID"
DOMAIN_GROUPS=(
"foo.domain.com *.foo.domain.com" # 支持申请 SAN 域名
"bar.domain.com *.bar.domain.com"
)
# 显示开始信息
echo "开始申请SAN SSL证书..."
echo "========================================"
# 检查 acme.sh 是否存在
if [ ! -f "$ACME_SCRIPT" ]; then
echo "❌ 错误: 找不到 acme.sh 脚本"
exit 1
fi
# 为每组域名申请证书
for group in "${DOMAIN_GROUPS[@]}"; do
main_domain=$(echo "$group" | awk '{print $1}')
echo "🔄 申请证书: $group"
# 构建并执行命令
cmd="$ACME_SCRIPT --issue"
for domain in $group; do
cmd="$cmd -d $domain"
done
cmd="$cmd --dns dns_cf --force"
eval $cmd
if [ $? -eq 0 ]; then
echo "✅ 证书申请成功: $main_domain"
else
echo "❌ 证书申请失败: $main_domain"
fi
echo "----------------------------------------"
done
echo "📋 最终证书列表:"
"$ACME_SCRIPT" --list
|
列出 acme 管理的域名:
1
2
| acme.sh --list
acme.sh --info -d foo.domain.com --ecc # 查看证书的信息
|
创建域名配置和域名所用到的目录
1
2
3
4
5
6
7
8
| mkdir -p /etc/nginx/{sites-available,sites-enabled}
touch /etc/nginx/sites-available/{foo.domain.com,bar.domain.com}
mkdir -p /var/www/{foo.domain.com,bar.domain.com}/html
chown $USER:www-data -R /var/www/{foo.domain.com,bar.domain.com}/html
ln -s /etc/nginx/sites-available/foo.domain.com /etc/nginx/sites-enabled/
ln -s /etc/nginx/sites-available/bar.domain.com /etc/nginx/sites-enabled/
|
/etc/nginx/sites-available/foo.domain.com:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
| server {
listen 80;
listen [::]:80;
server_name foo.domain.com;
# 重定向所有 HTTP 请求到 HTTPS
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name foo.domain.com;
# SSL 证书路径
ssl_certificate /root/.acme.sh/foo.domain.com_ecc/fullchain.cer;
ssl_certificate_key /root/.acme.sh/foo.domain.com_ecc/foo.domain.com.key;
# SSL 配置
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256- GCM-SHA384;
ssl_prefer_server_ciphers off;
# HSTS (可选)
add_header Strict-Transport-Security "max-age=63072000" always;
root /var/www/foo.domain.com/html;
index index.html index.htm;
location / {
try_files $uri $uri/ =404;
}
# 禁止访问隐藏文件
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}
access_log /var/log/nginx/foo.domain.com.access.log;
error_log /var/log/nginx/foo.domain.com.error.log;
}
|
其他同理。
将构建好的网页文件复制到网站的目录:
1
| cp sub-web/dist/* /var/www/foo.domain.com/html/ -r
|
Test:
目的: 通过 cloudflare 的代理 (代理状态记得打开), 防止 ip 暴露。
/etc/nginx/sites-available/bar.domain.com:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| # 代理相关头部
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# 反向代理配置
location / {
# 反向代理到本地服务
proxy_pass http://127.0.0.1:<port>;
# 代理超时设置
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
# 缓冲区设置
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 4k;
}
|
Test:
添加订阅文件站点
/etc/nginx/sites-available/baz.domain.com:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
| # 根目录 - 返回404,不提供任何信息
location = / {
return 404;
access_log off;
log_not_found off;
}
# 主文件服务位置
location /file/ {
# 文件根目录
alias /www/server/file_store/;
# 关键安全设置:完全禁用目录浏览
autoindex off;
# 禁用符号链接跟随
disable_symlinks on;
# 尝试访问文件,如果不存在则返回404
try_files $uri =404;
# 安全头部
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options DENY;
# 根据文件扩展名设置MIME类型
location ~* \.yaml$ {
types { }
default_type application/yaml;
add_header Content-Disposition "attachment";
}
location ~* \.yml$ {
types { }
default_type application/yaml;
add_header Content-Disposition "attachment";
}
location ~* \.json$ {
types { }
default_type application/json;
}
location ~* \.txt$ {
types { }
default_type text/plain;
}
}
# 禁止访问隐藏文件(.开头的文件)
location ~ /\. {
deny all;
access_log off;
log_not_found off;
return 404;
}
# 可选:限制某些敏感文件扩展名
location ~* \.(conf|config|ini|sql|env)$ {
deny all;
return 404;
}
|
Test:
1
| curl -LO https://baz.domain.com/file/<file_name>
|
添加域名重定向
目的: 简单地伪装大流量网站 (网盘网站)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
| server {
listen 80;
listen [::]:80;
server_name qux.domain.com;
# HTTP 重定向到目标网站
return 301 http://pan.qiangsungroup.cn$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name qux.domain.com;
# SSL 证书路径(保持原有证书)
ssl_certificate /root/.acme.sh/qux.domain.com_ecc/fullchain.cer;
ssl_certificate_key /root/.acme.sh/qux.domain.com_ecc/qux.domain.com.key;
# SSL 配置
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
# HTTPS 也重定向到目标网站(注意:目标网站是 HTTP)
return 301 http://pan.qiangsungroup.cn$request_uri;
# 可选:添加一些头部信息
add_header X-Redirected-From "qux.domain.com" always;
add_header X-Redirected-To "pan.qiangsungroup.cn" always;
}
|
Test: