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-Protoheader
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
Add Nginx logging to verify headers:
Add this log format to your Nginx server block to track theX-Forwarded-Protovalue 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.Validate Django's request metadata:
Re-run yourprint(request.META.get('HTTP_X_FORWARDED_PROTO'))test. It should now returnhttps, and DRF's auto-generated docs will use HTTPS links.
内容的提问来源于stack exchange,提问作者psychok7

