Mapping a custom domain to Cloud Functions Gen2 involves a few moving parts, but it’s essentially about telling Google Cloud how to route traffic from your domain to your serverless function.
Here’s a Cloud Function Gen2 deployed to us-central1 that simply returns a greeting:
from cloudevents.http import CloudEvent, from_http
from flask import Flask, jsonify
app = Flask(__name__)
@app.route('/', methods=['POST'])
def hello_world(event: CloudEvent):
data = event.data
name = data.get('name', 'World')
return jsonify({'message': f'Hello {name}!'})
When you deploy this, Cloud Functions Gen2 automatically creates a public URL for it. This URL is not what you want to use for your custom domain. Instead, you’ll be using a load balancer managed by Google Cloud.
The core mechanism is Google Cloud’s Serverless Network Endpoint Group (NEG). This special type of NEG doesn’t point to specific IP addresses; it points to a serverless service like Cloud Functions or Cloud Run. When you create a load balancer and configure it to use a Serverless NEG pointing to your function, the load balancer handles receiving traffic for your custom domain and then intelligently forwards it to the correct Cloud Function instance.
Here’s how you’d typically set this up:
-
Create a Serverless NEG: This is the bridge between the load balancer and your Cloud Function.
- Command:
gcloud compute network-endpoint-groups create my-function-neg \ --region=us-central1 \ --network-endpoint-type=SERVERLESS \ --cloud-run-service=my-function-name \ --project=your-gcp-project-id - Explanation: This command creates a Serverless NEG named
my-function-negin theus-central1region, specifically targeting the Cloud Run service (my-function-name) that underlies your Cloud Function Gen2.
- Command:
-
Create a Backend Service: This service defines how the load balancer interacts with the NEG.
- Command:
gcloud compute backend-services create my-function-backend-service \ --global \ --load-balancing-scheme=EXTERNAL_MANAGED \ --protocol=HTTP \ --timeout=30 \ --enable-cdn \ --project=your-gcp-project-id - Explanation: This creates a global backend service. The
--enable-cdnflag is useful for caching static responses if your function serves any. The--protocol=HTTPis often sufficient because the traffic between the load balancer and Cloud Functions is typically over HTTP, and SSL is terminated at the load balancer.
- Command:
-
Add the Serverless NEG to the Backend Service:
- Command:
gcloud compute backend-services add-backend my-function-backend-service \ --global \ --network-endpoint-group=my-function-neg \ --network-endpoint-group-region=us-central1 \ --project=your-gcp-project-id - Explanation: This links your
my-function-negto themy-function-backend-service.
- Command:
-
Create a URL Map: This directs incoming requests to the correct backend service.
- Command:
gcloud compute url-maps create my-function-url-map \ --default-service=my-function-backend-service \ --project=your-gcp-project-id - Explanation: This creates a URL map and sets your
my-function-backend-serviceas the default handler for all incoming requests. You could add more complex path-based routing here if needed.
- Command:
-
Create a Global Forwarding Rule: This is the public-facing IP address and port that your custom domain will point to.
- Command:
gcloud compute forwarding-rules create my-function-forwarding-rule \ --global \ --load-balancing-scheme=EXTERNAL_MANAGED \ --network-tier=PREMIUM \ --address=YOUR_STATIC_IP_ADDRESS \ --ports=443 \ --url-map=my-function-url-map \ --project=your-gcp-project-id - Explanation: This creates the ingress point. You’ll need to provision a static IP address (
YOUR_STATIC_IP_ADDRESS) first and then point your domain’s DNS A record to it. The--ports=443indicates it’s listening for HTTPS traffic.
- Command:
-
Configure SSL Certificate: For HTTPS, you need an SSL certificate. Google Cloud offers managed SSL certificates.
- Command:
gcloud compute ssl-certificates create my-ssl-cert \ --domains=your.custom.domain \ --global \ --project=your-gcp-project-id - Explanation: This creates a Google-managed SSL certificate for
your.custom.domain. Google will automatically provision and renew this certificate.
- Command:
-
Create a Target HTTPS Proxy: This uses the SSL certificate and the URL map.
-
Command:
gcloud compute target-https-proxies create my-https-proxy \ --ssl-certificates=my-ssl-cert \ --url-map=my-function-url-map \ --global \ --project=your-gcp-project-id -
Explanation: This proxy terminates SSL and then uses the URL map to route traffic. You’d then update your forwarding rule to use this proxy instead of directly pointing to the URL map if you want HTTPS.
-
Update Forwarding Rule for HTTPS:
gcloud compute forwarding-rules update my-function-forwarding-rule \ --global \ --target-https-proxy=my-https-proxy \ --project=your-gcp-project-id
-
-
Update DNS Records: Finally, go to your domain registrar and create an
Arecord pointingyour.custom.domainto the static IP address you reserved for the forwarding rule.
The most surprising true thing about this setup is that you’re actually configuring a Global External HTTP(S) Load Balancer, even though you’re not directly managing any VMs or traditional backends. The Serverless NEG abstracts away the complexities of the load balancer’s interaction with the serverless platform.
Once these steps are complete, traffic hitting https://your.custom.domain will be routed through the load balancer, which will then invoke your Cloud Function Gen2.
The next concept you’ll likely encounter is handling more complex routing scenarios, such as mapping different subdomains or URL paths to different serverless services, or implementing authentication and authorization at the load balancer level before traffic even reaches your function.