答案是 $scheme 变量最可靠,它由 nginx 根据 tls 握手状态自动赋值为 http 或 https,不依赖端口或代理头,适用于日志统计、条件跳转与协议透传;$https 仅在启用 ssl 时为 "on",语义不如 $scheme 通用。

Nginx 本身不直接读取系统环境变量来判断 HTTPS 请求,但可以通过内置变量和配置逻辑间接实现“判定 HTTPS 状态”的效果。真正起作用的是 $scheme、$https 和 $server_port 这类运行时变量,它们由 Nginx 在请求处理过程中自动赋值,而非来自操作系统环境变量。
如果你看到有人提到“用环境变量判定 HTTPS”,通常存在两种理解偏差:
- 把 Nginx 的内置变量(如
$https)误称为“环境变量”; - 或在启动 Nginx 前通过 shell 设置变量(如
HTTPS=on nginx),但这对运行中的请求无实际影响,无法用于日志或条件判断。
下面说清楚怎么可靠、实用地判定 HTTPS 请求状态:
直接使用 $https 变量(最常用)
Nginx 内置变量 $https 的值为 "on"(HTTPS)或空字符串(HTTP)。它由 ssl on; 或监听 443 ssl 的 server 块自动设置。
server {
listen 80;
listen 443 ssl;
ssl_certificate /path/to/cert.crt;
ssl_certificate_key /path/to/key.pem;
location /status {
return 200 "Scheme: $scheme, HTTPS: $https, Port: $server_port";
}
}
访问 https://example.com/status → 返回 Scheme: https, HTTPS: on, Port: 443
访问 http://example.com/status → 返回 Scheme: http, HTTPS: , Port: 80
利用 $scheme 更通用(推荐)
$scheme 总是返回 http 或 https,语义清晰、无需依赖 SSL 配置是否启用:
log_format https_log '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'scheme="$scheme"';
access_log /var/log/nginx/access.log https_log;
日志中会看到:
192.168.1.100 - - [16/Jun/2026:06:40:12 +0000] "GET / HTTP/1.1" 200 612 scheme="https" 192.168.1.100 - - [16/Jun/2026:06:40:15 +0000] "GET / HTTP/1.1" 200 612 scheme="http"
在 if 或 rewrite 中做条件判断
# 强制跳转 HTTPS(仅对非 HTTPS 请求生效)
if ($scheme = http) {
return 301 https://$host$request_uri;
}
# 或更稳妥写法(避免 if 在 location 外滥用)
server {
listen 80;
server_name example.com;
return 301 https://$host$request_uri;
}
注意:不要依赖 $server_port 单独判断
虽然 HTTPS 通常走 443、HTTP 走 80,但端口可自定义(如 listen 8443 ssl),且反向代理后端可能统一走 80。仅靠端口容易出错。
补充:前端传来的 X-Forwarded-Proto 怎么用?
当 Nginx 前有负载均衡器(如 AWS ALB、CDN)时,真实协议信息会放在请求头里:
map $http_x_forwarded_proto $real_scheme {
default $scheme;
https https;
http http;
}
log_format real_scheme_log '... scheme="$real_scheme"';
这样能穿透代理,准确还原原始协议。
不复杂但容易忽略











