Skip to content

Instantly share code, notes, and snippets.

@petelacey
Last active April 9, 2019 13:45
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save petelacey/e35c98f9a35063a89fa9 to your computer and use it in GitHub Desktop.
Save petelacey/e35c98f9a35063a89fa9 to your computer and use it in GitHub Desktop.
Nginx always-on SSL config for ElasticBeanstalk
files:
"/etc/nginx/conf.d/000_APP_NAME.conf":
mode: "000755"
owner: root
group: root
content: |
upstream APP_NAME_app {
server unix:///var/run/puma/my_app.sock;
}
map $uri $preferred_proto {
default "https";
~^/(assets|public)/ "none";
~^/health "http";
}
server {
listen 80;
if ($preferred_proto = "http") {
set $http_x_forwarded_proto $preferred_proto;
}
if ($preferred_proto = "none") {
set $preferred_proto $http_x_forwarded_proto;
}
if ($preferred_proto != $http_x_forwarded_proto) {
rewrite ^(.*) $preferred_proto://$host$request_uri redirect;
}
location / {
proxy_pass http://APP_NAME_app;
proxy_set_header Connection "";
proxy_http_version 1.1;
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 https;
}
location /assets {
alias /var/app/current/public/assets;
gzip_static on;
gzip on;
expires max;
add_header Cache-Control public;
}
location /public {
alias /var/app/current/public;
gzip_static on;
gzip on;
expires max;
add_header Cache-Control public;
}
}
Using ElasticBeanstalk to deploy a Rails app using Puma?
Want always on SSL even when the downstream app doesn't speak SSL?
Also want health checks from ELB?
Then drop the file below into your .ebextensions directory
To use, change instances of "APP_NAME" to some other string. In my case it's "synclinical." You'll likely want other
changes to. For instance, the upstream server communication protocol and the path to your health check action.
This is cobbled together from other places on the web, mostly this: http://www.redant.com.au/ruby-on-rails-devops/manage-ssl-redirection-in-nginx-using-maps-and-save-the-universe/
The premise is: a connection is made to ELB over HTTP or HTTPS. That request is sent to nginx over HTTP, which sets
$http_x_forwarded_proto to 'https'. In addition, ELB is periodically pinging http://health on the backend too.
All HTTP requests that are not for /health, /assets, or /public, get redirected to the same HTTPS path. If the request
is for /assets or /public, then it will be passed through regardless of the protocol, that is, it will not be redirected.
And if the request is for /health, it will only be good for HTTP. In short:
/health --> HTTP
/assets --> HTTP/HTTPS
/public --> HTTP/HTTPS
all others --> redirected to HTTPS
When the request is proxied to the Rails (or whatever) backend, we set X-REAL-IP, X-FORWARDED-FOR, and
X-FORWARDED-PROTO. Among other things, this lets you set: 'config.force_ssl = true' in your production.rb environment
file (even though the application host, e.g. Puma, is not really running SSL), which will turn on Strict Transport Security,
and secure cookies.
The 'location' settings for /assets and /public simply allow nginx to serve up these static assets (JS, CSS, images) instead
of Rails, compressed and with maximal cache control headers.
@jkburges
Copy link

👍 this worked straight off the bat for me.

@abuisman
Copy link

abuisman commented Mar 24, 2017

I didn't like using my own nginx config and after days of searching I ran into this beauty of a gem: https://github.com/lserman/aws-healthcheck

It creates a http route for /healthcheck that returns 200. Works like a charm without messy configs.

@f6v
Copy link

f6v commented Sep 11, 2017

@petelacey thanks for the gist! One question though, should my EC2 instance be able to terminate SSL? Or ELB is the only one who decrypts https?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment