Nginx – AWS ELB+Reverse Proxy (Nginx)+ELBs: Force SSL

amazon-elbnginxssl

I've reviewed/attempted prior suggestions found on the web to no avail.

I currently have an ELB setup in front of my Nginx reverse proxy which then passes traffic onto 3 distinct ELBs which reside in front of 3 distinct web apps (running on EC2). I need to ensure that traffic coming to the first ELB+Rev Proxy is always SSL. The rev proxy then routes to the various apps depending on the route.

Here is snippet of my nginx/sites-available/example.conf file:

server {
 listen 80;
 server_name staging.example.com;
 return 301 https://staging.example.com$request_uri;
}

server {
 listen 443 ssl;
 server_name staging.example.com;
 ssl_certificate /location
 ssl_certificate_key /location


 location /app1 {
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header Host $http_host;
  proxy_pass http://ELB
 }

}

When using the above, and trying prior information found on the web, once implemented that first ELB would stop working. If I then went directly to the rev proxy traffic wasn't making it through but the page wouldn't error out, it would just be blank.

Questions:
1. Assuming my rev proxy settings above are correct, once traffic becomes https and enters the ELB/Rev Proxy, does it continue on via https to the other ELBs? In other words do those ELBs need to have inbound 443 open, or will 80 work as traffic then switches over to http?
2. Do I need to change any of the settings within my location /app1 configuration, especially the proxy settings?

Best Answer

First, let me make sure that I am understanding your design properly:

--- HTTPS --> ELB -> nginx --- HTTP ---> ELB1 --> server1
                           --- HTTP ---> ELB1 --> server2
                           --- HTTP ---> ELB1 --> server3

Is that correct?

Assuming the above is correct, then to ensure that only HTTPS enters that first/frontend EBL, you can configure that frontend ELB with an HTTPS listener on port 443. That's it.

As for your first question, the requests coming out of the ELB to your backend server (the frontend nginx) will be HTTP. You have to go out of your way to configure an ELB to use SSL for the backend connections.

This means, then, that your backend ELBs only need listeners on port 80, for HTTP requests. (Or port 8080, or whatever port you want those backend ELBs to use.)

One suggestion I might add is that you create a separate "frontend-elb" security group, and a separate "backend-elb" security group. The frontend ELB (and frontend nginx instance!) should use the "frontelb-elb" security group, and the backend ELBs (and backend webapp instances!) should all use the "backend-elb" security group. The "frontend-elb" security group should allow incoming requests from anywhere (assuming, of course, that you want your services to be publicly available). The "backend-elb" security group, though, should only allow incoming connections from the "frontend-elb" security group. This will ensure that the only way to reach your webapps is through that frontend ELB, which in turn ensures that only HTTPS requests will reach your webapps.

As for your nginx proxy configuration, I think it looks OK. I should point out, however, that AWS ELBs will automatically set the X-Forwarded-For (and X-Forwarded-Proto) headers; you may not need to set that explicitly in your nginx configuration.

Hope this helps!