Skip to content

Instantly share code, notes, and snippets.

@chrisroos
Last active November 23, 2021 01:21
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chrisroos/1957bbdf21b2f4f5e900d6cd7d4817f0 to your computer and use it in GitHub Desktop.
Save chrisroos/1957bbdf21b2f4f5e900d6cd7d4817f0 to your computer and use it in GitHub Desktop.
Using a Let's Encrypt SSL certificate to serve a Rails app on Heroku

Intro

This is very similar to Collective Idea's blog post, "Let's Encrypt with a Rails app on Heroku". I ran through the process a couple of times to try to understand how the various parts fit together.

Create a new Rails app

NOTE. I'm skipping Active Record to make the deployment to Heroku slightly easier.

$ rails new rails-app-with-lets-encrypt --skip-active-record

Initialise git repository

$ cd rails-app-with-lets-encrypt
$ git init .
$ git add .
$ git commit -m 'Add empty Rails app'

Add public index page

To make it easier to confirm that we're connecting to our Rails app on Heroku.

$ echo "<h1>Rails app with Let's Encrypt</h1>" > public/index.html
$ git add .
$ git commit -m 'Add public index page'

Create the Heroku app

NOTE. Use your own application name here.

$ heroku apps:create rails-app-with-lets-encrypt
Creating ⬢ rails-app-with-lets-encrypt... done
https://rails-app-with-lets-encrypt.herokuapp.com/ | https://git.heroku.com/rails-app-with-lets-encrypt.git

Deploy to Heroku

$ git push heroku master

Test the app

Observe that we see the output of the index page added earlier.

$ curl https://rails-app-with-lets-encrypt.herokuapp.com
<h1>Rails app with Let's Encrypt</h1>

Add custom domain

$ heroku domains:add testing-lets-encrypt.seagul.co.uk
Adding testing-lets-encrypt.seagul.co.uk to ⬢ rails-app-with-lets-encrypt... done
 ▸    Configure your app's DNS provider to point to the DNS Target rails-app-with-lets-encrypt.herokuapp.com.
 ▸    For help, see https://devcenter.heroku.com/articles/custom-domains

Configure DNS

I'm using AWS Route 53 and manually configured my DNS records using the web console.

Test DNS

$ curl http://testing-lets-encrypt.seagul.co.uk
<h1>Rails app with Let's Encrypt</h1>

Use certbot to generate certificate

I've set the various *-dir options to the tmp directory in the Rails app. This was so that I could destroy the dummy Rails app and be confident that nothing's hanging around. You almost certainly won't want to do this if you were generating a certificate for real.

$ certbot certonly --manual \
  --domain testing-lets-encrypt.seagul.co.uk \
  --logs-dir tmp/letsencrypt/log/ \
  --config-dir tmp/letsencrypt/config/ \
  --work-dir tmp/letsencrypt/work/

Observe the output similar to:

Make sure your web server displays the following content at
http://testing-lets-encrypt.seagul.co.uk/.well-known/acme-challenge/<token> before continuing:

Create the required file:

NOTE. I'm using token and JWS as that's what I believe these things are according to the acme-spec.

$ mkdir -p ./public/.well-known/acme-challenge
$ echo "<JWS>" > \
./public/.well-known/acme-challenge/<token>
$ git add .
$ git commit -m "Add file required by Let's Encrypt"
$ git push heroku master

Test acme-challenge content

$ curl http://testing-lets-encrypt.seagul.co.uk/.well-known/acme-challenge/<token>
JWS

Finish certbot process

Observe the notice that says the certificate and chain have been saved.

Enable Heroku SSL (beta)

See Heroku SSL (Beta) for more information.

$ heroku labs:enable http-sni
Enabling http-sni for rails-app-with-lets-encrypt... done

$ heroku plugins:install heroku-certs
Installing plugin heroku-certs... done

Add certificate to Heroku

NOTE. Your Heroku app needs to be on a paid plan (at least "Hobby") for you to be allowed to use Heroku SSL. If you run the following command on a Free plan then you'll see the following error:

You need to be running on either Hobby or Professional dynos to be able to use SNI SSL.

NOTE. This command needs to be run as root as the certificate and key aren't publicly accessible.

$ sudo heroku _certs:add \
  tmp/letsencrypt/config/live/testing-lets-encrypt.seagul.co.uk/fullchain.pem \
  tmp/letsencrypt/config/live/testing-lets-encrypt.seagul.co.uk/privkey.pem
Resolving trust chain... done
Adding SSL certificate to ⬢ rails-app-with-lets-encrypt... done
Certificate details:
Common Name(s): testing-lets-encrypt.seagul.co.uk
Expires At:     2016-11-10 16:06 UTC
Issuer:         /C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
Starts At:      2016-08-12 16:06 UTC
Subject:        /CN=testing-lets-encrypt.seagul.co.uk
SSL certificate is verified by a root authority.

=== The following common names already have domain entries
testing-lets-encrypt.seagul.co.uk

=== Your certificate has been added successfully.  Update your application's DNS settings as follows
Domain                             Record Type  DNS Target
─────────────────────────────────  ───────────  ───────────────────────────────────────────────
testing-lets-encrypt.seagul.co.uk  CNAME        testing-lets-encrypt.seagul.co.uk.herokudns.com

Update DNS

I updated AWS Route 53 to point testing-lets-encrypt.seagul.co.uk at testing-lets-encrypt.seagul.co.uk.herokudns.com.

Test HTTPS access

$ curl https://testing-lets-encrypt.seagul.co.uk
<h1>Rails app with Let's Encrypt</h1>

View certificate details

$ curl -v -I https://testing-lets-encrypt.seagul.co.uk 2>&1 | grep certificate
* Server certificate: testing-lets-encrypt.seagul.co.uk
* Server certificate: Let's Encrypt Authority X3
* Server certificate: DST Root CA X3
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment