When dealing with Elastic Beanstalk environments that use Load Balancers (which is most production setups), there's a critical architectural detail many developers miss: the SSL termination happens at the LB level. This means your EC2 instances receive HTTP traffic even when the original request was HTTPS.
The standard Apache mod_rewrite
approach fails because:
# This WON'T work in EB with ALB:
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
The %{HTTPS}
variable always shows "off" since the LB already terminated SSL.
For Docker-based Python environments (specifically Debian Jessie), create this .ebextensions/https-redirect.config
:
files:
"/etc/nginx/conf.d/https_redirect.conf":
content: |
server {
listen 80;
if ($http_x_forwarded_proto = "http") {
return 301 https://$host$request_uri;
}
}
container_commands:
01_restart_nginx:
command: "service nginx restart"
If you're using Apache instead of Nginx, use this in .ebextensions/securelistener.config
:
files:
"/etc/httpd/conf.d/ssl_rewrite.conf":
content: |
RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} =http
RewriteRule .* https://%{HTTP:Host}%{REQUEST_URI} [L,R=permanent]
After deployment, verify with:
curl -I -H "X-Forwarded-Proto: http" http://yourdomain.com
Should return 301 with Location header pointing to HTTPS.
- Double redirects: Ensure your ALB listener rules don't conflict
- Mixed content: Update all absolute URLs in your Ember app to use
https://
- Health checks: Whitelist the ELB health check path from redirects
Since you're using Elastic Beanstalk with a load balancer, the most reliable method is to leverage the X-Forwarded-Proto
header that AWS ALB automatically injects. Here's how to implement this in your Docker/Python environment:
# .ebextensions/01_https_redirect.config
files:
"/etc/nginx/conf.d/https_redirect.conf":
mode: "000644"
owner: root
group: root
content: |
server {
listen 80;
if ($http_x_forwarded_proto = "http") {
return 301 https://$host$request_uri;
}
}
container_commands:
01_reload_nginx:
command: "service nginx reload"
If you prefer handling this at the application level (especially useful for Python WSGI apps), add this middleware:
# https_redirect_middleware.py
from django.http import HttpResponsePermanentRedirect
class HTTPSRedirectMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
if 'HTTP_X_FORWARDED_PROTO' in request.META:
if request.META['HTTP_X_FORWARDED_PROTO'] == 'http':
return HttpResponsePermanentRedirect(
'https://' + request.get_host() + request.path
)
return self.get_response(request)
When this doesn't work, check these troubleshooting steps:
- Verify ALB listeners: Ensure both HTTP (port 80) and HTTPS (port 443) listeners exist
- Confirm security groups: The instance must allow HTTP traffic from the ALB
- Check nginx logs:
sudo tail -f /var/log/nginx/access.log
For Docker containers, you'll need to modify the nginx config inside the container:
# Dockerfile
RUN rm /etc/nginx/conf.d/default.conf
COPY nginx.conf /etc/nginx/conf.d/default.conf
With corresponding nginx config:
# nginx.conf
server {
listen 80;
server_name _;
if ($http_x_forwarded_proto != "https") {
return 301 https://$host$request_uri;
}
location / {
proxy_pass http://localhost:8000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}