Setting up Let's Encrypt SSL Cert on KeystoneJS

641 views
Skip to first unread message

Chris Troutner

unread,
Apr 7, 2017, 5:22:02 PM4/7/17
to Keystone JS
Hey all,

A while ago, I was informed of this guide on settings up Let's Encrypt SSL certs for KeystoneJS:

I read through the guide and try to implement it, but I'm stuck and catch get KeystoneJS to launch. I think I'm close. If I can get a little help to get this working, I plan to write up a guide for the Keystone documentation on how to install NGINX to run multiple instances of Keystone AND how to set them up to serve pages over HTTPS.


Here are the steps I took:

  1. Register the domain name and set up the site as usual. (Domain name required)

  2. Setup nginx to serve static content. (optional)

  3. Install Certbot on the server: https://certbot.eff.org/#ubuntuxenial-nginx

  4. Install a certificate using Certbot. Example:
    sudo certbot certonly --webroot -w /home/safeuser/weekendfood/myCMS/public -d weekendfood.org

And that's about where I got stuck. I edited my keystone.js file to include these lines:

  'port': 3005,


  'ssl-port': 3006,
  'ssl': 'true',
  'letsencrypt': {
                email: 'chris.t...@gmail.com',
                domains: ['weekendfood.org'],
                register: true,
                tos: true,
        },




That should enable KeystoneJS to use the Let's Encrypt cert. I upgrade node to v4.8.2, because it was complaining about an older version of v4.x that I had. Here is the error that I'm getting:

le.challenges[http-01].loopback should be defined as function (opts, domain, token, keyAuthorization, cb) { ... } and should prove (by external means) that the ACME server challenge 'http-01' will succeed
le.challenges[tls-sni-01].loopback should be defined as function (opts, domain, token, keyAuthorization, cb) { ... } and should prove (by external means) that the ACME server challenge 'tls-sni-01' will succeed

------------------------------------------------
weekendfood failed to start: address already in use
Please check you are not already running a server on the specified port.


I've done some googling, but I can't find any solution to the loopback error or why I'm getting the 'address already in use' error. If I comment out the SSL stuff, I can run KeystoneJS like normal on port 3005 or 3006, so I know there is no other applications actually blocking those ports. The misleading error is definitely due to the SSL stuff. 


Any idea what the actual issue is, where it exists, and how to fix it?

Thanks in advance for any help you can provide!

-Chris Troutner

Chris Troutner

unread,
Apr 8, 2017, 9:45:16 PM4/8/17
to Keystone JS
For those who find this thread and are struggling with the same issues, I thought I'd post an update.

I got in touch with Wout Mertens, the guys who wrote the original tutorial, and help clear some things up. Apparently the KeystoneJS Let's Encrypt implementation is for single-domain servers that do not use NGINX.  Since I am using NGINX to run multiple KeystoneJS websites on the same Digital Ocean Droplet, I won't be able to use the KeystoneJS implementation in his tutorial. That's why I was running into issues.

So, I did some digging and I found this sweet little tutorial on the Digital Ocean website showing how to configure NGINX to use a Let's Encrypt certificate:
https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-ubuntu-16-04

My Droplet is currently running two simple, client sites: care-e-me.com and weekendfood.org. Here are the steps I used to get HTTP and a Let's Encrypt SSL certificate working for the weekendfood.org website:

Steps for setting up SSL certificate:
1. Register the domain name and set up the site as usual. (Domain name required)

2. Setup nginx to serve static content.

3. Install Certbot on the server: https://certbot.eff.org/#ubuntuxenial-nginx

4. Install a certificate using Certbot. Example:
sudo certbot certonly --webroot -w /home/safeuser/weekendfood/myCMS/public -d weekendfood.org


5. Generate a strong DH group:
sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048


a. This will create a file at /etc/ssl/certs/dhparam.pem

6. Create the file 
sudo nano /etc/nginx/snippets/ssl-example.com.conf

and add these lines to the file:

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

7. Create the file 
sudo nano /etc/nginx/snippets/ssl-params.conf

and add these lines to the file:
 # from https://cipherli.st/
 
# and https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html
 
 ssl_protocols
TLSv1 TLSv1.1 TLSv1.2;
 ssl_prefer_server_ciphers on
;
 ssl_ciphers
"EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
 ssl_ecdh_curve secp384r1
;
 ssl_session_cache shared
:SSL:10m;
 ssl_session_tickets off
;
 ssl_stapling on
;
 ssl_stapling_verify on
;
 resolver
8.8.8.8 8.8.4.4 valid=300s;
 resolver_timeout
5s;
 
# Disable preloading HSTS for now.  You can use the commented out header line that includes
 
# the "preload" directive if you understand the implications.
 
#add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
 add_header
Strict-Transport-Security "max-age=63072000; includeSubdomains";
 add_header X
-Frame-Options DENY;
 add_header X
-Content-Type-Options nosniff;
 
 ssl_dhparam
/etc/ssl/certs/dhparam.pem;


8. Backup the current NGINX config file:
sudo cp /etc/nginx/sites-available/default /etc/nginx/sites-available/default.bak


9. Update the config file with SSL instructions:


 server
{
 listen
80 default_server;
 listen
[::]:80 default_server;
 
 
#root /var/www/html;
 root
/home/safeuser/care-e-me/myCMS/public;
 
 server_name careeme
.com;
 
 location
/ {
 
# First attempt to serve request as file, then
 
# as directory, then fall back to displaying a 404.
 
#proxy_pass http://127.0.0.1:3001;
 
#try_files $uri $uri/ =404;
 
 
#http://ksloan.net/configuring-nginx-for-node-js-web-apps-that-serve-both-static-and-dynamic-content/
 try_files $uri
@backend;
 
 
}
 
 location
@backend {
 proxy_pass http
://127.0.0.1:3001;
 access_log off
;
 
 proxy_http_version
1.1;
 proxy_set_header
Upgrade $http_upgrade;
 proxy_set_header
Connection "upgrade";
 proxy_set_header
Host $host;
 proxy_hide_header X
-Frame-Options;
 
}
 
}
 
 server
{
 listen
80;
 
 
#root /var/www/html;
 root
/home/safeuser/weekendfood/myCMS/public;
 
 server_name weekendfood
.org;
 
 
#SSL
 
#return 301 https://$server_name$request_uri;
 
 
#SSL Configuration
 listen
443 ssl http2;
 
#listen[::]:443 ssl http2;
 include snippets
/ssl-weekendfood.org.conf;
 include snippets
/ssl-params.conf;
 
 location
/ {
 
# First attempt to serve request as file, then
 
# as directory, then fall back to displaying a 404.
 
#proxy_pass http://127.0.0.1:3002;
 
#try_files $uri $uri/ =404;
 
 
#http://ksloan.net/configuring-nginx-for-node-js-web-apps-that-serve-both-static-and-dynamic-content/
 try_files $uri
@backend;
 
 
}
 
 location
@backend {
 proxy_pass http
://127.0.0.1:3003;
 access_log off
;
 
 proxy_http_version
1.1;
 proxy_set_header
Upgrade $http_upgrade;
 proxy_set_header
Connection "upgrade";
 proxy_set_header
Host $host;
 proxy_hide_header X
-Frame-Options;
 
}
 
}

10. Check that there are no syntax errors in the config file:
sudo nginx -t


11. Restart nginx:
sudo systemctl restart nginx



Set up a Cron job for Automatic Renewal of SSL Certificates:
Note: This only needs to be done once per server.

1. Edit the root user cron tab: sudo crontab -e

2. Add these entries to the crontab:
30 2 * * 1 /usr/bin/certbot renew >> /var/log/le-renew.log
35 2 * * 1 /bin/systemctl reload nginx


Reply all
Reply to author
Forward
0 new messages