本文适用场景:通过 Nginx 部署 Hexo 博客,并实现 *.example.com 型泛域名 HTTPS 支持,通过设置泛域名证书,通过Nginx子域名部署其他服务都可以使用。

前置准备

  1. 域名要求

    • 已注册主域名(如 example.com
    • 完成域名解析(将 *.example.com A 记录指向服务器 IP)
  2. 服务器环境

    # 检查 Nginx 版本(需 ≥ 1.15.9)
    nginx -v
    # 安装 Certbot(以 Ubuntu 为例)
    sudo apt update && sudo apt install certbot python3-certbot-nginx

申请泛域名 SSL 证书

通过 Certbot 申请证书

sudo certbot certonly \
--manual \ # 手动模式
--preferred-challenges=dns \ # DNS 验证
--server https://acme-v02.api.letsencrypt.org/directory \
-d "*.example.com" \ # 泛域名
-d example.com # 主域名(可选)

DNS 验证操作

  1. 根据 Certbot 提示,在域名 DNS 中添加 TXT 记录:

    _acme-challenge.example.com. 300 IN TXT "gfj9X4...dyt67"
  2. 等待 DNS 生效(约 2-5 分钟),按回车继续

配置 Nginx 泛域名解析

基础配置示例

创建 /etc/nginx/sites-available/hexo.conf

{% raw %}
server {
listen 80;
server_name ~^(?<subdomain>.+)\.example\.com$ example.com;
return 301 https://$host$request_uri;
}

server {
listen 443 ssl http2;
server_name ~^(?<subdomain>.+)\.example\.com$ example.com;

# 泛域名证书路径
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

# 安全协议配置
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers on;

# Hexo 静态文件路径
root /var/www/hexo;
index index.html;

# 缓存与压缩配置
gzip on;
gzip_types text/css application/json application/javascript;

location / {
try_files $uri $uri/ =404;
}

# 禁止访问 .md 源文件
location ~* \.md$ {
deny all;
}
}
{% endraw %}

启用配置

sudo ln -s /etc/nginx/sites-available/hexo.conf /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

配置 Systemd 定时器自动续期

启用 Certbot 官方定时器

# 查看定时器状态
systemctl list-timers | grep certbot

# 启用并启动定时器
sudo systemctl enable --now certbot.timer

验证定时器规则

systemctl cat certbot.timer

# 输出关键部分示例:
[Timer]
OnCalendar=*-*-* 00:00:00 # 每天触发
RandomizedDelaySec=12h # 随机延迟 0-12 小时

设置续期后自动重载 Nginx

sudo nano /etc/letsencrypt/cli.ini

添加内容:

deploy-hook = systemctl reload nginx

验证与测试

手动测试续期流程

# 模拟续期(不实际更新证书)
sudo certbot renew --dry-run

# 强制立即续期(测试用)
sudo certbot renew --force-renewal

查看续期日志

journalctl -u certbot.service --since "1 hour ago"

验证证书有效期

openssl x509 -enddate -noout -in /etc/letsencrypt/live/example.com/fullchain.pem
# 输出示例:notAfter=Jun 30 23:59:59 2025 GMT

最佳实践建议

调整定时器触发时间(可选)

sudo systemctl edit certbot.timer

输入:

[Timer]
OnCalendar=*-*-* 02:30:00 # 每天 2:30 执行
RandomizedDelaySec=0 # 取消随机延迟

重启生效:

sudo systemctl restart certbot.timer

监控证书状态

# 查看下次续期时间
systemctl list-timers | grep certbot

故障排查

问题:定时器未触发

解决步骤

  1. 检查定时器状态:
systemctl status certbot.timer
  1. 查看系统时钟同步:
timedatectl status
  1. 手动触发调试:
sudo systemctl start certbot.service

通过以上配置,你的泛域名证书将完全由 Systemd 定时器 自动管理,无需手动干预。访问 SSL Labs 验证 HTTPS 配置完整性。

统一管理SSL配置

创建全局 SSL 配置

新建 /etc/nginx/conf.d/ssl.conf

# ================== 全局 SSL 配置 ==================
# 证书路径(泛域名)
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

# SSL 协议与加密套件(Certbot 自动优化)
include /etc/letsencrypt/options-ssl-nginx.conf;

# Diffie-Hellman 参数增强安全性
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

# OCSP 装订(加速 SSL 握手)
ssl_stapling on;
ssl_stapling_verify on;

# 缓存 SSL 会话(提升性能)
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;

# 安全响应头(可选)
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options SAMEORIGIN;

配置多服务代理示例

Hexo 博客配置

/etc/nginx/sites-available/hexo.conf

server {
listen 443 ssl http2;
server_name blog.example.com;

# 引入全局 SSL 配置
include /etc/nginx/conf.d/ssl.conf;

# Hexo 静态文件路径
root /var/www/hexo;
index index.html;

location / {
try_files $uri $uri/ =404;
}
}

Nextcloud 服务配置

/etc/nginx/sites-available/nextcloud.conf

server {
listen 443 ssl http2;
server_name cloud.example.com;

# 引入全局 SSL 配置
include /etc/nginx/conf.d/ssl.conf;

# 反向代理到内部服务
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}

主域名重定向

/etc/nginx/sites-available/redirect.conf

server {
listen 80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}

server {
listen 443 ssl http2;
server_name example.com www.example.com;

include /etc/nginx/conf.d/ssl.conf;

# 主域名跳转到博客
return 301 https://blog.example.com;
}

操作验证

检查语法并重载

sudo nginx -t && sudo systemctl reload nginx

测试所有子域名

# 测试 Hexo
curl -I https://blog.example.com

# 测试 Nextcloud
curl -I https://cloud.example.com

# 验证 OCSP 装订
openssl s_client -connect blog.example.com:443 -status

维护与更新

证书续期后统一生效

所有服务共用同一证书,续期后只需一次重载:

sudo certbot renew --post-hook "systemctl reload nginx"

更新 SSL 配置

修改 /etc/nginx/conf.d/ssl.conf 后,所有服务自动继承新配置。

注意事项

  1. 避免重复包含
    • 每个 server 块只能包含一次 include /etc/letsencrypt/options-ssl-nginx.conf;
    • 公共配置中的参数会被 最后一个包含的文件覆盖
  2. 多证书混合场景
    若部分服务使用独立证书,可在对应 server 块中覆盖路径:
server {
listen 443 ssl http2;
server_name special.example.com;

# 覆盖证书路径
ssl_certificate /path/to/special/fullchain.pem;
ssl_certificate_key /path/to/special/privkey.pem;

include /etc/nginx/conf.d/ssl.conf; # 其他配置仍继承
}

通过这种配置,你可以实现 一处修改,全局生效,极大简化多服务的 SSL 管理。完整配置示例可参考 GitHub Gist。