一、引言
在当今互联网环境中,HTTPS已不再是可选的安全增强手段,而是网站运营的基本要求。Nginx作为最流行的Web服务器和反向代理之一,其HTTPS配置直接影响服务的安全性、性能和用户体验。本文将深入探讨Nginx配置HTTPS的完整流程,包括证书获取、安全配置、性能优化和故障排查。
二、SCQA分析框架
情境(Situation)
- HTTPS是现代Web服务的标配,浏览器对HTTP网站的警告越来越严格
- Nginx是主流的Web服务器和反向代理,广泛应用于生产环境
- 证书管理、安全配置和性能优化是HTTPS部署的核心挑战
冲突(Complication)
- 证书获取和续期流程复杂
- 安全配置不当可能导致漏洞
- HTTPS会带来一定的性能开销
- 多节点部署时证书同步困难
问题(Question)
- 如何获取SSL证书?
- Nginx如何配置HTTPS?
- 如何优化HTTPS性能?
- 如何确保配置的安全性?
- 证书过期如何自动处理?
答案(Answer)
- 使用Let’s Encrypt免费证书,通过Certbot自动化管理
- 配置TLS 1.2/1.3协议和安全密码套件
- 启用HTTP/2、会话缓存和OCSP装订优化性能
- 设置HSTS和安全响应头增强安全性
- 配置Certbot自动续期
三、SSL证书获取
3.1 Let’s Encrypt证书
安装Certbot:
# Ubuntu/Debian
sudo apt-get update && sudo apt-get install certbot python3-certbot-nginx
# CentOS/RHEL
sudo yum install certbot python3-certbot-nginx
自动申请并配置证书:
# 自动检测Nginx配置并配置HTTPS
sudo certbot --nginx -d example.com -d www.example.com
# 交互式模式(手动选择选项)
sudo certbot --nginx -d example.com --dry-run
手动申请证书:
# 仅获取证书,不自动配置Nginx
sudo certbot certonly --nginx -d example.com
# 使用Webroot插件(适用于已有Web服务)
sudo certbot certonly --webroot -w /var/www/example -d example.com
证书文件位置:
# Let's Encrypt证书目录结构
/etc/letsencrypt/live/example.com/
├── cert.pem # 域名证书
├── chain.pem # 中间证书
├── fullchain.pem # 完整证书链(cert.pem + chain.pem)
└── privkey.pem # 私钥
3.2 商业证书
证书类型选择:
| 类型 | 验证方式 | 特点 | 适用场景 |
|---|---|---|---|
| DV | 域名验证 | 快速签发,仅验证域名所有权 | 个人网站、博客 |
| OV | 组织验证 | 验证企业身份,显示组织信息 | 企业官网 |
| EV | 扩展验证 | 最高安全级别,浏览器显示绿色地址栏 | 金融机构、电商平台 |
证书格式转换:
# PFX转PEM(Windows服务器导出的证书)
openssl pkcs12 -in certificate.pfx -out certificate.pem -nodes
# DER转PEM
openssl x509 -in certificate.cer -inform DER -out certificate.pem
四、Nginx HTTPS基础配置
4.1 最小配置示例
# HTTP服务器(重定向到HTTPS)
server {
listen 80;
server_name example.com www.example.com;
# 永久重定向到HTTPS
return 301 https://$server_name$request_uri;
}
# HTTPS服务器
server {
# 启用HTTPS和HTTP/2
listen 443 ssl http2;
server_name example.com www.example.com;
# SSL证书配置
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# TLS协议版本(仅支持安全版本)
ssl_protocols TLSv1.2 TLSv1.3;
# 密码套件(优先使用AEAD算法)
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;
# 根目录和索引文件
root /var/www/example;
index index.html index.htm;
# 反向代理示例(如果需要)
location /api/ {
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
4.2 配置说明
证书配置: | 配置项 | 说明 | |:——|:——| | ssl_certificate | 证书文件路径,必须包含完整证书链 | | ssl_certificate_key | 私钥文件路径,权限需设为600 | | ssl_protocols | 支持的TLS版本,禁用TLS 1.0/1.1 | | ssl_ciphers | 密码套件列表,优先选择AEAD算法 |
文件权限:
# 设置证书文件权限
chmod 600 /etc/letsencrypt/live/example.com/privkey.pem
chmod 644 /etc/letsencrypt/live/example.com/fullchain.pem
五、安全配置优化
5.1 HSTS(HTTP严格传输安全)
基础配置:
# 强制HTTPS访问,有效期1年
add_header Strict-Transport-Security "max-age=31536000" always;
# 包含所有子域名
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# 提交到浏览器预加载列表(需在hstspreload.org注册)
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
HSTS优势:
- 防止协议降级攻击
- 强制浏览器使用HTTPS
- 减少HTTP到HTTPS的重定向开销
5.2 安全响应头
常用安全头:
# 防止点击劫持
add_header X-Frame-Options DENY always;
# 防止MIME类型嗅探
add_header X-Content-Type-Options nosniff always;
# 控制Referrer信息
add_header Referrer-Policy strict-origin-when-cross-origin always;
# 内容安全策略(根据实际需求调整)
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'" always;
# 启用跨域资源共享(根据需求配置)
add_header Access-Control-Allow-Origin "*" always;
安全头说明:
| 头名称 | 作用 | 推荐值 |
|---|---|---|
X-Frame-Options | 防止点击劫持 | DENY |
X-Content-Type-Options | 防止MIME嗅探 | nosniff |
Referrer-Policy | 控制Referrer字段 | strict-origin-when-cross-origin |
Content-Security-Policy | 内容安全策略 | 根据业务配置 |
5.3 OCSP装订
配置示例:
# 启用OCSP装订
ssl_stapling on;
ssl_stapling_verify on;
# 指定可信CA证书(用于验证OCSP响应)
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
# DNS解析器配置
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
OCSP装订优势:
- 加速证书状态验证
- 减少客户端到OCSP服务器的请求
- 提升TLS握手性能
六、性能优化
6.1 SSL会话缓存
配置示例:
# 共享会话缓存(所有worker进程共享)
ssl_session_cache shared:SSL:10m;
# 会话超时时间
ssl_session_timeout 10m;
# 启用会话票证(无状态会话恢复)
ssl_session_tickets on;
# 会话票证密钥(定期轮换)
ssl_session_ticket_key /etc/nginx/session_ticket.key;
会话缓存效果:
- 减少重复TLS握手开销
- 10MB缓存约可存储40000个会话
- 会话票证支持无状态会话恢复
6.2 SSL缓冲区优化
# 减小SSL缓冲区大小(默认16k,可减小到4k)
ssl_buffer_size 4k;
缓冲区说明:
- 较小的缓冲区可以降低内存占用
- 适合小请求场景
- 大文件传输可能需要更大的缓冲区
6.3 HTTP/2配置
配置示例:
# 启用HTTP/2
listen 443 ssl http2;
# HTTP/2连接参数
http2_max_field_size 64k;
http2_max_header_size 128k;
http2_max_concurrent_streams 128;
HTTP/2优势:
- 多路复用:一个连接处理多个请求
- 头部压缩:减少请求开销
- 服务器推送:主动推送资源
七、证书自动续期
7.1 Certbot自动续期
测试续期:
# 模拟续期(不实际更新)
certbot renew --dry-run
配置自动续期:
# 创建定时任务文件
cat > /etc/cron.d/certbot <<EOF
# 每天凌晨2点检查并续期证书
0 2 * * * root certbot renew --quiet && systemctl reload nginx
EOF
续期日志:
# 查看续期日志
tail -f /var/log/letsencrypt/letsencrypt.log
7.2 多节点部署
方案一:共享存储:
# 使用NFS或分布式存储共享证书目录
mount -t nfs nfs-server:/path/to/certs /etc/letsencrypt/live
方案二:证书同步:
# 使用rsync同步证书到其他节点
rsync -avz /etc/letsencrypt/live/ user@node2:/etc/letsencrypt/live/
方案三:Vault管理:
# 使用HashiCorp Vault管理证书
vault write secret/ssl/example.com cert=@fullchain.pem key=@privkey.pem
八、配置验证与测试
8.1 配置验证
# 验证Nginx配置语法
nginx -t
# 查看Nginx编译模块(确认SSL模块已启用)
nginx -V 2>&1 | grep -o with-http_ssl_module
8.2 SSL连接测试
查看证书信息:
# 查看服务器证书
openssl s_client -connect example.com:443 -servername example.com
# 仅显示证书链
openssl s_client -connect example.com:443 -servername example.com -showcerts
测试TLS版本:
# 测试TLS 1.2
openssl s_client -connect example.com:443 -tls1_2
# 测试TLS 1.3
openssl s_client -connect example.com:443 -tls1_3
测试HTTP/2:
# 使用curl测试HTTP/2
curl -I --http2 https://example.com
# 使用nghttp测试
nghttp -v https://example.com
8.3 安全评分
SSL Labs测试:
# 在线测试(浏览器访问)
# https://www.ssllabs.com/ssltest/
# 命令行工具(需要安装)
ssllabs-scan example.com
九、常见问题与解决方案
问题一:证书不被信任
现象:浏览器提示”您的连接不是私密连接”
原因:
- 证书链不完整(缺少中间证书)
- 证书过期
- 域名不匹配
解决方案:
# 确保证书使用fullchain.pem
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
# 检查证书有效期
openssl x509 -in fullchain.pem -text -noout | grep -A 2 'Validity'
# 确认域名匹配
openssl x509 -in fullchain.pem -text -noout | grep 'Subject:'
问题二:SSL握手失败
现象:HTTPS连接无法建立,报SSL_ERROR
原因:
- 证书路径错误
- 私钥权限问题
- 私钥被密码保护
- SSL模块未启用
解决方案:
# 检查证书路径
ls -la /etc/letsencrypt/live/example.com/
# 检查私钥权限
chmod 600 /etc/letsencrypt/live/example.com/privkey.pem
# 检查私钥是否被加密(有DEK-Info行表示被加密)
head -5 privkey.pem
# 如果私钥被加密,去除密码
openssl rsa -in encrypted.key -out decrypted.key
问题三:混合内容警告
现象:浏览器控制台显示”混合内容”警告
原因:页面中包含HTTP资源
解决方案:
# 查找页面中的HTTP资源
grep -r "http://" /var/www/example/
# 修改为HTTPS
sed -i 's/http:\/\//https:\/\//g' /var/www/example/*.html
# 使用相对协议
# <img src="//example.com/image.jpg">
问题四:HTTP/2不生效
现象:curl测试显示HTTP/1.1
原因:
- 未配置
listen 443 ssl http2 - 浏览器不支持HTTP/2
- 代理服务器不支持HTTP/2
解决方案:
# 确认配置
grep -n "http2" /etc/nginx/sites-available/example.conf
# 测试HTTP/2支持
curl -I --http2 https://example.com
问题五:证书续期失败
现象:Certbot续期失败
原因:
- 域名解析问题
- Webroot路径错误
- 防火墙阻止访问
解决方案:
# 检查域名解析
nslookup example.com
# 检查Webroot路径
ls -la /var/www/example/.well-known/acme-challenge/
# 测试ACME挑战
certbot renew --dry-run
十、生产环境最佳实践
10.1 配置清单
必须配置项:
- ✅ SSL证书和私钥
- ✅ TLS 1.2/1.3协议
- ✅ 安全密码套件
- ✅ HTTP到HTTPS重定向
- ✅ HSTS头部
- ✅ 基本安全响应头
- ✅ 证书自动续期
推荐配置项:
- ✅ HTTP/2协议
- ✅ SSL会话缓存
- ✅ OCSP装订
- ✅ 安全的Content-Security-Policy
10.2 安全审计
定期检查项:
- SSL Labs评分(目标A+)
- 证书有效期(提前30天告警)
- 密码套件更新(移除弱算法)
- 安全头完整性
自动化审计:
# 使用OpenSCAP扫描安全配置
oscap xccdf eval --profile xccdf_org.ssgproject.content_profile_strict /usr/share/xml/scap/ssg/content/ssg-nginx-xccdf.xml
10.3 性能监控
监控指标: | 指标 | 说明 | 阈值建议 | |:——|:——|:——| | SSL握手时间 | TLS握手耗时 | <100ms | | HTTPS请求成功率 | 成功请求占比 | >99.9% | | SSL会话复用率 | 复用会话占比 | >90% | | 证书过期天数 | 剩余有效期 | >30天 |
Prometheus监控:
# 监控证书过期时间
groups:
- name: nginx-ssl.rules
rules:
- alert: SSLCertificateExpiring
expr: nginx_ssl_cert_expiry_days < 30
labels:
severity: warning
annotations:
summary: "SSL证书即将过期"
十一、总结
核心要点
- 证书获取:使用Let’s Encrypt免费证书,通过Certbot自动化管理
- 基础配置:配置证书路径、TLS协议版本和密码套件
- 安全优化:设置HSTS、安全响应头和OCSP装订
- 性能优化:启用HTTP/2、SSL会话缓存和缓冲区优化
- 自动化:配置证书自动续期和监控告警
配置模板
server {
listen 80;
server_name example.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name 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 off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_session_tickets on;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Frame-Options DENY always;
add_header X-Content-Type-Options nosniff always;
location / {
root /var/www/example;
index index.html;
}
}
本文对应的面试题:HTTPS访问Nginx需要怎么做?
附录:常用命令
# 检查SSL模块
nginx -V 2>&1 | grep ssl
# 验证配置
nginx -t
# 查看证书信息
openssl x509 -in fullchain.pem -text -noout
# 测试SSL连接
openssl s_client -connect example.com:443 -servername example.com
# 测试HTTP/2
curl -I --http2 https://example.com
# Certbot续期
certbot renew --dry-run
# SSL Labs测试
ssllabs-scan example.com
文档信息
- 本文作者:soveran zhong
- 本文链接:https://blog.clockwingsoar.cn/2026/06/14/nginx-https-best-practices/
- 版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)