diff --git a/src/content/docs/workers-vpc/configuration/vpc-services.mdx b/src/content/docs/workers-vpc/configuration/vpc-services/index.mdx similarity index 93% rename from src/content/docs/workers-vpc/configuration/vpc-services.mdx rename to src/content/docs/workers-vpc/configuration/vpc-services/index.mdx index 0d5e7cca73df2d9..8633fee384d1461 100644 --- a/src/content/docs/workers-vpc/configuration/vpc-services.mdx +++ b/src/content/docs/workers-vpc/configuration/vpc-services/index.mdx @@ -5,14 +5,7 @@ sidebar: order: 1 --- -import { - GlossaryTooltip, - Tabs, - TabItem, - Example, - Render, - WranglerConfig, -} from "~/components"; +import { Render, WranglerConfig } from "~/components"; VPC Services are the core building block of Workers VPC. They represent specific resources in your private network that Workers can access through Cloudflare Tunnel. @@ -36,7 +29,7 @@ A VPC Service consists of: - **Tunnel ID**: The Cloudflare Tunnel that provides network connectivity - **Hostname or IPv4/IPv6 addresses**: The hostname, or IPv4 and/or IPv6 addresses to use to route to your service from the tunnel in your private network - **Ports**: HTTP and/or HTTPS port configuration (optional, defaults to 80/443) -- **Resolver IPs**: Optionally, a specific resolver IP can be provided -- when not provided, `cloudflared` will direct DNS traffic to the currently configured default system resolver. +- **Resolver IPs**: Optionally, a specific resolver IP can be provided — when not provided, `cloudflared` will direct DNS traffic to the currently configured default system resolver. Requests are encrypted in flight until they reach your network via a tunnel, regardless of the scheme used in the URL provided to `fetch`. If the `http` scheme is used, a plaintext connection is established to the service from the tunnel. @@ -69,7 +62,7 @@ If your origin service presents a certificate that is not issued by a publicly t The following is an example of a VPC Service for a service using custom HTTP and HTTPS ports, and both IPv4 and IPv6 addresses. These configurations represent the expected contract of the [REST API for creating a VPC Service](/api/resources/connectivity/subresources/directory/subresources/services/), a type of service within the broader connectivity directory. -```json +```jsonc { "type": "http", "name": "human-readable-name", @@ -83,15 +76,15 @@ The following is an example of a VPC Service for a service using custom HTTP and "ipv4": "10.0.0.1", "ipv6": "fe80::", "network": { - "tunnel_id": "0191dce4-9ab4-7fce-b660-8e5dec5172da" - } - } + "tunnel_id": "0191dce4-9ab4-7fce-b660-8e5dec5172da", + }, + }, } ``` The following is an example of a VPC Service for a service using custom HTTP and HTTPS ports as well, using a hostname. Note that since we are using a hostname, we must provide our service with a `resolver_network` that optionally has `resolver_ips`. -```json +```jsonc { "type": "http", "name": "human-readable-name", @@ -105,9 +98,9 @@ The following is an example of a VPC Service for a service using custom HTTP and "hostname": "example.com", "resolver_network": { "tunnel_id": "0191dce4-9ab4-7fce-b660-8e5dec5172da", - "resolver_ips": ["10.0.0.1"] // Optional - } - } + "resolver_ips": ["10.0.0.1"], // Optional + }, + }, } ``` @@ -165,6 +158,7 @@ You can have multiple VPC service bindings: ## Next steps +- [Configure VPC Services with Terraform](/workers-vpc/configuration/vpc-services/terraform/) for managing VPC Services as infrastructure - Set up [Cloudflare Tunnel](/workers-vpc/configuration/tunnel/) for your environment - Learn about the [Service Binding API](/workers-vpc/api/) - Refer to [examples](/workers-vpc/examples/) of common use cases diff --git a/src/content/docs/workers-vpc/configuration/vpc-services/terraform.mdx b/src/content/docs/workers-vpc/configuration/vpc-services/terraform.mdx new file mode 100644 index 000000000000000..e99014102681962 --- /dev/null +++ b/src/content/docs/workers-vpc/configuration/vpc-services/terraform.mdx @@ -0,0 +1,195 @@ +--- +title: Configure with Terraform +pcx_content_type: how-to +description: Learn how to manage VPC Services using the Cloudflare Terraform provider. +sidebar: + order: 2 +--- + +VPC Services can be managed as infrastructure using the [`cloudflare_connectivity_directory_service`](https://registry.terraform.io/providers/cloudflare/cloudflare/latest/docs/resources/connectivity_directory_service) resource in the [Cloudflare Terraform provider](/terraform/). + +This maps directly to the [connectivity directory](/api/resources/connectivity/subresources/directory/subresources/services/) — the underlying API that the dashboard and Wrangler CLI also use to create and manage VPC Services. The same [VPC Service configuration fields](/workers-vpc/configuration/vpc-services/#vpc-service-configuration) (type, host, ports, tunnel ID) apply regardless of how the service is created. + +:::note +Requires Cloudflare Terraform provider v5.13.0 or later. +::: + +## VPC Service resource + +The `cloudflare_connectivity_directory_service` resource creates a VPC Service in the connectivity directory. Each resource corresponds to one VPC Service entry that a Worker can bind to. + +### Hostname-based configuration + +When using a hostname, provide `host.hostname` with a `resolver_network` block. This parallels the hostname-based [JSON configuration example](/workers-vpc/configuration/vpc-services/#configuration-example). + +```tf +resource "cloudflare_connectivity_directory_service" "my_private_api" { + account_id = var.account_id + name = "my-private-api" + type = "http" + http_port = 80 + https_port = 443 + + host = { + hostname = "internal-api.example.com" + resolver_network = { + tunnel_id = var.tunnel_id + } + } +} +``` + +To use a custom DNS resolver within your private network, add `resolver_ips`: + +```tf +resource "cloudflare_connectivity_directory_service" "my_private_api" { + account_id = var.account_id + name = "my-private-api" + type = "http" + + host = { + hostname = "internal-api.example.com" + resolver_network = { + tunnel_id = var.tunnel_id + resolver_ips = ["10.0.0.53"] + } + } +} +``` + +### IP-based configuration + +When using IP addresses, provide `host.ipv4` and/or `host.ipv6` with a `network` block. This parallels the IP-based [JSON configuration example](/workers-vpc/configuration/vpc-services/#configuration-example). + +```tf +resource "cloudflare_connectivity_directory_service" "my_private_api" { + account_id = var.account_id + name = "my-private-api" + type = "http" + http_port = 8080 + https_port = 8443 + + host = { + ipv4 = "10.0.1.50" + ipv6 = "fe80::1" + network = { + tunnel_id = var.tunnel_id + } + } +} +``` + +### Port configuration + +Ports are optional and default to 80 (HTTP) and 443 (HTTPS). To enforce a single scheme, provide only one of `http_port` or `https_port`. Refer to [VPC Service configuration](/workers-vpc/configuration/vpc-services/#vpc-service-configuration) for how scheme enforcement and port behavior work. + +## Workers binding configuration + +Once a VPC Service exists, bind it to a Worker using the `vpc_service` binding type in the `bindings` array of a `cloudflare_worker_version` resource. This is equivalent to the [`vpc_services` array in Wrangler configuration](/workers-vpc/configuration/vpc-services/#workers-binding-configuration). + +```tf +resource "cloudflare_worker_version" "my_worker_version" { + account_id = var.account_id + worker_id = cloudflare_worker.my_worker.id + compatibility_date = "2025-02-21" # Set this to today's date + main_module = "worker.js" + + modules = [{ + name = "worker.js" + content_type = "application/javascript+module" + content_file = "build/worker.js" + }] + + bindings = [{ + type = "vpc_service" + name = "PRIVATE_API" + service_id = cloudflare_connectivity_directory_service.my_private_api.service_id + }] +} +``` + +Multiple VPC Service bindings can be added to the same Worker: + +```tf +bindings = [ + { + type = "vpc_service" + name = "PRIVATE_API" + service_id = cloudflare_connectivity_directory_service.api.service_id + }, + { + type = "vpc_service" + name = "PRIVATE_DATABASE" + service_id = cloudflare_connectivity_directory_service.database.service_id + } +] +``` + +The Worker code accesses each binding through `env.PRIVATE_API.fetch()` and `env.PRIVATE_DATABASE.fetch()`, as described in the [Workers Binding API](/workers-vpc/api/). + +For more details on managing Workers and bindings with Terraform, refer to [Workers Infrastructure as Code](/workers/platform/infrastructure-as-code/). + +## Data sources + +The Terraform provider includes data sources for reading existing VPC Services without managing their lifecycle. + +### Look up a single VPC Service + +```tf +data "cloudflare_connectivity_directory_service" "existing" { + account_id = var.account_id + service_id = "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e" +} +``` + +This is useful for binding to a VPC Service that is managed outside of your Terraform configuration (for example, created through the dashboard or Wrangler CLI). + +### List VPC Services + +```tf +data "cloudflare_connectivity_directory_services" "all_http" { + account_id = var.account_id + type = "http" +} +``` + +## Resource schema reference + +```tf +resource "cloudflare_connectivity_directory_service" "example" { + # Required + account_id = "your-account-id" # Account identifier + name = "my-private-api" # Human-readable name + type = "http" # Service type (only "http" supported) + + # Optional + http_port = 80 # HTTP port (default: 80) + https_port = 443 # HTTPS port (default: 443) + + host = { + # Use hostname OR ipv4/ipv6, not both + + # Option A: Hostname-based + hostname = "internal-api.example.com" + resolver_network = { + tunnel_id = "tunnel-uuid" # Required — Cloudflare Tunnel ID + resolver_ips = ["10.0.0.53"] # Optional — custom DNS resolver IPs + } + + # Option B: IP-based + # ipv4 = "10.0.1.50" # IPv4 address + # ipv6 = "fe80::1" # IPv6 address + # network = { + # tunnel_id = "tunnel-uuid" # Required — Cloudflare Tunnel ID + # } + } + + # Read-only (computed by the API) + # id — Terraform resource ID + # service_id — VPC Service ID (use this for Worker bindings) + # created_at — Creation timestamp + # updated_at — Last update timestamp +} +``` + +For the full schema, refer to the [Terraform registry documentation](https://registry.terraform.io/providers/cloudflare/cloudflare/latest/docs/resources/connectivity_directory_service). diff --git a/src/content/docs/workers/platform/infrastructure-as-code.mdx b/src/content/docs/workers/platform/infrastructure-as-code.mdx index d840ecc2d57ac6a..c90f100b9e4077e 100644 --- a/src/content/docs/workers/platform/infrastructure-as-code.mdx +++ b/src/content/docs/workers/platform/infrastructure-as-code.mdx @@ -30,7 +30,7 @@ When using Wrangler for building and a different method for uploading, make sure ## Terraform -In this example, you need a local file named `my-script.mjs` with script content similar to the below examples. Learn more about the Cloudflare Terraform Provider [here](/terraform), and see an example with all the Workers script resource settings [here](https://github.com/cloudflare/terraform-provider-cloudflare/blob/main/examples/resources/cloudflare_workers_script/resource.tf). +In this example, you need a local file named `my-script.mjs` with script content similar to the below examples. Learn more about the [Cloudflare Terraform Provider](/terraform/), and refer to the [Workers script resource example](https://github.com/cloudflare/terraform-provider-cloudflare/blob/main/examples/resources/cloudflare_workers_script/resource.tf) for all available resource settings. ```tf variable "account_id" { @@ -48,7 +48,7 @@ resource "cloudflare_worker" "my_worker" { resource "cloudflare_worker_version" "my_worker_version" { account_id = var.account_id worker_id = cloudflare_worker.my_worker.id - compatibility_date = "$today" + compatibility_date = "2025-02-21" # Set this to today's date main_module = "my-script.mjs" modules = [ { @@ -71,7 +71,7 @@ resource "cloudflare_workers_deployment" "my_worker_deployment" { } ``` -Notice how you don't have to manage all of these resources in Terraform. For example, you could just the `cloudflare_worker` resource and seamlessly use Wrangler or your own deployment tools for Versions or Deployments. +Notice how you do not have to manage all of these resources in Terraform. For example, you could use just the `cloudflare_worker` resource and seamlessly use Wrangler or your own deployment tools for Versions or Deployments. ## Bindings in Terraform @@ -245,6 +245,26 @@ bindings = [{ - `name`: The binding name to access via `env.HYPERDRIVE` - `id`: The ID of your Hyperdrive configuration +### VPC Service Binding + +Bind to a [VPC Service](/workers-vpc/configuration/vpc-services/) for accessing resources in your private network: + +```tf +bindings = [{ + type = "vpc_service" + name = "PRIVATE_API" + service_id = "your-vpc-service-id" +}] +``` + +**Properties:** + +- `type`: `"vpc_service"` +- `name`: The binding name to access via `env.PRIVATE_API` +- `service_id`: The ID of your VPC Service (from `cloudflare_connectivity_directory_service` or the dashboard) + +You can create the VPC Service with Terraform using the `cloudflare_connectivity_directory_service` resource. For a full walkthrough, refer to [Configure VPC Services with Terraform](/workers-vpc/configuration/vpc-services/terraform/). + ### Analytics Engine Binding Bind to an [Analytics Engine](/analytics/analytics-engine/) dataset: @@ -346,6 +366,11 @@ resource "cloudflare_worker_version" "my_worker_version" { type = "secret_text" name = "API_KEY" text = var.api_key + }, + { + type = "vpc_service" + name = "PRIVATE_API" + service_id = var.vpc_service_id } ] }