Nginx HTTPS 配置与 SSL 证书管理完整教程
Nginx HTTPS 配置与 SSL 证书管理完整教程
前言:为什么需要 HTTPS
在当今的互联网环境中,HTTPS 已经不再是可选项,而是必需品。无论是个人博客、企业官网还是电商平台,启用 HTTPS 都是保障用户安全和提升网站可信度的基础要求。
HTTPS 的核心价值
- 数据加密传输:防止数据在传输过程中被窃听和篡改,保护用户的敏感信息(如密码、支付信息)
- 身份验证:确认网站的真实身份,防止钓鱼网站和中间人攻击
- 数据完整性:确保数据在传输过程中没有被修改
- SEO 优化:Google 等搜索引擎将 HTTPS 作为排名信号,HTTPS 网站在搜索结果中更有优势
- 浏览器信任:现代浏览器对 HTTP 网站会标记为”不安全”,影响用户体验和信任度
- 功能支持:许多现代 Web 功能(如 Service Worker、HTTP/2、地理位置 API)要求必须使用 HTTPS
HTTP vs HTTPS 对比
| 特性 | HTTP | HTTPS |
|---|---|---|
| 端口 | 80 | 443 |
| 协议 | 明文传输 | SSL/TLS 加密 |
| 安全性 | 低,易被窃听篡改 | 高,加密传输 |
| 证书 | 不需要 | 需要 SSL 证书 |
| 速度 | 略快(无加密开销) | 略慢(加密解密开销) |
| SEO | 无优势 | 有排名优势 |
| 浏览器标记 | 标记为”不安全” | 显示锁形图标 |
HTTPS 与 SSL 证书基础
工作原理
HTTPS 是在 HTTP 基础上加入 SSL/TLS 协议层实现的安全传输协议。其工作流程如下:
- 握手阶段:客户端与服务器建立连接,协商加密算法和协议版本
- 证书验证:服务器发送 SSL 证书,客户端验证证书的合法性
- 密钥交换:双方协商生成会话密钥,用于后续的对称加密
- 加密通信:使用会话密钥进行加密数据传输
SSL/TLS 协议版本
- SSL 3.0:已废弃,存在安全漏洞
- TLS 1.0:已废弃,不推荐使用
- TLS 1.1:已废弃,不推荐使用
- TLS 1.2:目前广泛使用,安全性较好
- TLS 1.3:最新版本,性能更好,安全性更强(推荐)
证书类型
1. DV(Domain Validation)域名验证证书
- 验证级别:仅验证域名所有权
- 颁发速度:几分钟到几小时
- 价格:免费或低价
- 适用场景:个人网站、博客、测试环境
- 浏览器显示:锁形图标
2. OV(Organization Validation)组织验证证书
- 验证级别:验证域名所有权 + 组织身份
- 颁发速度:几天到一周
- 价格:中等
- 适用场景:企业官网、中小型电商
- 浏览器显示:锁形图标 + 组织名称
3. EV(Extended Validation)扩展验证证书
- 验证级别:最严格的身份验证
- 颁发速度:一周到两周
- 价格:昂贵
- 适用场景:大型企业、金融机构、电商平台
- 浏览器显示:绿色地址栏 + 组织名称(部分浏览器已取消绿色地址栏)
CA(Certificate Authority)证书颁发机构
CA 是受信任的第三方机构,负责颁发和管理 SSL 证书。主要的 CA 包括:
- Let’s Encrypt:免费、自动化、开放的 CA(推荐)
- DigiCert:商业 CA,提供各类证书
- Sectigo(原 Comodo):商业 CA
- GlobalSign:商业 CA
- GeoTrust:商业 CA
免费 SSL 证书申请(Let’s Encrypt + Certbot)
Let’s Encrypt 是一个免费、自动化、开放的证书颁发机构,由互联网安全研究小组(ISRG)运营。
1. 环境准备
确保你的服务器满足以下条件:
- 已安装 Nginx
- 域名已解析到服务器 IP
- 服务器可访问外网(80 和 443 端口开放)
- 拥有 root 权限或 sudo 权限
2. 安装 Certbot
Ubuntu/Debian 系统
# 更新软件包列表
sudo apt update
# 安装 Certbot 和 Nginx 插件
sudo apt install certbot python3-certbot-nginx -yCentOS/RHEL 系统
# 安装 EPEL 仓库
sudo yum install epel-release -y
# 安装 Certbot 和 Nginx 插件
sudo yum install certbot python3-certbot-nginx -yDocker 方式(推荐)
# 拉取 Certbot 镜像
docker pull certbot/certbot
# 创建证书存储目录
mkdir -p /etc/letsencrypt3. 申请证书
方式一:自动配置(推荐)
Certbot 可以自动配置 Nginx,非常方便:
# 自动申请并配置 Nginx
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com方式二:手动申请
如果你想手动配置 Nginx:
# 仅申请证书,不自动配置
sudo certbot certonly --nginx -d yourdomain.com -d www.yourdomain.com方式三:Webroot 方式
如果 Nginx 已经在运行,可以使用 webroot 方式:
# 创建 webroot 目录
sudo mkdir -p /var/www/letsencrypt
# 申请证书
sudo certbot certonly --webroot -w /var/www/letsencrypt -d yourdomain.com方式四:DNS 验证(适合泛域名证书)
# 使用 DNS 验证方式申请泛域名证书
sudo certbot certonly --manual --preferred-challenges dns -d "*.yourdomain.com" -d yourdomain.com执行后会提示你在 DNS 中添加 TXT 记录,完成验证后即可获得证书。
4. 证书文件说明
申请成功后,证书文件会保存在 /etc/letsencrypt/live/yourdomain.com/ 目录下:
| 文件 | 说明 |
|---|---|
cert.pem | 服务器证书 |
chain.pem | 证书链(中间证书) |
fullchain.pem | 完整证书链(cert.pem + chain.pem)Nginx 配置使用这个 |
privkey.pem | 私钥文件 |
5. 自动续期
Let’s Encrypt 证书有效期为 90 天,需要定期续期。
测试续期
# 测试续期是否正常工作
sudo certbot renew --dry-run手动续期
# 手动续期所有即将过期的证书
sudo certbot renew自动续期(Cron 定时任务)
# 编辑 crontab
sudo crontab -e
# 添加以下内容(每天凌晨 2 点检查续期)
0 2 * * * /usr/bin/certbot renew --quiet --renew-hook "systemctl reload nginx"Systemd Timer 方式(推荐)
大多数系统已经自动配置了 systemd timer:
# 查看 timer 状态
sudo systemctl list-timers | grep certbot
# 如果没有,手动启用
sudo systemctl enable --now certbot.timerNginx HTTPS 配置
1. 基础配置
创建或编辑 Nginx 配置文件:
sudo nano /etc/nginx/sites-available/yourdomain.com基础 HTTPS 配置:
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
# 将 HTTP 重定向到 HTTPS
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name yourdomain.com www.yourdomain.com;
# SSL 证书配置
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
# 网站根目录
root /var/www/yourdomain.com;
index index.html index.htm;
# 日志配置
access_log /var/log/nginx/yourdomain.com.access.log;
error_log /var/log/nginx/yourdomain.com.error.log;
}启用配置并重启 Nginx:
# 启用站点
sudo ln -s /etc/nginx/sites-available/yourdomain.com /etc/nginx/sites-enabled/
# 测试配置
sudo nginx -t
# 重启 Nginx
sudo systemctl restart nginx2. 强加密套件配置
为了获得最佳安全性,建议使用强加密配置:
server {
listen 443 ssl http2;
server_name yourdomain.com www.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
# 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;
# 会话缓存(提升性能)
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
# 会话票据(提升性能)
ssl_session_tickets off;
# OCSP Stapling(提升握手速度)
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
}3. HTTP/2 配置
HTTP/2 可以显著提升网站性能,Nginx 1.9.5+ 支持 HTTP/2。
server {
# 在 listen 指令中添加 http2
listen 443 ssl http2;
server_name yourdomain.com;
# 其他 SSL 配置...
}4. HSTS 配置
HSTS(HTTP Strict Transport Security)强制浏览器使用 HTTPS 访问:
server {
listen 443 ssl http2;
server_name yourdomain.com;
# SSL 配置...
# HSTS 配置(1 年有效期,包含子域名,允许预加载)
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
# 其他安全头
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header Referrer-Policy "strict-origin-when-cross-origin";
}注意:HSTS 的 preload 指令会将你的域名提交到浏览器的 HSTS 预加载列表,一旦启用很难撤销,请谨慎使用。
5. 完整的推荐配置
以下是一个完整的、安全的 Nginx HTTPS 配置模板:
# HTTP 重定向到 HTTPS
server {
listen 80;
listen [::]:80;
server_name yourdomain.com www.yourdomain.com;
# ACME 挑战验证(用于 Certbot 续期)
location ~ /.well-known/acme-challenge {
allow all;
root /var/www/letsencrypt;
}
location / {
return 301 https://$server_name$request_uri;
}
}
# HTTPS 主配置
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name yourdomain.com www.yourdomain.com;
# SSL 证书
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
# 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;
# 会话配置
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;
# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 1.1.1.1 valid=300s;
resolver_timeout 5s;
# 安全头
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header Referrer-Policy "strict-origin-when-cross-origin";
# 网站根目录
root /var/www/yourdomain.com;
index index.html index.htm index.php;
# 日志
access_log /var/log/nginx/yourdomain.com.access.log;
error_log /var/log/nginx/yourdomain.com.error.log;
# PHP 配置(如果需要)
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
}
# 静态资源缓存
location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff|woff2|ttf|svg)$ {
expires 30d;
add_header Cache-Control "public, no-transform";
}
}证书管理
1. 查看证书信息
查看证书有效期
# 查看证书详细信息
sudo openssl x509 -in /etc/letsencrypt/live/yourdomain.com/cert.pem -text -noout
# 仅查看有效期
sudo openssl x509 -in /etc/letsencrypt/live/yourdomain.com/cert.pem -dates -noout
# 查看证书剩余天数
sudo openssl x509 -in /etc/letsencrypt/live/yourdomain.com/cert.pem -checkend 864000 -noout在线查看证书信息
# 查看远程服务器证书
echo | openssl s_client -servername yourdomain.com -connect yourdomain.com:443 2>/dev/null | openssl x509 -text -noout2. 证书续期管理
查看证书状态
# 查看所有证书状态
sudo certbot certificates手动续期
# 续期所有即将过期的证书
sudo certbot renew
# 强制续期特定证书
sudo certbot renew --cert-name yourdomain.com --force-renewal续期钩子
可以在续期后执行特定操作:
# 续期后重新加载 Nginx
sudo certbot renew --renew-hook "systemctl reload nginx"
# 续期后发送邮件通知
sudo certbot renew --renew-hook "echo 'Certificate renewed' | mail -s 'SSL Certificate Renewal' admin@yourdomain.com"3. 证书备份与迁移
备份证书
# 备份整个 letsencrypt 目录
sudo tar -czf letsencrypt-backup-$(date +%Y%m%d).tar.gz /etc/letsencrypt
# 仅备份特定域名的证书
sudo tar -czf yourdomain.com-certs-$(date +%Y%m%d).tar.gz /etc/letsencrypt/live/yourdomain.com /etc/letsencrypt/archive/yourdomain.com /etc/letsencrypt/renewal/yourdomain.com.conf迁移证书到新服务器
- 在新服务器上安装 Certbot
- 复制备份文件到新服务器
- 恢复证书:
# 解压备份
sudo tar -xzf letsencrypt-backup-20240101.tar.gz -C /
# 重新安装证书
sudo certbot install --nginx --cert-name yourdomain.com
# 测试续期
sudo certbot renew --dry-run4. 证书删除
# 删除特定证书
sudo certbot delete --cert-name yourdomain.com
# 交互式删除
sudo certbot delete常见问题与排错
1. 证书不被信任
症状:浏览器显示”您的连接不是私密连接”或证书无效。
可能原因和解决方案:
证书链不完整:确保使用
fullchain.pem而不是cert.pem# 错误 ssl_certificate /etc/letsencrypt/live/yourdomain.com/cert.pem; # 正确 ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;证书过期:检查证书有效期并续期
sudo certbot renew域名不匹配:证书中的域名与实际访问的域名不一致
# 查看证书中的域名 sudo openssl x509 -in /etc/letsencrypt/live/yourdomain.com/cert.pem -text -noout | grep DNS系统时间不正确:服务器时间错误导致证书验证失败
# 同步时间 sudo timedatectl set-ntp true
2. 混合内容警告
症状:浏览器地址栏的锁形图标上有感叹号。
原因:HTTPS 页面中加载了 HTTP 资源(图片、CSS、JS 等)。
解决方案:
使用相对协议:将
http://改为//<!-- 错误 --> <script src="http://example.com/script.js"></script> <!-- 正确 --> <script src="//example.com/script.js"></script>Nginx 自动修复:添加 CSP 头自动升级请求
add_header Content-Security-Policy "upgrade-insecure-requests";301 重定向:确保所有资源都通过 HTTPS 访问
3. 性能问题
症状:HTTPS 网站比 HTTP 慢很多。
优化方案:
启用会话缓存:
ssl_session_cache shared:SSL:10m; ssl_session_timeout 1d;启用 OCSP Stapling:
ssl_stapling on; ssl_stapling_verify on;启用 HTTP/2:
listen 443 ssl http2;使用 TLS 1.3:TLS 1.3 握手更快
ssl_protocols TLSv1.2 TLSv1.3;
4. Certbot 申请失败
常见错误和解决方案:
端口 80 被占用:确保 80 端口可访问,防火墙开放
sudo ufw allow 80/tcp sudo ufw allow 443/tcpDNS 解析问题:确认域名已正确解析到服务器 IP
dig yourdomain.com验证失败:检查
.well-known目录权限sudo mkdir -p /var/www/letsencrypt/.well-known/acme-challenge sudo chown -R www-data:www-data /var/www/letsencrypt
5. SSL Labs 评分优化
使用 SSL Labs Server Test 测试你的服务器配置,目标是 A+ 评分。
优化要点:
- 禁用弱加密算法
- 启用前向保密(PFS)
- 配置 HSTS
- 启用 OCSP Stapling
- 使用强私钥(至少 2048 位 RSA 或 256 位 ECDSA)
进阶配置
1. 多域名/泛域名证书
申请多域名证书
# 申请包含多个域名的证书
sudo certbot --nginx -d domain1.com -d www.domain1.com -d domain2.com -d www.domain2.com申请泛域名证书
# 申请泛域名证书(需要 DNS 验证)
sudo certbot certonly --manual --preferred-challenges dns -d "*.yourdomain.com" -d yourdomain.comNginx 多域名配置
# 域名 1
server {
listen 443 ssl http2;
server_name domain1.com www.domain1.com;
ssl_certificate /etc/letsencrypt/live/domain1.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/domain1.com/privkey.pem;
root /var/www/domain1.com;
# 其他配置...
}
# 域名 2
server {
listen 443 ssl http2;
server_name domain2.com www.domain2.com;
ssl_certificate /etc/letsencrypt/live/domain2.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/domain2.com/privkey.pem;
root /var/www/domain2.com;
# 其他配置...
}2. 反向代理配置
基础反向代理
server {
listen 443 ssl http2;
server_name app.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/app.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/app.yourdomain.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:3000;
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;
}
}WebSocket 反向代理
server {
listen 443 ssl http2;
server_name ws.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/ws.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/ws.yourdomain.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
}
}3. SSL 性能优化
使用 ECDSA 证书
ECDSA 证书比 RSA 证书更小、更快:
# 申请 ECDSA 证书
sudo certbot --nginx --key-type ecdsa --elliptic-curve secp384r1 -d yourdomain.com启用 Brotli 压缩
# 需要先安装 ngx_brotli 模块
brotli on;
brotli_comp_level 6;
brotli_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;TCP 优化
# 在 http 块中配置
http {
# TCP 优化
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# 其他配置...
}4. 自动证书管理脚本
创建一个自动化管理脚本:
#!/bin/bash
# /usr/local/bin/ssl-manager.sh
DOMAINS=("domain1.com" "domain2.com" "domain3.com")
EMAIL="admin@yourdomain.com"
WEBROOT="/var/www/letsencrypt"
# 检查并续期证书
for domain in "${DOMAINS[@]}"; do
echo "Checking certificate for $domain..."
# 检查证书是否在 30 天内过期
if ! openssl x509 -checkend 2592000 -noout -in /etc/letsencrypt/live/$domain/cert.pem 2>/dev/null; then
echo "Renewing certificate for $domain..."
certbot renew --cert-name $domain --quiet
else
echo "Certificate for $domain is valid."
fi
done
# 重新加载 Nginx
systemctl reload nginx
echo "SSL certificate check completed at $(date)"设置定时执行:
# 添加执行权限
chmod +x /usr/local/bin/ssl-manager.sh
# 添加到 crontab(每周一凌晨 3 点执行)
echo "0 3 * * 1 /usr/local/bin/ssl-manager.sh >> /var/log/ssl-manager.log 2>&1" | sudo tee -a /etc/crontab总结与最佳实践
核心要点回顾
- HTTPS 是必需品:所有网站都应该启用 HTTPS,不再有例外
- Let’s Encrypt 是首选:免费、自动化、足够安全
- 安全配置很重要:使用强加密、禁用旧协议、配置安全头
- 自动化管理:设置自动续期,避免证书过期
- 性能优化:HTTP/2、会话缓存、OCSP Stapling 等可以显著提升性能
最佳实践清单
✅ 必须做的
- 为所有域名启用 HTTPS
- 将 HTTP 重定向到 HTTPS
- 使用 Let’s Encrypt 等可信 CA 的证书
- 配置自动续期
- 使用 TLS 1.2 和 TLS 1.3
- 启用 HSTS
- 配置强加密套件
- 启用 OCSP Stapling
- 定期检查 SSL Labs 评分
⚠️ 谨慎做的
- 启用 HSTS preload(难以撤销)
- 使用 EV 证书(性价比不高)
- 禁用 TLS 1.2(可能影响旧设备)
❌ 不要做的
- 使用自签名证书(生产环境)
- 使用 SSL 3.0、TLS 1.0、TLS 1.1
- 使用弱加密算法(如 RC4、MD5)
- 手动管理证书续期
- 混合 HTTP 和 HTTPS 内容
推荐工具
- 证书申请与管理:Certbot、acme.sh
- SSL 测试:SSL Labs Server Test、testssl.sh
- 性能测试:WebPageTest、GTmetrix
- 安全扫描:Qualys SSL Labs、Mozilla Observatory
- 监控告警:UptimeRobot、证书过期监控
学习资源
结语:HTTPS 配置看似复杂,但只要按照规范一步步操作,其实并不难。关键是理解原理、使用正确的工具、建立自动化的管理流程。希望这篇教程能帮助你顺利为网站启用 HTTPS,为用户提供更安全的访问体验。