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

Amazon ELB与Django HTTPS配置问题:X-Forwarded-Proto异常显示http

问题分析与解决方案

Let's break down what's happening here and fix it step by step. The core issue is how your Nginx is handling the X-Forwarded-Proto header from the Classic ELB, which is causing Django to misidentify the request protocol.

Why You're Seeing HTTP_X_FORWARDED_PROTO = http

Your Classic ELB terminates HTTPS connections and forwards traffic to Nginx over HTTP (since Nginx listens on port 80). In this setup, Nginx's internal $scheme variable resolves to http—so when you set X-Forwarded-Proto $scheme, you're telling Django the request came over HTTP, even though the original user request was HTTPS.

The good news: Classic ELB automatically adds an X-Forwarded-Proto: https header to requests that came in via HTTPS. You just need to pass this header directly to Django instead of using Nginx's local $scheme value.


Step 1: Fix Nginx's X-Forwarded-Proto Configuration

Update your Nginx location block to forward the ELB-provided X-Forwarded-Proto header instead of using $scheme:

server {
    listen 80;
    listen [::]:80;

    # Keep your existing redirect logic (it's correct!)
    if ($http_x_forwarded_proto = 'http') {
        return 301 https://$server_name$request_uri;
    }

    location / {
        proxy_pass_header Server;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        # Replace $scheme with $http_x_forwarded_proto here
        proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
        proxy_set_header X-Scheme $http_x_forwarded_proto;
        proxy_pass http://app_server;
    }
}

Step 2: Verify Classic ELB Header Forwarding

Classic ELB enables forwarding of X-Forwarded-Proto, X-Forwarded-For, and X-Forwarded-Port by default, but double-check to be safe:

  • Go to the AWS EC2 Console → Your Classic ELB → Listeners tab
  • Confirm your HTTPS (443) listener forwards traffic to HTTP (80) on your Nginx instances
  • Ensure no custom header rules are overriding the default X-Forwarded-Proto header

Step 3: Confirm Django Configuration

Your current Django settings are already correct—no changes needed here:

SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
SECURE_SSL_REDIRECT = False

SECURE_PROXY_SSL_HEADER tells Django to trust the X-Forwarded-Proto header from your proxy (Nginx/ELB), which will now correctly report https.


Testing the Fix

  1. Add Nginx logging to verify headers:
    Add this log format to your Nginx server block to track the X-Forwarded-Proto value from ELB:

    log_format elb_combined '$remote_addr - $remote_user [$time_local] "$request" '
                            '$status $body_bytes_sent "$http_referer" '
                            '"$http_user_agent" "$http_x_forwarded_proto"';
    access_log /var/log/nginx/elb_access.log elb_combined;
    

    After accessing your site, check the log—you should see "https" for HTTPS requests.

  2. Validate Django's request metadata:
    Re-run your print(request.META.get('HTTP_X_FORWARDED_PROTO')) test. It should now return https, and DRF's auto-generated docs will use HTTPS links.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 09:31:06