How to setup custom domain for your Google cloud functions
Software systems builder
There's a way to have your own domain to serve your Google Cloud functions.
This post is mainly a reminder to myself. I recently created a SaaS that I wanted to deploy to Google Cloud Platform to use its cloud functions and datastore services.
I wanted to have URL like this for my functions:
https://app.mydomain.com/api/v1/FunctionName
The application's frontend uses Firebase as the deployment target. I'm only using the hosting part of Firebase. The marketing website and the single-page app use Firebase's custom domain and CDN hosting.
The domain name is already setup on both Firebase hosting targets.
The backend API is written in Go and uses GCP cloud functions. The issue is I wanted to have the custom domain and URL above for my functions and not use the default one.
If you search for how to use custom domain for Google cloud functions, you'll see articles showing that you can use Firebase's configuration to rewrites the path to your functions.
What they are not saying is that to work, you have to
deploy the functions in the us-central1 region since Firebase is deployed
there. I was deploying to other regions and was not understanding why I could
not reach my functions from Firebase rewrites. They have to be in us-central1
.
Here's my Firebase config file:
{
"hosting": [
{
"target": "web",
"public": "site/public",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
]
},
{
"target": "app",
"public": "app",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**",
"**/*.ts",
"package*.json",
"tsconfig.json"
],
"rewrites": [
{
"source": "/api/v1/dosomething",
"function": "DoSomething"
}
]
}
]
}
For all my functions I have a rewrtes
block indicating the URL I want to
rewrite to which function. The key point here is that my functions are not
Node Firebase functions. They are Google cloud functions deployed in my GCP
project. Turns out I prefer writting them in Go ;).
You can see that I have my marketing site in the site/public
directory. This
is a static site generated by Hugo. The other target named app
is the
single-page application and is an Elm application.
I wanted a mono repository for this project. The marketing site, the single-page application, and the backend functions are all in the same GitHub repository.
Here's the structure of the directories:
{% include push-content.html %}
.
├── app
│ ├── css
│ ├── img
│ └── js
├── functions
├── site
│ ├── archetypes
│ ├── content
│ ├── data
│ ├── layouts
│ ├── public
│ ├── resources
│ ├── static
│ ├── tailwind
│ └── themes
└── src
├── Api
└── Page
The app
directory is the single-page application. The elm make
output bundle
in the js
directory of app
.
The functions
directory is where all my Go functions are. This is a standard
Go package that exposes the functions. For instance:
package functions
import (
"fmt"
"net/http"
)
func DoSomething(w http.ResponseWriter, r *http.Request) {
fmt.Println("this is the functions")
}
The site
directory is the Hugo static site.
The src
directory is the Elm source files.
Using make to deploy functions
The quickest way I found to deploy functions when they change was by using make. I've been using make more and more for the past 2 years. It's very good and you wonder why so many rebuilt build tool instead of using that.
Here's an example of a deploy code for a specific function.
dosomething-deploy:
cd functions; \
gcloud functions deploy DoSomething --allow-unauthenticated --region=us-central1 \
--env-vars-file .env.yaml --runtime go111 --trigger-http --memory=128MB
I copy-paste this target for all of my functions. If you're deploying
Go function setting the memory to 128MB
will save you some amount of money.
I'm also passing an .env.yaml
file to all my functions with shared environment
variables.
The most important parameter is the --region=us-central
making the function
available in the rewrite
section of the Firebase configuration.
That way your functions use the custom domain you set on your Firebase target
and the rewrites
section makes sure the function gets called via the custom
route you specified.
Is the Makefile approach scales?
I would dare say yes, unless you have more than 150 functions. Once you create
a good naming convention in your Makefile
it become intuitive to type:
shell`
$> make dosome+TAB
And you get auto-complete for the function you want to deploy.
I know there's tools out there that help or handle the deployment. I prefer having
control over what I'm doing and understand what's going on. Especially when
make
is such a proven and powerful tool.
As always YMMV, the point of this post was to clearly indicates that you have
to deploy your functions to us-central1
to have them available in your Firebase
rewrites
section.