SSL 证书与 HTTPS:用 Certbot 0成本启动全站加密
📂 所属阶段:第六阶段 — 上线部署(生产篇)
🔗 相关章节:Gunicorn 与 Nginx · Docker 部署全流程
1. 为什么上线前必须上 HTTPS?
咱们先来看最直观的场景对比——用户输入密码的那一刻:
HTTP(裸奔模式,踩过坑的都懂 😭)
┌─────────────┐ 明文传输 ┌──────────────┐ 明文截获 ┌─────────────┐
│ 用户浏览器 │ ─────────> │ 中间节点/WiFi │ ─────────> │ 黑客控制台 │
└─────────────┘ └──────────────┘ └─────────────┘
HTTPS(加密保险箱模式 ✅)
┌─────────────┐ SSL/TLS 加密 ┌──────────────┐ 加密绕过 ┌─────────────┐
│ 用户浏览器 │ ──────────────> │ 中间节点/WiFi │ ──────────> │ 黑客(啥也看不到) │
└─────────────┘ └──────────────┘ └─────────────┘
↓ 密文直接转发
┌──────────────┐
│ 你的后端服务器 │ ← 只有你有私钥解密
└──────────────┘
除了最核心的防数据泄露,HTTPS 现在还有5个不可替代的生产级优势:
- 防 ISP/公共WiFi 的流量劫持+恶意广告插入
- 防中间人篡改你的 HTML/CSS/JS(比如给按钮加钓鱼链接)
- SEO 硬门槛:Google/Baidu 现在直接把 HTTPS 设为搜索排序加分项,甚至有的纯 HTTP 站会被降权
- 浏览器信任标识:Chrome/Firefox 现在把纯 HTTP 站标红加「不安全」提示,转化率直接跌20%+
- 开启 HTTP/2 协议的前提:HTTP/2 能把网站加载速度提30%-50%,但所有主流浏览器都要求 HTTPS 才支持
2. 0成本搞定90天自动续期的证书
国内很多免费证书要么是1年换一次手动麻烦,要么是只支持单域名,要么是来路不明的小机构。全球最靠谱的免费证书方案,绝对是 Let's Encrypt + Certbot 的组合拳。
2.1 先搞懂俩角色
- Let's Encrypt(非盈利证书颁发机构):背后有 Google、Microsoft、Mozilla 等大厂背书,所有主流浏览器都信任,证书永久免费、支持多域名/通配符、90天有效期
- Certbot(官方自动化工具):帮你一键「申请证书→配置Web服务器→设置自动续期」,全程不超过5分钟
2.2 安装 Certbot(主流系统一键走)
Certbot 对不同系统的适配都很完善,直接用包管理器就行:
# Ubuntu / Debian(最常用的云服务器系统)
sudo apt update && sudo apt install -y certbot python3-certbot-nginx
# CentOS 7 / RHEL 7
sudo yum install -y epel-release && sudo yum install -y certbot python3-certbot-nginx
# CentOS 8+ / RHEL 8+ / Rocky Linux
sudo dnf install -y certbot python3-certbot-nginx
# macOS(本地测试用)
brew install certbot
2.3 新手推荐:Nginx 全自动配置版
如果你已经用 Nginx 配置好了 HTTP 站点(比如前面学过的 Gunicorn + Nginx),直接用这个命令就行,Certbot 会自动帮你完成所有步骤:
# 把 daomanpy.com 换成你自己的主域名,www 可以加多个二级域名
sudo certbot --nginx -d daomanpy.com -d www.daomanpy.com
输入命令后会有4个简单的交互:
- 邮箱地址:用来接收证书过期的紧急通知(只发2-3封,不会垃圾邮件)
- 同意服务条款:必须选 A(Agree)
- 是否共享邮箱给 EFF:选 Y 或 N 都行(EFF 是推动网络隐私的非营利组织)
- 是否自动跳转 HTTPS:强烈建议选 2(Redirect,强制把所有 HTTP 请求301永久重定向到 HTTPS,防止 Mixed Content 问题)
完成后你会看到「Congratulations!」的提示,刷新浏览器,你的网站就已经有小绿锁(或者安全盾牌)了!
2.4 进阶/自定义版:只拿证书自己配
如果你用的不是 Nginx,或者不想让 Certbot 改你的 Nginx 配置,也可以只申请证书,自己手动配置Web服务器:
# --nginx 这里是用「Nginx临时验证」的方式验证域名所有权
# --webroot 是另一种常用的验证方式(Nginx配置了静态目录的话)
# 以下两种选一种就行:
# 方式1:Nginx临时验证(推荐,不用改现有配置)
sudo certbot certonly --nginx -d daomanpy.com -d www.daomanpy.com
# 方式2:Webroot验证(假设你的Nginx静态目录是/var/www/html)
sudo certbot certonly --webroot -w /var/www/html -d daomanpy.com -d www.daomanpy.com
申请成功后,证书会放在 /etc/letsencrypt/live/你的域名/ 目录下(软链接指向最新的证书,续期后不用改路径),我们只需要两个文件:
fullchain.pem:证书链(给浏览器看的,包含中间证书和根证书)
privkey.pem:私钥(只有你自己的服务器有,千万别泄露!)
3. 进阶版安全 Nginx HTTPS 配置
如果用了 Certbot 的全自动配置,它会给你生成一个基础的 HTTPS 配置,但要拿到 SSLLabs 的 A+ 评分(生产级安全标准),还要加一些额外的安全配置。
这里给大家一个经过验证的、兼容主流浏览器(Chrome 60+、Firefox 55+、Safari 12+)的完整 HTTPS 配置模板,直接替换你的 /etc/nginx/conf.d/你的域名.conf 就行:
# /etc/nginx/conf.d/daomanpy.conf
# 注意:把所有 daomanpy.com 换成你自己的域名
# --------------------------
# 1. HTTP → HTTPS 强制重定向(301永久跳转)
# --------------------------
server {
listen 80;
listen [::]:80; # IPv6支持(云服务器一般都支持,加上更好)
server_name daomanpy.com www.daomanpy.com;
# 保留 Let's Encrypt 的验证路径(续期时必须能访问)
location /.well-known/acme-challenge/ {
root /var/www/html;
}
# 其他所有请求301跳转
return 301 https://$host$request_uri;
}
# --------------------------
# 2. HTTPS 主站配置
# --------------------------
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name daomanpy.com www.daomanpy.com;
# 根目录和入口(如果是静态站需要,反向代理可以不加,但加了更规范)
root /var/www/daoman;
index index.html index.htm;
# --------------------------
# SSL 核心配置(必须改路径)
# --------------------------
ssl_certificate /etc/letsencrypt/live/daomanpy.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/daomanpy.com/privkey.pem;
# --------------------------
# SSL 安全优化(Mozilla 推荐的 Intermediate 级配置)
# --------------------------
ssl_protocols TLSv1.2 TLSv1.3; # 只留安全的协议版本(TLS1.0/1.1 已被禁用)
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; # 只留安全的加密套件
ssl_prefer_server_ciphers off; # 让浏览器自己选最优的加密套件(TLS1.3 不需要,但兼容老版本)
ssl_session_cache shared:SSL:10m; # SSL 会话缓存(减少握手时间,提升性能)
ssl_session_timeout 1d; # 会话缓存有效期1天
ssl_session_tickets off; # 关闭会话票证(防止部分安全漏洞)
# --------------------------
# OCSP Stapling(优化证书验证速度)
# --------------------------
ssl_stapling on; # 开启 OCSP Stapling(服务器代替浏览器去验证证书有效性,减少网络延迟)
ssl_stapling_verify on; # 验证 OCSP 响应的有效性
resolver 8.8.8.8 8.8.4.4 valid=300s; # DNS 解析器(Google的,也可以换国内的114.114.114.114)
resolver_timeout 5s; # DNS 超时时间5秒
# --------------------------
# 安全响应头(防止常见的 Web 攻击)
# --------------------------
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; # HSTS(强制浏览器1年内只访问HTTPS,preload可选但需要申请)
add_header X-Frame-Options "SAMEORIGIN" always; # 防止点击劫持
add_header X-Content-Type-Options "nosniff" always; # 防止 MIME 类型嗅探
add_header Referrer-Policy "strict-origin-when-cross-origin" always; # 控制 Referer 头的发送
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always; # 控制浏览器API的访问权限
# --------------------------
# 反向代理到 Gunicorn(Flask/Django 等后端项目需要)
# --------------------------
location / {
proxy_pass http://127.0.0.1:8000; # Gunicorn 监听的端口
proxy_http_version 1.1;
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; # 告诉后端当前是 HTTPS 协议
proxy_redirect off;
proxy_connect_timeout 60s;
proxy_read_timeout 60s;
client_max_body_size 20M; # 允许上传的最大文件大小(根据项目调整)
}
# --------------------------
# 静态文件(Nginx 直接服务,比后端快10倍+)
# --------------------------
location /static/ {
alias /var/www/daoman/static/; # 静态文件目录(根据项目调整)
expires 30d; # 静态文件缓存30天
add_header Cache-Control "public, immutable"; # 告诉浏览器缓存期间不用重新请求
access_log off; # 静态文件访问日志可以关,减少磁盘IO
}
# --------------------------
# 健康检查(负载均衡/监控需要)
# --------------------------
location /health {
return 200 "healthy\n";
add_header Content-Type text/plain;
access_log off;
}
}
配置完成后,记得先验证 Nginx 配置是否正确,再重启 Nginx:
# 验证配置
sudo nginx -t
# 如果显示「syntax is ok」和「test is successful」,再重启
sudo systemctl reload nginx # 用 reload 不用 restart,避免服务中断
4. 90天自动续期:一劳永逸的设置
Let's Encrypt 的证书只有90天有效期,这是为了安全考虑(万一私钥泄露,影响时间也短)。Certbot 自带自动续期功能,我们只需要设置一个定时任务就行。
4.1 先测试续期是否正常
在正式设置定时任务之前,一定要先用 dry-run 模式测试(不会真的续期,只是验证流程):
sudo certbot renew --dry-run
如果显示「Congratulations, all renewals succeeded」,说明测试通过!
4.2 配置定时续期(两种主流方式)
方式1:systemd timer(Ubuntu 18.04+ / CentOS 8+ 推荐)
现在的主流 Linux 发行版默认已经安装了 Certbot 的 systemd timer,只需要检查是否启动即可:
# 检查 timer 状态
sudo systemctl status certbot.timer
# 如果没启动,手动启动并设置开机自启
sudo systemctl enable --now certbot.timer
# 查看所有 systemd timers,确认 certbot.timer 在里面
sudo systemctl list-timers
默认的 timer 是每天凌晨2点左右检查续期(有随机偏移,避免同时请求 Let's Encrypt 服务器),如果续期成功,还会自动 reload Nginx(Certbot 会自动检测你用的是 Nginx 还是 Apache)。
方式2:crontab(老系统兼容)
如果你的系统没有 systemd,或者想自己控制续期时间,可以用 crontab:
# 编辑 root 用户的 crontab(必须用 root,因为证书目录只有 root 能访问)
sudo crontab -e
# 在文件末尾添加这一行(每天凌晨3点检查续期,续期成功后 reload Nginx)
0 3 * * * certbot renew --quiet --renew-hook "systemctl reload nginx"
5. 检查你的 HTTPS 安全等级
配置完成后,一定要用在线工具检测一下安全等级,确保没有漏洞:
5.1 在线检测(推荐)
5.2 本地简单测试
# 测试 SSL 连接是否正常
openssl s_client -connect daomanpy.com:443 -servername daomanpy.com
# 查看证书的详细信息(有效期、颁发机构等)
openssl x509 -in /etc/letsencrypt/live/daomanpy.com/fullchain.pem -text -noout
6. 避坑指南:常见的 HTTPS 问题
6.1 Mixed Content(混用 HTTP/HTTPS)警告
如果浏览器显示「小绿锁旁边有个感叹号」,或者控制台有 Mixed Content 的错误,说明你的网站里还有HTTP 协议的资源(比如图片、CSS、JS、字体)。
解决方法:把所有资源的 URL 改成 https:// 开头,或者直接用 // 开头的相对协议(自动跟随当前页面的协议)。
6.2 证书续期失败
如果续期时显示「Failed authorization procedure」,一般是因为Let's Encrypt 的验证路径无法访问:
- 检查 Nginx 配置里的
.well-known/acme-challenge/ 路径是否正确
- 检查防火墙是否开放了 80 端口(续期时必须用 80 端口验证)
- 检查域名解析是否正常(
ping 你的域名 看看能不能通)
7. 小结
全站 HTTPS 现在已经是生产级项目的标配,用 Let's Encrypt + Certbot 0成本就能搞定,全程不超过10分钟。
快速回顾部署流程:
- 安装 Certbot 和对应的 Web 服务器插件
- 用
certbot --nginx -d 你的域名 全自动申请+配置
- (可选)替换成进阶版的安全 Nginx 配置
- 检查自动续期是否正常
- 用 SSLLabs 检测安全等级
💡 生产级最后提醒:
- 一定要设置 HSTS 头,防止用户误访问 HTTP 站点
- 定期(比如每月)用 SSLLabs 检测一下安全等级
- 千万不要把
privkey.pem 私钥上传到 Git 仓库!
🔗 扩展阅读