Manually Deploy Express.js App to Google App Engine with Let's Encrypt Cert

I didn't find a guide that brought this all together on the web, so here it is. We are going to be adding a module to our app that will be returning the correct text for the Let's Encrypt validation, using express middleware to direct the route correctly, and having a lot of fun! It is assumed that you have already set up your custom domains and DNS inside of Google App Engine, and that won't be covered here (but is totally necessary for this to work). If you can't get to your app by the domain you are requesting a cert for, go fix that first.

First, lets clone the letsencrypt utilities to our computer (you do have git, don't you?)

git clone

Then we'll run letsencrypt with the manual procedure

./letsencrypt/letsencrypt-auto certonly --manual

Enter in the domain(s) you want to encrypt and continue. These must ALL be set up with custom domain configuration for your Google app, and have DNS pointing to the correct places.

You should see this output for each domain you entered:

Create a file containing just this data:
And make it available on your web server at this URL:

Don't continue yet! We are going to go add the new middleware to the app and deploy it before we continue.

Inside your project, create a letsEncrypt.js file with the following lines of code. The example has two domains (for a root and www), but you may need more/less. The Paths and Data should come from the letsencrypt output. From the example output above, letsEncryptPath would be 'mVGn8u8ig4lhC2vAw1Zdewe56Tp_8DPl4WAfuzgi5uY' and letsEncryptData would be 'mVGn8u8ig4lhC2vAw1Zdewe56Tp_8DPl4WAfuzgi5uY.LToI9ULE3ZWt45hja0mmptp7V5-4nBbh847mSuHamJs'.

//import express and express router
var express = require('express');
var router = require('express').Router();

//set constants for encryption from letsencrypt command
const letsEncryptPath = 'your-path-here';
const letsEncryptData = 'your-data-here';
const wwwletsEncryptPath = 'your-wwwpath-here';
const wwwletsEncryptData = 'your-wwwdata-here';

//make router path for letsencrypt
router.get(`/${letsEncryptPath}`, (req, res) => {

//make router path for www pathed site
router.get(`/${wwwletsEncryptPath}`, (req, res) => {

//export express routes
module.exports = router;

Great! Now we will just require the module in our entry point app, and add it as middleware. NOTE: Where you put the middleware (app.use) line is relevant, I'm trusting you to place it appropriately.

//import letsencrypt
const letsEncrypt = require('./config/letsEncrypt.js');

//middleware for letsencrypt
app.use('/.well-known/acme-challenge', letsEncrypt);

Now redeploy your app with 'gcloud app deploy'. Once the deployment is done, browse to the URLs specified in the letsencrypt window and make sure they are handing the data out. Once you have verified the data is being returned correctly, you can hit Enter to continue the letsencrypt process.

Now we need to remake the private key as an RSA key

sudo openssl rsa -in /etc/letsencrypt/live/${DOMAIN}/privkey.pem -out private_rsa.key

Now we just need to paste the information into the appropriate fields in the Google console settings window for Google App Engine! For the 'Public Key Certificate' information box, paste the CERTIFICATE section returned from:

sudo cat /etc/letsencrypt/live/${DOMAIN}/cert.pem

For the 'RSA Private Key' information, we'll read our newly made rsa private key file

sudo cat ./private_rsa.key

Finish adding the certificate, then go into the console and check the boxes for all the relevant domains under "Enable SSL for the following custom domains" when in the certificate editing page.

Huzzah! You should now be able to access your application over https. I would definitely recommend automating this, but will work for testing purposes etc.

UPDATE: To take your first step in automating this process, as well as make site authentication possible without having to redeploy your app every time, check out my followup post: