You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何NGINX中使用$scheme变量的proxy_pass配置无法正常工作?

问题分析:NGINX反向代理中$scheme变量导致的访问异常

问题场景

我运行着一台NGINX服务器,用于向其他Web系统提供反向代理服务,配置如下:

server {
    # HTTP configuration
    
    listen 80;
    listen [::]:80;
    listen 443 ssl;
    listen [::]:443 ssl;       
    server_name example.com;
    
    large_client_header_buffers 4 16k;

    error_log   /var/log/nginx/example.com.log  info;
    access_log  /var/log/nginx/example.com.log  main;

    ssl_certificate root/fullchain.pem; 
    ssl_certificate_key root/privkey.pem;


location / {       
    proxy_redirect        off;
    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_http_version 1.1;
    proxy_set_header        Upgrade $http_upgrade;
    proxy_set_header        Connection 'upgrade';
    proxy_cache_bypass      $http_upgrade;
    proxy_set_header Connection $http_connection;
    proxy_set_header X-Real-Port $server_port;
    proxy_set_header X-Real-Scheme $scheme;
     proxy_read_timeout 3600;
     resolver_timeout 60s;
    
    client_max_body_size 50M;
    proxy_pass $scheme://192.168.1.1/;
  }
}

server {
    if ($host = example.com) {
    return 301 https://$host$request_uri;
   } 
    listen 80;
    listen [::]:80;
    server_name example.com;
    return 404; 
 }

我发现使用proxy_pass $scheme://192.168.1.1/时页面无法正常工作,但改为proxy_pass http://192.168.1.1/后就能正常运行。我的目标是让该特定系统同时支持HTTP和HTTPS访问。

原因分析

  1. 强制重定向拦截HTTP请求:第二个server块中,所有80端口的请求都会被301重定向到HTTPS,导致第一个server块的80端口监听实际不会处理任何请求。当用户通过HTTPS访问时,$scheme值为https,NGINX会尝试用HTTPS协议连接后端192.168.1.1。如果后端未配置HTTPS服务(无SSL证书、未开启443端口监听),就会出现连接失败,页面无法加载。
  2. 固定HTTP协议的兼容性:改为proxy_pass http://192.168.1.1/后,无论前端是HTTP还是HTTPS请求,NGINX都用HTTP协议连接后端,只要后端HTTP服务正常,就能正常响应。

解决方案

要实现同时支持HTTP和HTTPS访问,可按以下两种方式调整配置:

方案一:拆分HTTP和HTTPS独立server块

分别配置处理HTTP和HTTPS的server块,按需设置proxy_pass:

# 处理HTTP请求
server {
    listen 80;
    listen [::]:80;
    server_name example.com;
    
    large_client_header_buffers 4 16k;
    error_log   /var/log/nginx/example.com-http.log  info;
    access_log  /var/log/nginx/example.com-http.log  main;

    location / {
        proxy_redirect        off;
        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_http_version 1.1;
        proxy_set_header        Upgrade $http_upgrade;
        proxy_set_header        Connection 'upgrade';
        proxy_cache_bypass      $http_upgrade;
        proxy_set_header Connection $http_connection;
        proxy_set_header X-Real-Port $server_port;
        proxy_set_header X-Real-Scheme $scheme;
        proxy_read_timeout 3600;
        resolver_timeout 60s;
        
        client_max_body_size 50M;
        proxy_pass http://192.168.1.1/; # 后端用HTTP协议
    }
}

# 处理HTTPS请求
server {
    listen 443 ssl;
    listen [::]:443 ssl;       
    server_name example.com;
    
    large_client_header_buffers 4 16k;
    error_log   /var/log/nginx/example.com-https.log  info;
    access_log  /var/log/nginx/example.com-https.log  main;

    ssl_certificate root/fullchain.pem; 
    ssl_certificate_key root/privkey.pem;

    location / {
        proxy_redirect        off;
        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_http_version 1.1;
        proxy_set_header        Upgrade $http_upgrade;
        proxy_set_header        Connection 'upgrade';
        proxy_cache_bypass      $http_upgrade;
        proxy_set_header Connection $http_connection;
        proxy_set_header X-Real-Port $server_port;
        proxy_set_header X-Real-Scheme $scheme;
        proxy_read_timeout 3600;
        resolver_timeout 60s;
        
        client_max_body_size 50M;
        # 后端支持HTTPS可改为https://192.168.1.1/,否则保持http://
        proxy_pass http://192.168.1.1/;
    }
}

方案二:保留单个server块,移除强制重定向

若不需要将HTTP请求强制跳转HTTPS,可删除第二个server块,让第一个server块同时处理两种请求。此时需确保后端能处理对应协议请求,或统一用HTTP连接后端:

server {
    listen 80;
    listen [::]:80;
    listen 443 ssl;
    listen [::]:443 ssl;       
    server_name example.com;
    
    large_client_header_buffers 4 16k;
    error_log   /var/log/nginx/example.com.log  info;
    access_log  /var/log/nginx/example.com.log  main;

    ssl_certificate root/fullchain.pem; 
    ssl_certificate_key root/privkey.pem;

    location / {
        proxy_redirect        off;
        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_http_version 1.1;
        proxy_set_header        Upgrade $http_upgrade;
        proxy_set_header        Connection 'upgrade';
        proxy_cache_bypass      $http_upgrade;
        proxy_set_header Connection $http_connection;
        proxy_set_header X-Real-Port $server_port;
        proxy_set_header X-Real-Scheme $scheme;
        proxy_read_timeout 3600;
        resolver_timeout 60s;
        
        client_max_body_size 50M;
        # 后端仅支持HTTP则写http://192.168.1.1/,支持HTTPS可使用$scheme变量
        proxy_pass http://192.168.1.1/;
    }
}

关键提示

  • 若要使用$scheme作为proxy_pass的协议部分,必须确保后端对应协议服务正常运行(比如HTTPS需后端配置SSL证书并监听443端口)。
  • 强制重定向规则会阻断HTTP请求直接到达后端,若需同时支持两种访问方式,需调整重定向逻辑或拆分server块。

内容的提问来源于stack exchange,提问作者Augustus Buckman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 15:43:21