Skip to content

Instantly share code, notes, and snippets.

@deepak
Last active February 22, 2019 22:11
Show Gist options
  • Select an option

  • Save deepak/d0db832088112d200924f1f4d65e733d to your computer and use it in GitHub Desktop.

Select an option

Save deepak/d0db832088112d200924f1f4d65e733d to your computer and use it in GitHub Desktop.

Revisions

  1. deepak revised this gist Apr 29, 2016. No changes.
  2. deepak revised this gist Apr 29, 2016. 1 changed file with 24 additions and 0 deletions.
    24 changes: 24 additions & 0 deletions steps.txt
    Original file line number Diff line number Diff line change
    @@ -101,4 +101,28 @@ location @example {

    `proxy_set_header Host $http_host;` is https specific. Others are for the reverse-proxy.

    Also notice that, in the above code-snippet, we proxy to `http` not `https`. Otherwise we will get error like

    ```
    if proxying to https, logs will look like


    ==> /shared/log/nginx.error.log <==
    2016/04/12 09:05:34 [info] 8373#0: *347 peer closed connection in SSL handshake while SSL handshaking, client: <some-ip>, server: 0.0.0.0:443
    2016/04/12 09:05:35 [info] 8373#0: *348 peer closed connection in SSL handshake while SSL handshaking, client: <some-ip>, server: 0.0.0.0:443
    2016/04/12 09:05:35 [info] 8373#0: *349 peer closed connection in SSL handshake while SSL handshaking, client: <some-ip>, server: 0.0.0.0:443
    2016/04/12 09:05:35 [info] 8373#0: *350 peer closed connection in SSL handshake while SSL handshaking, client: <some-ip>, server: 0.0.0.0:443
    2016/04/12 09:05:36 [info] 8373#0: *351 peer closed connection in SSL handshake while SSL handshaking, client: <some-ip>, server: 0.0.0.0:443
    2016/04/12 09:05:36 [info] 8373#0: *352 peer closed connection in SSL handshake while SSL handshaking, client: <some-ip>, server: 0.0.0.0:443
    2016/04/12 09:05:37 [info] 8373#0: *353 peer closed connection in SSL handshake while SSL handshaking, client: <some-ip>, server: 0.0.0.0:443
    2016/04/12 09:05:37 [info] 8373#0: *354 peer closed connection in SSL handshake while SSL handshaking, client: <some-ip>, server: 0.0.0.0:443
    2016/04/12 09:19:03 [info] 8373#0: *359 recv() failed (104: Connection reset by peer) while SSL handshaking, client: 5.45.64.228, server: 0.0.0.0:443
    2016/04/12 09:23:20 [error] 8373#0: *361 SSL_do_handshake() failed (SSL: error:140770FC:SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol) while SSL handshaking to upstream, client: 202.83.38.120, server: example.com, request: "GET / HTTP/1.1", upstream: "https://unix:///shared/tmp/sockets/puma.sock:/", host: "example.com"

    ==> /shared/log/puma.access.log <==
    ---
    2016-04-12 09:03:30 +0200: HTTP parse error, malformed request (127.0.0.1): #<Puma::HttpParserError: Invalid HTTP format, parsing fails.>
    2016-04-12 09:03:30 +0200: ENV: {"rack.version"=>[1, 3], "rack.errors"=>#<File:/current/log/puma.access.log>, "rack.multithread"=>true, "rack.multiprocess"=>false, "rack.run_once"=>false, "SCRIPT_NAME"=>"", "QUERY_STRING"=>"", "SERVER_PROTOCOL"=>"HTTP/1.1", "SERVER_SOFTWARE"=>"2.16.0", "GATEWAY_INTERFACE"=>"CGI/1.2", "REMOTE_ADDR"=>"127.0.0.1"}
    ```

    in the rails server logs. [puma](http://puma.io) in this case
  3. deepak revised this gist Apr 29, 2016. 1 changed file with 104 additions and 0 deletions.
    104 changes: 104 additions & 0 deletions steps.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,104 @@
    Followed the digital ocean guide on [Nginx + Let's Encrypt](https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-ubuntu-14-04)

    For additional security the guide suggests to generate a `dhparam` file
    it is [recommended](http://security.stackexchange.com/questions/38206/can-someone-explain-a-little-better-what-exactly-is-accomplished-by-generation-o) for a new random seed value

    command: `sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048`

    After the `Let's Encrypt` setup is done, we will use the following certificate files:

    - fullchain.pem
    - privkey.pem

    They are stored under the `/etc/letsencrypt/live/some.example.com/` folder
    replace `some.example.com` with your website

    Now that the certificates are already generated, the steps to steps to configure `Nginx` + `Puma (the rails server` are:

    - edit the site config. will be under `/etc/nginx/sites-enabled/site-name` to add `ssl`

    am guessing ssl is not configuered.
    there might be a `listen 80` or something like it
    or there will be no `listen` directive at all, which as per the [docs](http://nginx.org/en/docs/http/ngx_http_core_module.html#listen) means that:

    ```
    If the directive is not present then either *:80 is used
    if nginx runs with the superuser privileges, or *:8000 otherwise.
    ```

    `ssl` is not on by default so we need to add it

    change it to something like:

    ```
    server {
    listen 443 ssl;
    server_name some.example.com;

    ssl_certificate /etc/letsencrypt/live/some.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/some.example.com/privkey.pem;

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    ssl_dhparam /etc/ssl/certs/dhparam.pem;
    ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:50m;
    ssl_stapling on;
    ssl_stapling_verify on;

    # is set by rails to "max-age=31536000"
    # so not valid here
    # add_header Strict-Transport-Security max-age=15768000;
    ...
    }
    ```

    The Digital Ocean [guide](https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-ubuntu-14-04) asks us to add a `add_header Strict-Transport-Security max-age=15768000;` header. but [Rails](http://rubyonrails.org) already sets it for us. Adding it here duplicates the same header in the response, but with different values.

    so the response looks like:

    ```
    add_header Strict-Transport-Security max-age=15768000;
    add_header Strict-Transport-Security max-age=31536000;
    ```

    This is not what we want. No error is shown on the browser. But am not sure which value is used and [ssllabs](www.ssllabs.com/ssltest/analyze.html) throws a warning. So let [Rails](http://rubyonrails.org) manage it for us.

    - make sure `http` redirects to `https`

    ```
    server {
    listen 80 deferred;
    server_name some.example.com;
    return 307 https://example.com$request_uri;
    }
    ```

    Again some changes here from the Digital Ocean [guide](https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-ubuntu-14-04).

    - they use [301 Moved Permanently](http://httpstatus.es/301). But we use a [307 Temporary Redirect](https://httpstatuses.com/307). Just in case we change our mind. Although I cannot think of a good reason why we would want to do that :-)
    - `deferred` is just a linux only performance micro-tweak. see [h5bp](https://github.com/h5bp/server-configs-nginx/issues/100)

    - reload nginx with a `sudo service nginx reload`
    - test that the website works by going to the `https` url eg. `https://some.example.com`
    and that the `http` url redirects to the https version
    - lint that the `ssl` setup is correct by visiting `ssllabs`. eg. url is `https://www.ssllabs.com/ssltest/analyze.html?d=some.example.com`. replace the param at the end with your own website url

    A potential cause for error might be that the ruby http/s parser cannot recognize the https request. Rails and most of the http servers depend on the `host` header being set for https

    ```
    location @example {
    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;
    proxy_set_header Host $http_host;
    proxy_redirect off;

    proxy_pass http://example;
    }
    ```

    `proxy_set_header Host $http_host;` is https specific. Others are for the reverse-proxy.


  4. deepak revised this gist Apr 12, 2016. 1 changed file with 4 additions and 1 deletion.
    5 changes: 4 additions & 1 deletion example nginx config.txt
    Original file line number Diff line number Diff line change
    @@ -42,7 +42,10 @@ server {
    ssl_session_cache shared:SSL:50m;
    ssl_stapling on;
    ssl_stapling_verify on;
    add_header Strict-Transport-Security max-age=15768000;

    # is set by rails to "max-age=31536000"
    # so not valid here
    # add_header Strict-Transport-Security max-age=15768000;

    location ^~ /assets/ {
    gzip_static on;
  5. deepak created this gist Apr 12, 2016.
    67 changes: 67 additions & 0 deletions example nginx config.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,67 @@
    # rails config needs `force_ssl`
    # example:
    # Force all access to the app over SSL, use Strict-Transport-Security,
    # and use secure cookies.
    # config.force_ssl = true
    # and rails needs some headers to be set, otherwise will be trapped in a redirect loop
    # nginx config for headers:
    # 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;
    # proxy_set_header Host $http_host;

    # help at
    # https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-ubuntu-14-04

    upstream example {
    server unix:///<path>/shared/tmp/sockets/puma.sock fail_timeout=1;
    }

    server {
    listen 80 default deferred;
    server_name example.com;
    return 307 https://example.com$request_uri;
    }

    server {
    listen 443 ssl;
    server_name example.com;

    root <path>/current/public;
    access_log <path>/current/log/nginx.access.log;
    error_log <path>/current/log/nginx.error.log info;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    ssl_dhparam /etc/ssl/certs/dhparam.pem;
    ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:50m;
    ssl_stapling on;
    ssl_stapling_verify on;
    add_header Strict-Transport-Security max-age=15768000;

    location ^~ /assets/ {
    gzip_static on;
    expires max;
    add_header Cache-Control public;
    }

    try_files $uri/index.html $uri @example;
    location @example {
    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;
    proxy_set_header Host $http_host;
    proxy_redirect off;

    proxy_pass http://example;
    }

    error_page 500 502 503 504 /500.html;
    client_max_body_size 10M;
    keepalive_timeout 10;
    }