A while back, I wrote about configuring a Rails app to always enforce HTTPS behind an ELB. The main problem is that it’s easy to setup the blanket requirement for HTTPS, but when you are behind an ELB, where the ELB is acting as the HTTPS endpoint and only sending HTTP traffic to your server, you break the ability to respond with an
HTTP 200 OK response for the health check that the ELB needs. This is because your blanket HTTPS enforcement will redirect the ELB’s health check from HTTP to HTTPS – and that redirection is not considered to be a healthy response by the ELB.
The same applies to any server you’re running behind an ELB in this fashion.
This posts discusses how to handle the same issue with Nginx.
In this scenario, we have an ELB accepting HTTPS traffic and proxying it over HTTP in the clear to an Nginx server listening on port 80. We want Nginx to force all requests that were not originally made with HTTPS to redirect to the same URL on HTTPS, except requests for the health check, which the ELB will make directly over HTTP. For this example, we are using Nginx as a reverse proxy to upstream server processes on the same instance, such as a unicorn webserver hosting a Sinatra app. (This would work well for Rails, too).
There are two main components that make up this solution:
- A specific
locationdirective for the health check URL that does not do any HTTPS enforcement.
- A redirect if the
X-Forwarded-Proto: httpsheader does not exist.
For best-practice, we can add HTTP Strict Transport Security with the
add_header directive here too. Below is an example of a simplified nginx config file demonstrating these.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43