[SOLVED] Mup problem with 1.4.2

Thanks. Also, in this file it requires the full path to the SSL cert and key.

ssl_certificate /etc/nginx/ssl/todos.pem; # full path to SSL certificate and CA certificate concatenated together
ssl_certificate_key /etc/nginx/ssl/todos.key; # full path to SSL key

This is where I need to add in the Let’s Encrypt results.

Yes, see the snipped I posted above. If you use letsencrypt it should look like this:

ssl_certificate /etc/letsencrypt/live/DOMAIN_NAME/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/DOMAIN_NAME/privkey.pem;
1 Like

Thanks again. So I finished with the config file and started looking at creating the cert, when inside the instructions you posted about setting up the nginx server I found this: https://www.digitalocean.com/community/tutorials/how-to-create-a-ssl-certificate-on-nginx-for-ubuntu-12-04

What is this Self-Signed Cert about? It states that ‘Certificate Authorities can issue SSL certificates that verify the server’s details while a self-signed certificate has no 3rd party corroboration.’ Is it recommended to use 3rd party corroboration over self-signed?

Don’t bother. Self-Signed certs are as the name implies - certs that are signed only by you. The problem with them is that no browser will trust them, so if you use them on your website your users will get a nasty security warning each time they visit.

Let’s Encrypt on the other hand is a Certificate Authority which can issue certs that are trusted by browsers. They do it for free and release tools to automate the process as much as possible.

1 Like

The DOMAIN_NAME is going to be the URL the site will point to? For example what if I have staging.my-site.com and testing.my-site.com? I have staging.my-site.com and testing.my-site.com on two different EC2 servers. Is the DOMAIN_NAME my-site.com or *.my-site.com? How does that work?

Thanks. Following your let’s encrypt instructions now.

You have to generate certificates for each subdomain (so the domain name will be staging.my-site.com or testing.my-site.com in your case), because Let’s Encrypt doesn’t support wildcart domain certificates. If your domains point to different servers, you will have to do all those steps on both servers replacing the DOMAIN_NAME with the correct domain that points to this server.

1 Like

Thank you for all your help so far. :slight_smile:

While running the command:

$ ./letsencrypt-auto certonly -a webroot --webroot-path=/var/www -d staging.my-site.com

I get this error:

Failed authorization procedure. staging.my-site.com (http-01): 
urn:acme:error:unauthorized 
:: The client lacks sufficient authorization 
:: Invalid response from http://staging.my-site.com/.well-known/acme-challenge/gRTS9H6hrFB56suiG-1Hc34EERE5tAZlWay54VRadbCDDw: "
<!DOCTYPE html>
<html>
<head>
  <link rel="stylesheet" type="text/css" class="__meteor-css__" href="/b1614051fghsd1a081c4534aerfasdf"
IMPORTANT NOTES:
Domain: staging.my-site.com
   Type:   unauthorized
   Detail: Invalid response from
   http://staging.my-site.com/.well-known/acme-challenge/gRTS9H6hrFB56suiG-1Hc34EERE5tAZlWay54VRadbCDDw:
   "<!DOCTYPE html>
   <html>
   <head>
     <link rel="stylesheet" type="text/css" class="__meteor-css__"
   href="/b1614051fghsd1a081c4534aerfasdf"

Further it states:

To fix these errors, please make sure that your domain name was
   entered correctly and the DNS A record(s) for that domain
   contain(s) the right IP address.
 - Your account credentials have been saved in your Certbot
   configuration directory at /etc/letsencrypt. You should make a
   secure backup of this folder now. This configuration directory will
   also contain certificates and private keys obtained by Certbot so
   making regular backups of this folder is ideal.

In my case the domain was entered correctly and the DNS A record for the domain does contain the right IP address as far as I know.

UPDATE:
Wait, it just occurred to me, that staging.my-site.com domain is currently running on another EC2 instance that has it’s own IP.

I stood up this fresh new EC2 instance to basically test this deployment out on it. Could there be an issue since the current staging.my-site.com is on another IP that the one I’m installing all these tools on?

Should I stop that old EC2 instance that staging.my-site.com is running on and install staging.my-site.com on this new EC2 instance and point staging.my-site.com to this new IP?

UPDATE2:
The A Record is pointing to the old EC2 instance that is currently hosting staging.my-site.com. I guess I need to change that A Record to the new EC2 instance i’m trying to install the new tools on?

You need to add the following to your Nginx site configuration (to each server block) for Let’s Encrypt to work properly:

    location ^~ /.well-known {
        root /var/www/;
        default_type "text/plain";
        allow all;
    }

It should be added BEFORE other location blocks.

1 Like

Thanks. I added that, here is what I have in the file right now:

This file staging-mysite-com (with no file extension) was added to /etc/nginx/sites-available:

server_tokens off; # for security-by-obscurity: stop displaying nginx version

# this section is needed to proxy web-socket connections
map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

# HTTP
server {
    listen 80 default_server; # if this is not a default server, remove "default_server"
    listen [::]:80 default_server ipv6only=on;

    root /usr/share/nginx/html; # root is irrelevant
    index index.html index.htm; # this is also irrelevant

    server_name staging-mysite.com; # the domain on which we want to host the application. Since we set "default_server" previously, nginx will answer all hosts anyway.

    # for Let's Encrypt to work properly
    location ^~ /.well-known {
        root /var/www/;
        default_type "text/plain";
        allow all;
    }

    # redirect non-SSL to SSL
    location / {
        rewrite     ^ https://$server_name$request_uri? permanent;
    }
}

# HTTPS server
server {
    listen 443 ssl spdy; # we enable SPDY here
    server_name todos.net; # this domain must match Common Name (CN) in the SSL certificate

    root html; # irrelevant
    index index.html; # irrelevant

    ssl_certificate /etc/letsencrypt/live/staging.mysite.com/fullchain.pem; # full path to SSL certificate and CA certificate concatenated together
    ssl_certificate_key /etc/letsencrypt/live/staging.mysite.com/privkey.pem; # full path to SSL key

    # performance enhancement for SSL
    ssl_stapling on;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 5m;

    # safety enhancement to SSL: make sure we actually use a safe cipher
    ssl_prefer_server_ciphers on;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384: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-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:ECDHE-RSA-RC4-SHA:ECDHE-ECDSA-RC4-SHA:RC4-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK';

    # config to enable HSTS(HTTP Strict Transport Security) https://developer.mozilla.org/en-US/docs/Security/HTTP_Strict_Transport_Security
    # to avoid ssl stripping https://en.wikipedia.org/wiki/SSL_stripping#SSL_stripping
    add_header Strict-Transport-Security "max-age=31536000;";

    # If your application is not compatible with IE <= 10, this will redirect visitors to a page advising a browser update
    # This works because IE 11 does not present itself as MSIE anymore
    if ($http_user_agent ~ "MSIE" ) {
        return 303 https://browser-update.org/update.html;
    }

    # pass all requests to Meteor
    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade; # allow websockets
        proxy_set_header Connection $connection_upgrade;
        proxy_set_header X-Forwarded-For $remote_addr; # preserve client IP

        # this setting allows the browser to cache the application in a way compatible with Meteor
        # on every applicaiton update the name of CSS and JS file is different, so they can be cache infinitely (here: 30 days)
        # the root path (/) MUST NOT be cached
        if ($uri != '/') {
            expires 30d;
        }
    }
}

But I’m still getting the same error when running the following command:

./letsencrypt-auto certonly -a webroot --webroot-path=/var/www -d staging.my-site.com
Domain: stagin.my-site.com
   Type:   unauthorized
   Detail: Invalid response from
   http://staging.my-site.com/.well-known/acme-challenge/gQ_sdfasdfaspMyDxrgYl8:
   "<!DOCTYPE html>
   <html>
   <head>
     <link rel="stylesheet" type="text/css" class="__meteor-css__"
   href="/asdfasdfasdf"
To fix these errors, please make sure that your domain name was
   entered correctly and the DNS A record(s) for that domain
   contain(s) the right IP address.

My A Record is pointing to the old EC2 instance IP that is currently hosting staging.my-site.com. Do I need to change that A Record to point to the new EC2 instance IP i’m trying to install these new tools and SSL on?

UPDATE:

This is the letsencrypt.log debug dump:

2016-12-17 21:54:01,727:DEBUG:certbot.main:Root logging level set at 20
2016-12-17 21:54:01,727:INFO:certbot.main:Saving debug log to /var/log/letsencrypt/letsencrypt.log
2016-12-17 21:54:01,732:DEBUG:certbot.main:certbot version: 0.9.3
2016-12-17 21:54:01,732:DEBUG:certbot.main:Arguments: ['-a', 'webroot', '--webroot-path=/var/www', '-d', 'staging.my-site.com']
2016-12-17 21:54:01,732:DEBUG:certbot.main:Discovered plugins: PluginsRegistry(PluginEntryPoint#standalone,PluginEntryPoint#manual,PluginEntryPoint#nginx,PluginEntryPoint#webroot,PluginEntryPoint#apache,PluginEntryPoint#null)
2016-12-17 21:54:01,735:DEBUG:certbot.plugins.selection:Requested authenticator webroot and installer None
2016-12-17 21:54:01,738:DEBUG:certbot.plugins.selection:Single candidate plugin: * webroot
Description: Place files in webroot directory
Interfaces: IAuthenticator, IPlugin
Entry point: webroot = certbot.plugins.webroot:Authenticator
Initialized: <certbot.plugins.webroot.Authenticator object at 0x7fbea6a31550>
Prep: True
2016-12-17 21:54:01,738:DEBUG:certbot.plugins.selection:Selected authenticator <certbot.plugins.webroot.Authenticator object at 0x7fbea6a31550> and installer None
2016-12-17 21:54:01,876:DEBUG:certbot.main:Picked account: <Account(057f5d2438cc6f04a918831750818c99)>
2016-12-17 21:54:01,877:DEBUG:root:Sending GET request to https://acme-v01.api.letsencrypt.org/directory. args: (), kwargs: {}
2016-12-17 21:54:01,879:INFO:requests.packages.urllib3.connectionpool:Starting new HTTPS connection (1): acme-v01.api.letsencrypt.org
2016-12-17 21:54:02,405:DEBUG:requests.packages.urllib3.connectionpool:"GET /directory HTTP/1.1" 200 352
2016-12-17 21:54:02,406:DEBUG:root:Received <Response [200]>. Headers: {'Content-Length': '352', 'Expires': 'Sat, 17 Dec 2016 21:54:02 GMT', 'Boulder-Request-Id': '3lf3Wb0ggSK52Rgm9bI0huFuxwGuf7Zf0iy_OR0Kd5A', 'Strict-Transport-Security': 'max-age=604800', 'Server': 'nginx', 'Connection': 'keep-alive', 'Pragma': 'no-cache', 'Cache-Control': 'max-age=0, no-cache, no-store', 'Date': 'Sat, 17 Dec 2016 21:54:02 GMT', 'X-Frame-Options': 'DENY', 'Content-Type': 'application/json', 'Replay-Nonce': 'H3c0E1X3-50_9ytcQ0mO291WZlOpLdO44lYR23RMLos'}. Content: '{\n  "key-change": "https://acme-v01.api.letsencrypt.org/acme/key-change",\n  "new-authz": "https://acme-v01.api.letsencrypt.org/acme/new-authz",\n  "new-cert": "https://acme-v01.api.letsencrypt.org/acme/new-cert",\n  "new-reg": "https://acme-v01.api.letsencrypt.org/acme/new-reg",\n  "revoke-cert": "https://acme-v01.api.letsencrypt.org/acme/revoke-cert"\n}'
2016-12-17 21:54:02,406:DEBUG:acme.client:Received response <Response [200]> (headers: {'Content-Length': '352', 'Expires': 'Sat, 17 Dec 2016 21:54:02 GMT', 'Boulder-Request-Id': '3lf3Wb0ggSK52Rgm9bI0huFuxwGuf7Zf0iy_OR0Kd5A', 'Strict-Transport-Security': 'max-age=604800', 'Server': 'nginx', 'Connection': 'keep-alive', 'Pragma': 'no-cache', 'Cache-Control': 'max-age=0, no-cache, no-store', 'Date': 'Sat, 17 Dec 2016 21:54:02 GMT', 'X-Frame-Options': 'DENY', 'Content-Type': 'application/json', 'Replay-Nonce': 'H3c0E1X3-50_9ytcQ0mO291WZlOpLdO44lYR23RMLos'}): '{\n  "key-change": "https://acme-v01.api.letsencrypt.org/acme/key-change",\n  "new-authz": "https://acme-v01.api.letsencrypt.org/acme/new-authz",\n  "new-cert": "https://acme-v01.api.letsencrypt.org/acme/new-cert",\n  "new-reg": "https://acme-v01.api.letsencrypt.org/acme/new-reg",\n  "revoke-cert": "https://acme-v01.api.letsencrypt.org/acme/revoke-cert"\n}'
2016-12-17 21:54:02,407:INFO:certbot.main:Obtaining a new certificate
2016-12-17 21:54:02,412:DEBUG:root:Requesting fresh nonce
2016-12-17 21:54:02,412:DEBUG:root:Sending HEAD request to https://acme-v01.api.letsencrypt.org/acme/new-authz. args: (), kwargs: {}
2016-12-17 21:54:02,475:DEBUG:requests.packages.urllib3.connectionpool:"HEAD /acme/new-authz HTTP/1.1" 405 0
2016-12-17 21:54:02,476:DEBUG:root:Received <Response [405]>. Headers: {'Content-Length': '91', 'Pragma': 'no-cache', 'Boulder-Request-Id': 'dnyIPuymxn3X0OGYW2cvpU9gQwg6Pk1ND_pbSOm_V-U', 'Expires': 'Sat, 17 Dec 2016 21:54:02 GMT', 'Server': 'nginx', 'Connection': 'keep-alive', 'Allow': 'POST', 'Cache-Control': 'max-age=0, no-cache, no-store', 'Date': 'Sat, 17 Dec 2016 21:54:02 GMT', 'Content-Type': 'application/problem+json', 'Replay-Nonce': 'WPzJeFuqJu7uP7C_Pv0WFaC8wvNqXP0F5vnZZdeanig'}. Content: ''
2016-12-17 21:54:02,476:DEBUG:acme.client:Storing nonce: 'X\xfc\xc9x[\xaa&\xee\xee?\xb0\xbf>\xfd\x16\x15\xa0\xbc\xc2\xf3j\\\xfd\x05\xe6\xf9\xd9e\xd7\x9a\x9e('
2016-12-17 21:54:02,476:DEBUG:acme.jose.json_util:Omitted empty fields: combinations=None, challenges=None, status=None, expires=None
2016-12-17 21:54:02,476:DEBUG:acme.client:Serialized JSON: {"identifier": {"type": "dns", "value": "staging.my-site.com"}, "resource": "new-authz"}
2016-12-17 21:54:02,477:DEBUG:acme.jose.json_util:Omitted empty fields: x5c=(), crit=(), kid=None, jwk=None, typ=None, alg=None, jku=None, x5tS256=None, cty=None, x5u=None, x5t=None
2016-12-17 21:54:02,479:DEBUG:acme.jose.json_util:Omitted empty fields: x5c=(), crit=(), kid=None, typ=None, nonce=None, jku=None, x5tS256=None, cty=None, x5u=None, x5t=None

That error has nothing to do with your DNS setup. Did you restart Nginx after modifying the config file? Also note, that this config file should be symlinked in /etc/nginx/sites-enabled directory for Nginx to pick it up.

One other note - you need for now to remove from the config the whole server block with the comment “HTTPS server” above it, because Nginx will complain that it cannot find the SSL certificate, and that’s because you didn’t generate it yet! Only after Let’s Encrypt successfully generates your cert you can paste that block again to the Nginx config file.

1 Like

Your advice worked! Thank you very much, I couldn’t have done this without your help!

Only a question, what does this command do?

$ openssl dhparam -out /etc/ssl/certs/dhparam.pem 4096

and in the config file:

ssl_dhparam /etc/ssl/certs/dhparam.pem;

Everything seemed to work without this config setting added in.

It creates Diffie-Hellman parameters, which increases the security of the SSL connections your server creates. It’s not mandatory, but it’s something good to have to be extra secure.

1 Like

The only issue I’m having now is my app is constantly refreshing. I’m on Meteor 1.3.5.1 behind the nginx using your mup lib to deploy. Strange, I never had this issue before using nginx.

I took out the following from the config:

if ($uri != '/') {
  expires 30d;
}

And the issue hasn’t returned yet.

Thanks again for all your help!