Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,7 @@
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.

Expand All @@ -32,11 +25,11 @@

A VPC Service consists of:

- **Type**: Currently only `http` is supported (support for `tcp` coming soon)

Check warning on line 28 in src/content/docs/workers-vpc/configuration/vpc-services/index.mdx

View workflow job for this annotation

GitHub Actions / Semgrep

semgrep.style-guide-coming-soon

Found forbidden string 'coming soon'. Too often we set expectations unfairly by attaching this phrase to a feature that may not actually arrive soon. (add [skip style guide checks] to commit message to skip)
- **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.

Expand Down Expand Up @@ -69,7 +62,7 @@

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",
Expand All @@ -83,15 +76,15 @@
"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",
Expand All @@ -105,9 +98,9 @@
"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
},
},
}
```

Expand Down Expand Up @@ -165,6 +158,7 @@

## 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
Original file line number Diff line number Diff line change
@@ -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.
:::
Comment thread
Oxyjun marked this conversation as resolved.

## 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).
31 changes: 28 additions & 3 deletions src/content/docs/workers/platform/infrastructure-as-code.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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" {
Expand All @@ -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
Comment thread
thomasgauvin marked this conversation as resolved.
main_module = "my-script.mjs"
modules = [
{
Expand All @@ -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

Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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
}
]
}
Expand Down
Loading