1. 引言
随着网络安全意识的提升,HTTPS 已成为网站部署的标配。HTTPS 不仅能够加密客户端与服务器之间的数据传输,防止中间人攻击,还能提升搜索引擎排名和用户信任度。Nginx 作为高性能的 Web 服务器和反向代理服务器,配置 HTTPS 是其核心功能之一。
本文将带你从零开始,在 Nginx 中配置 HTTPS,并对配置文件中的每一个参数进行详细解读,帮助你不仅会配置,更理解每一行配置背后的含义。
2. 准备工作
在开始配置之前,需要做好以下准备:
- 一台已安装 Nginx 的服务器(本文以 Ubuntu/Debian 系统为例,其他系统命令略有差异)。
- 一个已解析到该服务器的域名。
- 一份 SSL 证书及私钥文件。你可以从证书颁发机构(CA)购买,也可以使用 Let's Encrypt 免费获取。
2.1 检查 Nginx 是否安装
bash
nginx -v
如果未安装,可使用以下命令安装:
bash
sudo apt update
sudo apt install nginx -y
2.2 获取 SSL 证书
以 Let's Encrypt 为例,使用 Certbot 工具可以快速获取免费证书:
bash
sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx -d example.com -d www.example.com
Certbot 会自动修改 Nginx 配置并启用 HTTPS。但为了深入理解配置,本文将手动编写配置。
3. 基础 HTTPS 配置
首先,我们来看一个最基础的 HTTPS 配置示例:
nginx
server {
listen 443 ssl;
server_name example.com www.example.com;
ssl_certificate /etc/nginx/ssl/example.com.crt;
ssl_certificate_key /etc/nginx/ssl/example.com.key;
root /var/www/html;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
3.1 listen 443 ssl
nginx
listen 443 ssl;
参数解读:
listen:指定 Nginx 监听的端口和协议。443:HTTPS 的默认端口。ssl:告诉 Nginx 在该端口上启用 SSL/TLS 加密。这是启用 HTTPS 的关键参数。
注意 :在较新版本的 Nginx 中,
ssl参数可以省略,因为listen 443默认会启用 SSL。但为了兼容性和明确性,建议保留。
3.2 server_name
nginx
server_name example.com www.example.com;
参数解读:
server_name:指定该虚拟主机匹配的域名。- 可以配置多个域名,用空格分隔。
- 当客户端请求的
Host头与这里的域名匹配时,Nginx 会使用该server块处理请求。
3.3 ssl_certificate
nginx
ssl_certificate /etc/nginx/ssl/example.com.crt;
参数解读:
ssl_certificate:指定 SSL 证书文件的路径。- 证书文件通常以
.crt、.pem或.cer为扩展名。 - 该文件包含服务器的公钥证书,由 CA 签发。
- 如果证书链中包含中间证书,需要将服务器证书和中间证书合并到同一个文件中。
3.4 ssl_certificate_key
3.5 多域名与通配符证书
在实际部署中,一个站点往往需要同时服务多个域名,或者为某个主域名下的所有子域名提供 HTTPS。这时就需要用到多域名证书或通配符证书。
3.5.1 同一 server 块配置多个域名共用一张证书
如果一张证书的 SAN(Subject Alternative Name,主题备用名称)字段中包含了多个域名,那么可以在同一个 server 块中配置这些域名,共用这一张证书:
nginx
server {
listen 443 ssl;
server_name example.com www.example.com blog.example.com;
ssl_certificate /etc/nginx/ssl/example.com.crt;
ssl_certificate_key /etc/nginx/ssl/example.com.key;
root /var/www/html;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
参数解读:
server_name:这里列出了三个域名,用空格分隔。只要请求的Host头匹配其中任意一个,Nginx 就会使用该server块处理请求。ssl_certificate/ssl_certificate_key:指向同一张证书和对应的私钥。这张证书必须同时覆盖上面列出的所有域名,否则浏览器会提示证书不匹配。
适用场景 :当几个域名指向同一个站点、且证书已包含这些域名时使用。例如公司官网同时使用
example.com和www.example.com,或主站与博客共用一张多域名证书。
3.5.2 使用通配符证书(*.example.com)
通配符证书可以覆盖某个主域名下的所有一级子域名,例如 *.example.com 可以匹配 www.example.com、blog.example.com、api.example.com 等,但不匹配 example.com 本身。
nginx
server {
listen 443 ssl;
server_name *.example.com;
ssl_certificate /etc/nginx/ssl/wildcard.example.com.crt;
ssl_certificate_key /etc/nginx/ssl/wildcard.example.com.key;
root /var/www/html;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
参数解读:
server_name *.example.com:使用通配符匹配所有一级子域名。ssl_certificate/ssl_certificate_key:指向通配符证书及其私钥。通配符证书的 CN 或 SAN 字段为*.example.com。
注意 :通配符证书只匹配一级子域名,
a.b.example.com这类多级子域名无法被*.example.com覆盖,需要单独配置或使用多域名证书。
适用场景 :当子域名数量较多、且未来可能动态新增子域名时使用。例如 SaaS 平台为每个客户分配独立的customer.example.com,使用通配符证书可以避免频繁申请新证书。
nginx
ssl_certificate_key /etc/nginx/ssl/example.com.key;
参数解读:
ssl_certificate_key:指定 SSL 私钥文件的路径。- 私钥文件通常以
.key为扩展名。 - 私钥必须保密,不能泄露给任何人。
- 私钥与证书必须匹配,否则 Nginx 启动时会报错。
安全提示 :私钥文件的权限应设置为仅 root 可读,例如
chmod 600 example.com.key。
4. 增强 HTTPS 安全性的配置
基础配置已经可以启用 HTTPS,但为了提升安全性,还需要进行以下优化。
4.1 HTTP 自动跳转 HTTPS
为了让用户访问 HTTP 时自动跳转到 HTTPS,可以添加一个额外的 server 块:
nginx
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
参数解读:
listen 80:监听 HTTP 默认端口。return 301:返回 301 永久重定向状态码。https://$host$request_uri:重定向目标地址。$host是请求的域名,$request_uri是请求的 URI。
说明:使用 301 永久重定向有利于 SEO,搜索引擎会将权重转移到 HTTPS 页面。
4.2 配置 HTTP/2
HTTP/2 可以显著提升页面加载速度,Nginx 1.9.5 及以上版本支持:
nginx
listen 443 ssl http2;
参数解读:
http2:启用 HTTP/2 协议。- HTTP/2 支持多路复用、头部压缩等特性,能减少延迟、提升性能。
- 注意:HTTP/2 需要 SSL/TLS 支持,因此必须与
ssl同时使用。
4.3 配置 TLS 协议版本
nginx
ssl_protocols TLSv1.2 TLSv1.3;
参数解读:
ssl_protocols:指定允许使用的 TLS 协议版本。TLSv1.2:目前广泛支持的版本,安全性较高。TLSv1.3:最新版本,安全性最高,性能更好。- 建议禁用 SSLv3、TLSv1.0 和 TLSv1.1,这些旧版本存在已知安全漏洞。
4.4 配置加密套件
nginx
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_ciphers:指定允许的加密套件列表,用冒号分隔。- 加密套件决定了密钥交换、认证、加密和消息认证的方式。
- 上述配置优先使用 ECDHE 密钥交换(支持前向保密)和 AES-GCM 加密算法(高效且安全)。
- 建议使用 Mozilla 推荐的加密套件配置。
4.5 配置 SSL 会话缓存
nginx
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
参数解读:
ssl_session_cache:配置 SSL 会话缓存。shared:SSL:10m表示在共享内存中分配 10MB 缓存,大约可以存储 40000 个会话。ssl_session_timeout:会话超时时间,超过该时间后会话失效,需要重新握手。- 启用会话缓存可以减少重复握手的开销,提升性能。
4.6 配置 OCSP Stapling
nginx
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
参数解读:
ssl_stapling on:启用 OCSP Stapling。服务器主动向 CA 查询证书状态并缓存,在 TLS 握手时直接返回给客户端,无需客户端再向 CA 查询,提升握手速度。ssl_stapling_verify on:验证 OCSP 响应。resolver:指定 DNS 解析器,用于解析 OCSP 响应服务器的域名。resolver_timeout:DNS 解析超时时间。
4.7 配置 HSTS
nginx
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
参数解读:
add_header:添加 HTTP 响应头。Strict-Transport-Security:HSTS 头,告诉浏览器只能通过 HTTPS 访问该站点。max-age=31536000:有效期 1 年(单位秒)。includeSubDomains:对子域名同样生效。always:无论响应状态码是什么都添加该头。
注意:启用 HSTS 后,浏览器会强制使用 HTTPS,如果证书配置有误,用户将无法访问站点。建议先在测试环境验证。
4.8 配置 TLS 会话票据
4.9 HTTPS 反向代理配置
Nginx 最常见的用途之一就是作为反向代理:对外提供 HTTPS 加密访问,对内将请求转发给后端的 HTTP 服务(如 Tomcat、Node.js、Gunicorn 等)。这样既能让后端服务专注于业务逻辑,又能在入口统一处理 TLS 加密、负载均衡和安全策略。
nginx
server {
listen 443 ssl http2;
server_name example.com www.example.com;
# 证书配置
ssl_certificate /etc/nginx/ssl/example.com.crt;
ssl_certificate_key /etc/nginx/ssl/example.com.key;
# 协议与加密套件
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 on;
# 反向代理配置
location / {
proxy_pass http://127.0.0.1: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 $scheme;
}
}
参数解读:
proxy_pass:指定后端服务的地址。这里将请求转发到本机的8080端口,即后端 HTTP 服务监听的端口。proxy_set_header Host $host:将客户端请求的Host头原样传递给后端,保证后端能正确识别域名。proxy_set_header X-Real-IP $remote_addr:传递客户端的真实 IP 地址。由于 Nginx 转发后,后端看到的连接来源是 Nginx 本身,需要该头才能获取真实客户端 IP。proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for:追加客户端 IP 到转发链中,常用于日志记录和访问控制。proxy_set_header X-Forwarded-Proto $scheme:告诉后端原始请求使用的协议(http或https)。$scheme变量在 HTTPS 请求中取值为https。
说明 :
X-Forwarded-Proto是解决后端重定向协议丢失问题的关键。如果缺少该头,后端在生成重定向 URL 时(例如登录成功后跳转)会误以为原始请求是 HTTP,从而生成http://开头的地址,导致用户被重定向到非加密页面,甚至出现「重定向次数过多」的错误。
4.9.1 后端重定向协议丢失的解决方案
当后端服务需要根据请求协议生成绝对 URL 时(如 Spring Boot 的 RedirectView、Django 的 HttpResponseRedirect),必须让后端感知到原始请求是 HTTPS。除了设置 X-Forwarded-Proto 头,部分框架还需要额外配置:
nginx
# 对于需要识别 X-Forwarded-Proto 的框架(如 Django、Spring Boot)
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port $server_port;
参数解读:
X-Forwarded-Proto $scheme:声明原始请求协议为 HTTPS,后端据此生成https://开头的重定向地址。X-Forwarded-Port $server_port:传递 Nginx 监听的端口(443),供后端生成包含正确端口的 URL。
注意 :部分框架默认不信任代理设置的
X-Forwarded-*头,需要显式开启。例如 Django 需在settings.py中配置SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https'),Spring Boot 需设置server.forward-headers-strategy=framework。否则后端仍会忽略该头,重定向协议问题依旧存在。
nginx
ssl_session_tickets on;
参数解读:
ssl_session_tickets:启用 TLS 会话票据(Session Tickets)。- 与会话缓存不同,会话票据由服务器加密后发给客户端,客户端在后续连接中携带票据即可恢复会话,无需服务器存储会话状态。
- 适用于多台服务器负载均衡的场景。
5. 完整的安全配置示例
将以上配置整合,得到一个完整的 HTTPS 配置示例:
nginx
# HTTP 跳转 HTTPS
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
# HTTPS 主配置
server {
listen 443 ssl http2;
server_name example.com www.example.com;
# 证书配置
ssl_certificate /etc/nginx/ssl/example.com.crt;
ssl_certificate_key /etc/nginx/ssl/example.com.key;
# 协议与加密套件
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 on;
# 会话缓存与票据
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_session_tickets on;
# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
# HSTS
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# 站点根目录
root /var/www/html;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
5.1 ssl_prefer_server_ciphers
nginx
ssl_prefer_server_ciphers on;
参数解读:
ssl_prefer_server_ciphers:当客户端支持多种加密套件时,是否优先使用服务器端配置的加密套件顺序。- 设置为
on可以确保优先使用服务器端更安全的加密套件。
6. 验证配置并重启 Nginx
配置完成后,需要验证配置文件的正确性并重启 Nginx:
bash
# 验证配置
sudo nginx -t
# 重启 Nginx
sudo systemctl restart nginx
如果配置正确,nginx -t 会输出:
nginx: configuration file /etc/nginx/nginx.conf test is successful
7. 常见问题排查
7.1 证书不匹配
如果证书与私钥不匹配,Nginx 启动时会报错。可以使用以下命令验证:
bash
# 查看证书信息
openssl x509 -in /etc/nginx/ssl/example.com.crt -noout -modulus | openssl md5
# 查看私钥信息
openssl rsa -in /etc/nginx/ssl/example.com.key -noout -modulus | openssl md5
两个命令输出的 MD5 值应一致。
7.2 证书链不完整
如果浏览器提示证书链不完整,需要将服务器证书和中间证书合并:
bash
cat example.com.crt intermediate.crt > combined.crt
然后将 ssl_certificate 指向合并后的文件。
7.3 端口被占用
如果 443 端口被其他程序占用,可以使用以下命令查看:
bash
sudo netstat -tlnp | grep 443
8. 总结
本文详细介绍了 Nginx 配置 HTTPS 的完整流程,并对每个参数进行了深入解读。从基础的 listen 443 ssl、ssl_certificate、ssl_certificate_key,到安全增强的 ssl_protocols、ssl_ciphers、HSTS、OCSP Stapling 等,每一个参数都有其特定的作用。
配置 HTTPS 不仅仅是启用加密,更重要的是通过合理的参数配置,在安全性、性能和兼容性之间找到最佳平衡。希望本文能帮助你深入理解 Nginx HTTPS 配置的每一个细节,在实际部署中游刃有余。