When using Nginx as a reverse proxy for an Apache backend with HTTP authentication, developers often encounter a frustrating scenario where the HTTP_AUTHORIZATION
header mysteriously vanishes during the proxy pass. This isn't actually Nginx filtering it out - the header is being passed, but gets lost in the Apache/mod_wsgi chain.
First, ensure your Nginx proxy configuration properly forwards all headers:
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://localhost:81;
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 Authorization $http_authorization;
proxy_pass_header Authorization;
}
}
Even with proper Nginx configuration, Django applications running under mod_wsgi won't receive the authorization headers by default. This is a security feature in mod_wsgi that intentionally filters these headers.
For Django/mod_wsgi setups, add this directive to your Apache configuration:
<VirtualHost *:81>
WSGIPassAuthorization On
# Other Apache configuration...
</VirtualHost>
To verify headers are being passed correctly, create a simple test endpoint:
# Django view example
def header_test(request):
return JsonResponse({
'auth_header': request.META.get('HTTP_AUTHORIZATION'),
'all_headers': dict(request.META)
})
For non-WSGI setups or when you need more control:
# Apache mod_rewrite solution
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},NE]
Or using Nginx to transform the header:
map $http_authorization $auth_header {
default $http_authorization;
"" $sent_http_authorization;
}
When setting up Nginx as a reverse proxy for an Apache backend that requires HTTP authentication, many developers encounter a frustrating issue: the HTTP_AUTHORIZATION
header gets mysteriously dropped during the proxy pass. This becomes particularly problematic when working with dynamic Basic Auth scenarios where hardcoding credentials in the Nginx config isn't feasible.
Here's a typical Nginx proxy setup that exhibits this behavior:
server {
listen 80;
server_name example.co.uk;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
location / {
proxy_pass http://localhost:81/;
}
}
After extensive debugging, I discovered that while Apache was actually receiving the auth headers, they were being filtered out by mod_wsgi when used with frameworks like Django. This explains why many developers initially think the issue lies with Nginx configuration.
To properly handle HTTP authentication through this stack, we need two key configurations:
1. Nginx Proxy Configuration
First, ensure Nginx preserves the auth header:
server {
# ... other configurations ...
location / {
proxy_pass http://localhost:81/;
proxy_set_header Authorization $http_authorization;
proxy_pass_request_headers on;
}
}
2. Apache mod_wsgi Configuration
Then, tell mod_wsgi to pass through the authorization headers:
<VirtualHost *:81>
# ... other configurations ...
WSGIPassAuthorization On
</VirtualHost>
If you're not using mod_wsgi but still experiencing header drops, try this more comprehensive Nginx configuration:
server {
listen 80;
server_name example.co.uk;
location / {
proxy_pass http://localhost:81;
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_set_header Authorization $http_authorization;
proxy_pass_request_headers on;
proxy_pass_request_body on;
}
}
To verify everything works, create a simple test endpoint in your Django application:
from django.http import HttpResponse
def auth_test(request):
auth_header = request.META.get('HTTP_AUTHORIZATION')
if auth_header:
return HttpResponse(f"Auth header received: {auth_header}")
return HttpResponse("No auth header received", status=401)
Then test with curl:
curl -u username:password http://example.co.uk/auth-test/
When implementing this solution:
- Benchmark your setup as passing additional headers adds minor overhead
- Consider caching authenticated responses where appropriate
- Ensure your logging configuration doesn't accidentally log credentials
When working with authorization headers:
- Always use HTTPS to prevent credential exposure
- Set appropriate timeout values for your proxy connections
- Consider implementing rate limiting to prevent brute force attacks