Custom Domains for AWS Lambda/API Gateway using Letsencrypt

AWS Lambda lets you run code without provisioning or managing servers. You pay only for the compute time you consume - there is no charge when your code is not running.

In general Lambda is well designed and the platform is pretty developer friendly, especially if you use a framework like serverless or apex. However as someone who creates new services on Lambda all the time, there is one thing that consistently annoys me.

Configuring a custom domain for use with Lambda is stupidly complex for such a common feature.

Here’s the AWS documentation to use a custom domain with API Gateway. Take a look, I’ll wait.

At first glance the instructions seem somewhat reasonable. For security reasons API Gateway requires SSL for all requests, which means that to use a custom domain, you first need an SSL certificate.

Unfortunately this becomes a problem when you realize that Letsencrypt HTTP-01 doesn’t work because of the catch-22 requiring you to prove that you own the custom domain before generating certificates. Even worse, AWS’s built-in free certificate service (Certificate Manger) doesn’t yet support API Gateway.

So what’s the solution?


I was able to create a nice little script using python which invokes the aws-cli, dehydrated letsencrypt client & lexicon and does all the steps necessary to add a custom domain to an API Gateway, automatically.

Here’s what it does:

  • validates that all the correct credentials & environmental variables are set
  • validates that the specified AWS API Gateway exists
  • generate a new set of letsencrypt certificates for the specified custom domain using the DNS-01 challenge & lexicon
  • register custom domain name with AWS (which creates a distribution domain name on cloudfront)
  • adds a CNAME dns record mapping your custom domain to the AWS distribution domain
  • maps the custom domain to your selected API Gateway

The code is all open source and lives here: Analogj/aws-api-gateway-letsencrypt

I’ve also created a simple Docker image which you can use if you don’t want to install anything:

docker run \
-e LEXICON_CLOUDFLARE_USERNAME=*** \
-e LEXICON_CLOUDFLARE_TOKEN=*** \
-e AWS_ACCESS_KEY_ID=*** \
-e AWS_SECRET_ACCESS_KEY=*** \
-e DOMAIN=api.quietthyme.com \
-e API_GATEWAY_NAME=dev-quietthyme-api \
-v `pwd`/certs:/srv/certs \
analogj/aws-api-gateway-letsencrypt

Jason Kulatunga

Devops & Infrastructure guy @Gusto (ex-Adobe). I write about, and play with, all sorts of new tech. All opinions are my own.

San Francisco, CA blog.thesparktree.com

Subscribe to Sparktree

Get the latest posts delivered right to your inbox.

or subscribe via RSS with Feedly!