服务器怎么配置SSL证书

结论: 给服务器配置 SSL 证书最快的方式是用 Let's Encrypt 免费证书:安装 certbot 与 python3-certbot-nginx 插件,执行 certbot --nginx -d 你的域名 自动签发并改写 Nginx 配置,放行 443 端口即可。证书有效期 90 天,必须配置自动续期(系统默认自带 timer),并用 certbot renew --dry-run 定期验证续期链路可用。

SSL 证书(TLS Certificate)的作用是在浏览器与服务器之间建立加密通道,让地址栏出现锁标志、URL 前缀变成 HTTPS。截至 2026 年,主流浏览器已对未加密的 HTTP 站点强制标记"不安全",搜索引擎也会降低其收录权重,因此 HTTPS 不再是加分项而是底线。本文只讲 Let's Encrypt 免费证书的自动化签发与续期这条路径,商业证书(OV / EV)、多平台(Apache、Tomcat、IIS)安装方式属于另一篇的范畴。

Let's Encrypt 证书是什么,为什么默认选它

结论:Let's Encrypt 是由 ISRG 运营的免费、自动化、开放的证书颁发机构(CA),单张证书有效期 90 天,通过 ACME 协议自动完成域名归属验证。 它对个人站点、中小企业官网、API 服务完全够用。

对比项Let's Encrypt(DV)商业 DV 证书商业 OV / EV 证书
价格免费每年几百元每年千元至万元级
签发速度1~5 分钟10~30 分钟1~7 个工作日
有效期90 天通常 398 天通常 398 天
验证方式自动(HTTP-01 / DNS-01)自动或邮箱验证需核验企业营业执照
浏览器显示锁标志锁标志EV 曾显示公司名(现已普遍取消)
保险赔付无有,额度不等有,额度较高
适用场景博客、官网、API、内部系统小型商业站点金融、电商、政务

免费证书的三个硬限制,事先要知道

  • 有效期只有 90 天:这是刻意设计,倒逼使用者实现自动化续期,手工续期必然出错。
  • 只做域名验证(DV):证书里不含企业信息,无法用来证明主体身份,金融类业务不合规。
  • 有签发速率限制:截至 2026 年,同一注册域名每周最多签发 50 张证书,同一组域名重复签发每周上限 5 张。调试时务必加 --dry-run,否则会被限流数小时。

申请前的四项前置检查

结论:签发失败九成是因为前置条件没满足。 花两分钟确认下面四项,能省掉后面绝大部分排查时间。

bash
# 1. 域名已解析到本机,且解析结果与本机公网 IP 一致
dig +short example.com
curl -s ifconfig.me

# 2. Nginx 已配置该域名的 server_name(certbot 靠它定位配置块)
sudo nginx -T | grep -n "server_name"

# 3. 80 端口处于监听状态(HTTP-01 挑战必须通过 80 端口验证)
sudo ss -lntp | grep ':80'

# 4. 443 端口当前是否被占用(一般为空,签发后由 Nginx 监听)
sudo ss -lntp | grep ':443'
  • 第 1 项不成立,ACME 服务器访问不到你的机器,验证必然失败。
  • 第 2 项不成立,certbot 找不到要改写的配置块,会提示无法识别域名。
  • 第 3 项中 80 端口若被其他进程占用(如另一个 Web 服务),需要临时停掉或改用 DNS-01 验证方式。
  • 服务器位于国内时,域名必须已完成 ICP 备案,否则 80 端口入站被拦截,验证同样失败。

第一步:安装 certbot 与 Nginx 插件

结论:Ubuntu 24.04 直接用 apt 安装 certbot 与 python3-certbot-nginx 即可,其中 Nginx 插件负责自动读取和改写站点配置,不要只装 certbot 本体。

bash
# ===== Ubuntu 24.04 / Debian 12 =====
sudo apt update
sudo apt install -y certbot python3-certbot-nginx

# ===== CentOS Stream 9 / Rocky Linux 9 =====
sudo dnf install -y epel-release
sudo dnf install -y certbot python3-certbot-nginx

# 验证安装版本
certbot --version

插件名中的 nginx 就是"authenticator + installer"的组合:--nginx 表示既用 Nginx 完成验证,也由它自动写入证书路径。若服务器上已有其他服务占用 80 端口且不能停,可改用 certbot certonly --webroot -w /var/www/html,只签证书不改配置,再手工引用。

第二步:一键签发证书

结论:一条 certbot --nginx -d 命令即可完成域名验证、证书签发与 Nginx 配置改写三件事。 多个域名用多个 -d 参数,第一个为主域名(Common Name)。

bash
# 同时签发根域名与 www(推荐,一张证书覆盖两个名字)
sudo certbot --nginx -d example.com -d www.example.com

# 只签证书不改动 Nginx 配置(webroot 模式)
sudo certbot certonly --webroot -w /var/www/example.com -d example.com

# 首次运行会交互式询问:
#   1) 邮箱地址(用于到期提醒与安全通告)
#   2) 是否同意服务条款(输入 A 回车)
#   3) 是否共享邮箱给 EFF(选 N 不影响使用)
#   4) 是否把 HTTP 重定向到 HTTPS(选 2 = Redirect,强烈建议)

# 查看已签发的证书列表与到期时间
sudo certbot certificates

成功时输出会包含 Congratulations! Your certificate and chain have been saved at: /etc/letsencrypt/live/example.com/fullchain.pem。证书文件保存在 /etc/letsencrypt/live/域名/ 目录下,四个文件各有用途:

  • cert.pem:服务器证书本身,一般不用直接引用。
  • chain.pem:中间证书(Intermediate CA),用于构建信任链。
  • fullchain.pem:cert.pem + chain.pem 的合并,Nginx 应引用这个。
  • privkey.pem:私钥,绝对不能外传,权限应为 600。

第三步:确认 Nginx 配置块已被正确改写

结论:certbot 会在原 server 块中插入 ssl_certificate(指向 fullchain.pem)与 ssl_certificate_key(指向 privkey.pem),并新增一个 443 监听块。 理解这几个指令,才能手工排查证书链问题。

nginx
server {
    listen 443 ssl;
    listen [::]:443 ssl;
    http2 on;

    server_name example.com www.example.com;
    root /var/www/example.com;
    index index.html index.php;

    # 证书链:fullchain.pem 已包含中间证书,浏览器才能追溯到根 CA
    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_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;

    access_log /var/log/nginx/example.access.log;
}

# certbot 自动生成的 HTTP 跳转块
server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://$host$request_uri;
}

证书链(Certificate Chain)是指"服务器证书 → 中间证书 → 根证书"的信任传递关系。如果只配 cert.pem 而不配中间证书,多数桌面浏览器能靠缓存补全,但移动端、curl、Java 客户端会直接报 unable to get local issuer certificate。因此永远引用 fullchain.pem,这是最容易被忽略却最难排查的一个细节。

第四步:放行 443 端口并验证

结论:HTTPS 使用 443 端口,必须在系统防火墙与云平台安全组两处同时放行。 只签了证书没开端口,浏览器会停在"连接超时"。

bash
# Ubuntu / Debian
sudo ufw allow 443/tcp
sudo ufw reload

# CentOS Stream 9 / Rocky Linux 9
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload

# 重载 Nginx 使证书生效
sudo nginx -t && sudo systemctl reload nginx

# 验证 HTTP 是否跳转 HTTPS
curl -I http://example.com          # 期望 301 Moved Permanently
# 验证 HTTPS 返回码
curl -I https://example.com         # 期望 200 OK

# 查看证书有效期与颁发者
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
  | openssl x509 -noout -subject -issuer -dates

第五步:配置自动续期

结论:Let's Encrypt 证书 90 天到期,必须靠定时任务续期。certbot 的 apt/dnf 安装包默认已注册 systemd timer,一般无需手工加 crontab,但一定要用 --dry-run 实测一次。

bash
# 查看系统自带的续期定时器(Ubuntu 24.04 默认为 certbot.timer)
systemctl list-timers | grep certbot
systemctl status certbot.timer --no-pager

# 强制演练一次续期(不会真的换证书,用的是测试环境)
sudo certbot renew --dry-run
# 出现 "The dry run was successful" 即表示续期链路通畅

# 手工立即续期(仅在证书快到期时用)
sudo certbot renew

# 续期后让 Nginx 加载新证书(certbot 的 nginx 插件会自动 reload,此行用于 certonly 模式)
sudo systemctl reload nginx

若系统没有 timer(例如用 snap 安装的 certbot),可自行加一条 crontab:

bash
# 每天凌晨 3:17 检查续期,仅当剩余有效期 < 30 天时才真正签发
sudo crontab -e
17 3 * * * /usr/bin/certbot renew --quiet --deploy-hook "systemctl reload nginx"

注意 certbot renew 是幂等的:证书剩余有效期超过 30 天时它什么也不做,所以每天执行不会有速率问题。

续期失败的三种常见原因

  1. 80 端口被占用或被拦截:HTTP-01 验证要求 ACME 服务器能访问你域名的 80 端口。Nginx 之外的程序占用 80、安全组临时关闭 80、或国内未备案导致 80 被云厂商拦截,都会报 Connection refused / Timeout during connect。
  2. DNS 验证失败:使用 DNS-01 方式时,插件需要调用 DNS 服务商 API 写入 TXT 记录。API Token 过期、权限不足、TXT 记录尚未传播完成(TTL 未过),都会报 Incorrect TXT record。改用 HTTP-01 或更新 Token 即可解决。
  3. 权限不足:certbot renew 必须以 root 身份运行(或用 sudo),否则无法写入 /etc/letsencrypt 与重载 Nginx。crontab 里应写绝对路径 /usr/bin/certbot,并确认加在 root 的 crontab 而非普通用户下。