Automate Cloud CDN setup with Terraform

Use the following examples to deploy sample backends with Cloud CDN enabled.

If you are new to using Terraform for Google Cloud, see Get started with Terraform.

Using a Cloud Storage bucket

The following sample configures Cloud CDN with a public Cloud Storage bucket. The sample also includes load balancing and caching configurations. The configurations can be modified, as required.

For details about each section of the sample, see Set up a backend bucket.

# Cloud Storage bucket resource "random_id" "bucket_prefix" { byte_length = 8 } resource "google_storage_bucket" "default" { name = "${random_id.bucket_prefix.hex}-my-bucket" location = "us-east1" uniform_bucket_level_access = true storage_class = "STANDARD" // delete bucket and contents on destroy. force_destroy = true // Assign specialty files website { main_page_suffix = "index.html" not_found_page = "404.html" } } # make bucket public resource "google_storage_bucket_iam_member" "default" { bucket = google_storage_bucket.default.name role = "roles/storage.objectViewer" member = "allUsers" } resource "google_storage_bucket_object" "index_page" { name = "index-page" bucket = google_storage_bucket.default.name content = <<-EOT <html><body> <h1>Congratulations on setting up Google Cloud CDN with Storage backend!</h1> </body></html> EOT } resource "google_storage_bucket_object" "error_page" { name = "404-page" bucket = google_storage_bucket.default.name content = <<-EOT <html><body> <h1>404 Error: Object you are looking for is no longer available!</h1> </body></html> EOT } # image object for testing, try to access http://<your_lb_ip_address>/test.jpg resource "google_storage_bucket_object" "test_image" { name = "test-object" # Uncomment and add valid path to an object. # source = "/path/to/an/object" # content_type = "image/jpeg" # Delete after uncommenting above source and content_type attributes content = "Data as string to be uploaded" content_type = "text/plain" bucket = google_storage_bucket.default.name } # reserve IP address resource "google_compute_global_address" "default" { name = "example-ip" } # forwarding rule resource "google_compute_global_forwarding_rule" "default" { name = "http-lb-forwarding-rule" ip_protocol = "TCP" load_balancing_scheme = "EXTERNAL" port_range = "80" target = google_compute_target_http_proxy.default.id ip_address = google_compute_global_address.default.id } # http proxy resource "google_compute_target_http_proxy" "default" { name = "http-lb-proxy" url_map = google_compute_url_map.default.id } # url map resource "google_compute_url_map" "default" { name = "http-lb" default_service = google_compute_backend_bucket.default.id } # backend bucket with CDN policy with default ttl settings resource "google_compute_backend_bucket" "default" { name = "cat-backend-bucket" description = "Contains beautiful images" bucket_name = google_storage_bucket.default.name enable_cdn = true cdn_policy { cache_mode = "CACHE_ALL_STATIC" client_ttl = 3600 default_ttl = 3600 max_ttl = 86400 negative_caching = true serve_while_stale = 86400 } }

Using MIG and custom headers

You can use Terraform resources to bring up an external HTTP load balancer with a Cloud CDN backend service and custom request and response headers.

For information about the load balancer setup, see the primary setup guide.

# VPC resource "google_compute_network" "default" { name = "l7-xlb-network" provider = google-beta auto_create_subnetworks = false } # backend subnet resource "google_compute_subnetwork" "default" { name = "l7-xlb-subnet" provider = google-beta ip_cidr_range = "10.0.1.0/24" region = "us-central1" network = google_compute_network.default.id } # reserved IP address resource "google_compute_global_address" "default" { provider = google-beta name = "l7-xlb-static-ip" } # forwarding rule resource "google_compute_global_forwarding_rule" "default" { name = "l7-xlb-forwarding-rule" provider = google-beta ip_protocol = "TCP" load_balancing_scheme = "EXTERNAL" port_range = "80" target = google_compute_target_http_proxy.default.id ip_address = google_compute_global_address.default.id } # http proxy resource "google_compute_target_http_proxy" "default" { name = "l7-xlb-target-http-proxy" provider = google-beta url_map = google_compute_url_map.default.id } # url map resource "google_compute_url_map" "default" { name = "l7-xlb-url-map" provider = google-beta default_service = google_compute_backend_service.default.id } # backend service with custom request and response headers resource "google_compute_backend_service" "default" { name = "l7-xlb-backend-service" provider = google-beta protocol = "HTTP" port_name = "my-port" load_balancing_scheme = "EXTERNAL" timeout_sec = 10 enable_cdn = true custom_request_headers = ["X-Client-Geo-Location: {client_region_subdivision}, {client_city}"] custom_response_headers = ["X-Cache-Hit: {cdn_cache_status}"] health_checks = [google_compute_health_check.default.id] backend { group = google_compute_instance_group_manager.default.instance_group balancing_mode = "UTILIZATION" capacity_scaler = 1.0 } } # instance template resource "google_compute_instance_template" "default" { name = "l7-xlb-mig-template" provider = google-beta machine_type = "e2-small" tags = ["allow-health-check"] network_interface { network = google_compute_network.default.id subnetwork = google_compute_subnetwork.default.id access_config { # add external ip to fetch packages } } disk { source_image = "debian-cloud/debian-12" auto_delete = true boot = true } # install nginx and serve a simple web page metadata = { startup-script = <<-EOF1 #! /bin/bash set -euo pipefail export DEBIAN_FRONTEND=noninteractive apt-get update apt-get install -y nginx-light jq NAME=$(curl -H "Metadata-Flavor: Google" "http://metadata.google.internal/computeMetadata/v1/instance/hostname") IP=$(curl -H "Metadata-Flavor: Google" "http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/ip") METADATA=$(curl -f -H "Metadata-Flavor: Google" "http://metadata.google.internal/computeMetadata/v1/instance/attributes/?recursive=True" | jq 'del(.["startup-script"])') cat <<EOF > /var/www/html/index.html <pre> Name: $NAME IP: $IP Metadata: $METADATA </pre> EOF EOF1 } lifecycle { create_before_destroy = true } } # health check resource "google_compute_health_check" "default" { name = "l7-xlb-hc" provider = google-beta http_health_check { port_specification = "USE_SERVING_PORT" } } # MIG resource "google_compute_instance_group_manager" "default" { name = "l7-xlb-mig1" provider = google-beta zone = "us-central1-c" named_port { name = "http" port = 8080 } version { instance_template = google_compute_instance_template.default.id name = "primary" } base_instance_name = "vm" target_size = 2 } # allow access from health check ranges resource "google_compute_firewall" "default" { name = "l7-xlb-fw-allow-hc" provider = google-beta direction = "INGRESS" network = google_compute_network.default.id source_ranges = ["130.211.0.0/22", "35.191.0.0/16"] allow { protocol = "tcp" } target_tags = ["allow-health-check"] }