
Caddy your Serverless Functions
Use Caddy to bring your serverless functions under one "custom domain" roof, with automatic HTTPS.
Why host your own API gateway?
First a public service announcement:
Each of the major cloud providers have an API management service that works well with their functions-as-a-service product. You may prefer to use that instead of hosting your own server.
For my personal project I wanted to:
- bring together my cloud functions under a custom domain, rather than expose cloud function endpoints separately
- roll my own gateway on a Digital Ocean droplet, using Docker, Docker Compose and Caddy. I enjoy the engineering journey and flexibility this combination offers
- have automatic HTTPS support
- keep it simple since I'm hosting it myself
Configuring Caddy v2
Caddy is an open source web server that offers a streamlined configuration for automatic HTTPS (by handling the certificate renewal for you) and reverse proxying.
This configuration example shows how to hide https://us-central1-abc123.cloudfunctions.net/myCloudFunction
beyond a custom domain and expose the function at https://myfunction.mydomain.com/add
https://myfunction.mydomain.com {
tls myemail@gmail.com
handle_path /add* {
rewrite * /myCloudFunction{uri}
reverse_proxy {
header_up Host "us-central1-abc123.cloudfunctions.net"
to https://us-central1-abc123.cloudfunctions.net
}
}
log {
output file /logs/myfunction.mydomain.com.log
}
}
Here are the highlights:
tls
configures automatic HTTPS forhttps://myfunction.mydomain.com
handle_path
handles the "/add" route and then rewrites the url by stripping the incoming "/add" and thenrewrite
add the cloud function namereverse-proxy
forwards the request to the newly formed URL and returns the results- the
Host
header is required so the cloud provider (Google Cloud in this case) knows where to find the function. It avoids "The requested URL /myCloudFunction/ was not found on this server" error.
If you're currently using an older version of Caddy (v1)
Caddy v2 was released in May 2020 and I recently went through the exercise of upgrading my Caddy v1 configuration and ran into a couple of challenges:
There weren't easy-to-find examples for the scenario I was interested in, so after playing for awhile I reached out to the Caddy team to help me convert the one-line
proxy
directive in v1 to a combination ofreverse-proxy
,handle_path
andrewrite
in v2.That got me closer, though Google Cloud was still returning a 404 for
myCloudFunction
. After researching SNI and hints around the internet, the key was addingheader_up Host "us-central1-abc123.cloudfunctions.net"
to avoid "The requested URL /myCloudFunction/ was not found on this server" error.
For reference, here was my original configuration from Caddy v1's:
https://myfunction.mydomain.com {
tls myemail@gmail.com
proxy /add https://us-central1-abc123.cloudfunctions.net/myCloudFunction
errors /log/myfunction.mydomain.com.errors.log
log / /log/myfunction.mydomain.com.log "{combined}" {
rotate_size 100
rotate_keep 10
}
}
Wrapping up
As an engineer, hosting your own server with open source technology is a great way to stay sharp and learn about what's happening behind-the-scenes.