Appearance
HTTPS 免费证书申请与自动续期指南
定位:本文档旨在提供一套在 Linux 服务器上通过
acme.sh申请 Let's Encrypt 免费 SSL 证书,并与 Nginx (特别是 Docker 容器化 Nginx) 完美结合的标准操作流程。核心优势:无需手动干预,证书到期前自动续期并热重载 Nginx。
1. 安装与初始化 acme.sh
acme.sh 是一个极为轻量且强大的 ACME 协议客户端。
1.1 一键安装
bash
# 下载并安装 acme.sh
curl https://get.acme.sh | sh
# 使环境变量立即生效
source ~/.bashrc1.2 注册邮箱并切换默认 CA
目前 acme.sh 默认使用 ZeroSSL,建议切换回兼容性更好的 Let's Encrypt。
bash
# 注册邮箱(请替换为你的真实邮箱,用于接收证书过期提醒)
acme.sh --register-account -m your_email@example.com --server letsencrypt
# 将 Let's Encrypt 设置为默认 CA
acme.sh --set-default-ca --server letsencrypt2. 申请证书 (Webroot 验证模式)
前提条件:
- 你的域名(如
app.example.com)已正确解析到当前服务器的公网 IP。- 服务器已开放 80 端口,且 Nginx 正在运行。
2.1 Nginx 验证配置
为了让 Let's Encrypt 能够通过 80 端口验证你对域名的所有权,我们需要在 Nginx 配置中指定一个静态资源目录(Webroot)。
在你的 Nginx 配置 (conf.d/app.conf) 中添加:
nginx
server {
listen 80;
server_name app.example.com;
# 专门用于 ACME 验证的路径
location ^~ /.well-known/acme-challenge/ {
# 这里的路径必须映射到宿主机上的某个目录,例如 ./static
alias /usr/share/nginx/html/static/.well-known/acme-challenge/;
try_files $uri =404;
}
# 其他业务逻辑或跳转...
}2.2 签发证书
假设你在宿主机的 Nginx 网关目录下,静态目录位于 ./static/,执行以下命令签发证书:
bash
acme.sh --issue -d app.example.com --webroot ./static/ --server letsencrypt如果一切正常,终端会显示绿色字体的 Cert success。
3. 安装证书并配置自动重载
⚠️ 警告:千万不要直接使用 ~/.acme.sh/ 目录下的证书文件,这些是内部文件,路径结构可能会变。必须使用 --install-cert 命令将证书“导出”到你的业务目录。
3.1 安装到 Nginx 挂载目录
假设你的 Nginx SSL 证书挂载目录为宿主机的 ./ssl/:
bash
# 确保目录存在
mkdir -p ./ssl/
# 如果你是普通用户,可能需要修复权限
# sudo chown -R $(whoami):$(whoami) ./ssl/
# 安装证书,并配置自动续期时的重载命令
acme.sh --install-cert -d app.example.com \
--key-file ./ssl/app.example.com.key \
--fullchain-file ./ssl/app.example.com.crt \
--reloadcmd "docker exec hub-nginx nginx -s reload"参数说明:
--reloadcmd:当acme.sh自动续期成功后,会自动执行这条命令让 Nginx 重新加载证书,无需重启容器。
4. Nginx 业务配置
证书就绪后,我们需要配置 Nginx 处理 HTTPS 流量。这里提供两种常见的业务模式。
模式 A:强制 HTTPS 跳转 (推荐)
最安全的标准模式,所有 HTTP 流量都会被 301 重定向到 HTTPS。
nginx
# 80 端口配置
server {
listen 80;
server_name app.example.com;
# 保留 ACME 验证路径
location ^~ /.well-known/acme-challenge/ {
alias /usr/share/nginx/html/static/.well-known/acme-challenge/;
try_files $uri =404;
}
# 其他所有请求强制跳转 HTTPS
location / {
return 301 https://$host$request_uri;
}
}
# 443 端口配置
server {
listen 443 ssl;
server_name app.example.com;
# 证书路径 (容器内的路径)
ssl_certificate /etc/nginx/ssl/app.example.com.crt;
ssl_certificate_key /etc/nginx/ssl/app.example.com.key;
location / {
proxy_pass http://backend-app:8080;
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 https;
}
}模式 B:HTTP 与 HTTPS 并存 (兼容模式)
如果不希望破坏现有的纯 HTTP 链路(例如某些老旧客户端不支持 HTTPS,或为了最小化对已有架构的改动),可以配置两者并存,不进行跳转。
nginx
# 80 端口正常提供服务
server {
listen 80;
server_name app.example.com;
location ^~ /.well-known/acme-challenge/ {
alias /usr/share/nginx/html/static/.well-known/acme-challenge/;
try_files $uri =404;
}
location / {
proxy_pass http://backend-app:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 传递 scheme 为 http
proxy_set_header X-Forwarded-Proto $scheme;
}
}
# 443 端口同样提供服务
server {
listen 443 ssl;
server_name app.example.com;
ssl_certificate /etc/nginx/ssl/app.example.com.crt;
ssl_certificate_key /etc/nginx/ssl/app.example.com.key;
location / {
proxy_pass http://backend-app:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 传递 scheme 为 https
proxy_set_header X-Forwarded-Proto https;
}
}5. 重载与验证
配置完成后,测试 Nginx 配置并使其生效:
bash
docker exec hub-nginx nginx -t
docker exec hub-nginx nginx -s reload验证方法:
- 打开浏览器访问
https://app.example.com,点击地址栏的锁图标,确认证书颁发机构为Let's Encrypt,且无安全警告。
6. 日常运维说明
自动续期:
acme.sh安装时已自动在系统中添加了 Cron 定时任务,每天会检查证书是否即将过期(通常是到期前 30 天内),如果满足条件将自动续期并执行配置的reloadcmd。你无需任何手动干预。强制续期:如果需要手动强制续期,可执行:
bashacme.sh --renew -d app.example.com --force
