How to set up free SSL certificates with Let's Encrypt

Let’s Encrypt is a free Certificate Authority (CA), meaning you can enable SSL on your sites without having to pay some annual fee.

SSL using Let’s Encrypt

Before you can start the SSL registration, you’ll need your own domain or subdomain configured. I.e. you must already have serving traffic on a publicly-reachable server.

Get Let’s Encrypt to sign your CSR

Create a CSR (Certificate Signing Request) which effectively means generating a public/private key pair on your local machine.

Create a CSR using OpenSSL:

openssl req -nodes -nconfigurationewkey rsa:2048 -keyout your-domain.key -out your-domain.csr

OpenSSL will ask questions for the certificate registration. Some may have no obvious answer (for instance, I have no “Organization affiliation” so I used my name). Locking the CSR with a password is also not required. For the domain name, use your full path since Let’s Encrypt doesn’t support wildcard matches.

Verify your domain with Let’s Encrypt

You need to send the CSR to Let’s Encrypt that they can sign it and certify the public key belongs to your domain. This basically means you need to serve a simple webpage at a given URL on a server addressable by your hostname.

Depending on your hosting provider, there may be an option for automaticly set this up. For us we had to follow the manual steps

Manual domain verification with Let’s Encrypt

The tool to perform the manual verification can be installed in Fedora using:

sudo dnf install certbot

Once installed, I ran it pointing all config paths to the location on my machine where I want the certs/keys to live. You’ll want to maintain the output of the tool and back-up the resultant keys / certificates, so put it in a place where you’ll always be able to find it.

certbot certonly --manual --config-dir ~/Code/csrDirectoryFromAbove --logs-dir ~/Code/csrDirectoryFromAbove --work-dir ~/Code/csrDirectoryFromAbove

Certbot will ask further questions. Remember that the domain (or subdomain) name must be specific and cannot have a wildcard.

If you want SSL traffic over and, you’ll need 2 separate certificates. Meaning get a CSR for each, run certbot for each, verify a webpage on each.

Hosting page to verify site

Certbot will ask you to serve a webpage on the domain you are registering so they can verify you own it. It’ll say something like:

Make sure your web server displays the following content at


To host the verification page on our App Engine project using Golang, it was a matter of adding this handler:

http.HandleFunc("/.well-known/acme-challenge/n6k7LN8uNZuafdasdfn6k7LN8uNZuafdasdf", sslCertHandler)

func sslCertHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprint(w, "> hhjqOMRVlY4.biK-npBDQpn1Vy")

After deploying the above to our server, I was able to verify the content appeared by accessing the URL in the browser before continuing the certbot workflow.

CSR signed

After verification, the signed public/private keys are stored in a subdirectory specified when executing certbot. Hooray!

Using the SSL certificates on App Engine

To configure App Engine to use the signed certs, you’ll need to convert your server’s private key generated in the first OpenSSL command to RSA format:

Convert signed private key to RSA

App Engine requires us to convert our private key to RSA format.

Note: You need to use the private key returned from LetsEncrypt located at: ~/Code/csrDirectoryFromAbove/live/

Perform the conversion with OpenSSL:

openssl rsa -in privkey.pem -out privkey_rsa.pem

Verify the signed private key matches the public certs

Verify the hashes match on the public/private keys (the “fullchain.pem” and “privkey_rsa.pem” files):

openssl rsa -noout -modulus -in privkey_rsa.pem | openssl md5
openssl x509 -noout -modulus -in fullchain.pem | openssl md5

Upload keys to your server

To use the SSL certs, you’ll need to upload them securely to your server. For App Engine, this is done here

The files to upload are:

Force traffic over SSL

It’s a good idea to encforce HSTS (HTTP Strict Transport Security).

For our App Engine configuration, we can force all traffic to be sent over SSL by adding the ‘secure’ flag to our app.yaml configuration:

- url: /.*
  script: _go_app
  secure: always

Renewal of certificates

Instructions for renewing Let’s Encrypt certificates using certbot are available here

Since certificates expire at 90 days, you’ll want to renew them prior to that, say at 60 days.

Final takeaways

Always remember:

Further instructions for using a custom domain and Let’s Encrypt can be found here

◀   GAE/Golang quickstart with Bootstrap templates Hosting a static site for free on Firebase   ▶