---
description: Learn how to manage VPC Services using the Cloudflare Terraform provider.
title: Configure with Terraform
image: https://developers.cloudflare.com/og-docs.png
---

[Skip to content](#main-content)

> Documentation Index  
> Fetch the complete documentation index at: https://developers.cloudflare.com/workers-vpc/llms.txt  
> Use this file to discover all available pages before exploring further.

# Configure with Terraform

Last updated Aug 24, 2026|Copy as Markdown|[View as Markdown](https://docs-durable-objects-instance-replaced-errors.previews.developers.cloudflare.com/workers-vpc/configuration/vpc-services/terraform/index.md)|[Agent setup](https://docs-durable-objects-instance-replaced-errors.previews.developers.cloudflare.com/agent-setup/)

VPC Services can be managed as infrastructure using the [cloudflare\_connectivity\_directory\_service ↗](https://registry.terraform.io/providers/cloudflare/cloudflare/latest/docs/resources/connectivity%5Fdirectory%5Fservice) resource in the [Cloudflare Terraform provider](https://docs-durable-objects-instance-replaced-errors.previews.developers.cloudflare.com/terraform/).

This maps directly to the [connectivity directory](https://docs-durable-objects-instance-replaced-errors.previews.developers.cloudflare.com/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](https://docs-durable-objects-instance-replaced-errors.previews.developers.cloudflare.com/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](https://docs-durable-objects-instance-replaced-errors.previews.developers.cloudflare.com/workers-vpc/configuration/vpc-services/#configuration-examples).

```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](https://docs-durable-objects-instance-replaced-errors.previews.developers.cloudflare.com/workers-vpc/configuration/vpc-services/#configuration-examples).

```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
    }
  }
}
```

### TCP service configuration

For TCP services (for example, databases), set `type = "tcp"` and provide a `tcp_port`. You can optionally specify an `app_protocol` of `postgresql` or `mysql`.

```tf
resource "cloudflare_connectivity_directory_service" "my_database" {
  account_id   = var.account_id
  name         = "my-postgres-db"
  type         = "tcp"
  tcp_port     = 5432
  app_protocol = "postgresql"

  host = {
    ipv4 = "10.0.0.5"
    network = {
      tunnel_id = var.tunnel_id
    }
  }
}
```

### TLS certificate verification

To configure the TLS certificate verification mode for the connection to the origin, add a `tls_settings` block:

```tf
resource "cloudflare_connectivity_directory_service" "my_database" {
  account_id   = var.account_id
  name         = "my-postgres-db"
  type         = "tcp"
  tcp_port     = 5432
  app_protocol = "postgresql"

  host = {
    ipv4 = "10.0.0.5"
    network = {
      tunnel_id = var.tunnel_id
    }
  }

  tls_settings = {
    cert_verification_mode = "verify_ca"
  }
}
```

Valid values for `cert_verification_mode` are:

* `verify_full` (default)
* `verify_ca`
* `disabled`

Refer to [TLS certificate verification mode](https://docs-durable-objects-instance-replaced-errors.previews.developers.cloudflare.com/workers-vpc/configuration/vpc-services/#tls-certificate-verification-mode) for details.

### Port configuration

For HTTP services, 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](https://docs-durable-objects-instance-replaced-errors.previews.developers.cloudflare.com/workers-vpc/configuration/vpc-services/#vpc-service-configuration) for how scheme enforcement and port behavior work.

For TCP services, `tcp_port` is required.

## 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](https://docs-durable-objects-instance-replaced-errors.previews.developers.cloudflare.com/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](https://docs-durable-objects-instance-replaced-errors.previews.developers.cloudflare.com/workers-vpc/api/).

For more details on managing Workers and bindings with Terraform, refer to [Workers Infrastructure as Code](https://docs-durable-objects-instance-replaced-errors.previews.developers.cloudflare.com/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"
}

data "cloudflare_connectivity_directory_services" "all_tcp" {
  account_id = var.account_id
  type       = "tcp"
}
```

## 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: "http" or "tcp"

  # HTTP-specific (optional, defaults to 80/443)
  http_port  = 80                       # HTTP port
  https_port = 443                      # HTTPS port

  # TCP-specific (tcp_port is required when type = "tcp")
  # tcp_port     = 5432                 # TCP port
  # app_protocol = "postgresql"         # Optional: "postgresql" or "mysql"

  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
    # }
  }

  # Optional TLS settings
  # tls_settings = {
  #   cert_verification_mode = "verify_full"  # "verify_full", "verify_ca", or "disabled"
  # }

  # 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%5Fdirectory%5Fservice).

Was this helpful?

YesNo

## On this page

[![](https://docs-durable-objects-instance-replaced-errors.previews.developers.cloudflare.com/_astro/logo.te5VL_aD.svg)Docs](https://docs-durable-objects-instance-replaced-errors.previews.developers.cloudflare.com/)

```json
{"@context":"https://schema.org","@type":"TechArticle","@id":"https://developers.cloudflare.com/workers-vpc/configuration/vpc-services/terraform/#page","headline":"Configure with Terraform · Cloudflare Workers VPC","description":"Learn how to manage VPC Services using the Cloudflare Terraform provider.","url":"https://developers.cloudflare.com/workers-vpc/configuration/vpc-services/terraform/","inLanguage":"en","image":"https://developers.cloudflare.com/og-docs.png","dateModified":"2026-08-24","publisher":{"@type":"Organization","name":"Cloudflare","description":"One platform for your apps, agents, and workforce. Build, secure, and scale without managing infrastructure","url":"https://www.cloudflare.com/","sameAs":["https://github.com/cloudflare","https://www.linkedin.com/company/cloudflare","https://x.com/cloudflare"],"logo":{"@type":"ImageObject","url":"https://developers.cloudflare.com/logo.svg"},"address":{"@type":"PostalAddress","streetAddress":"101 Townsend St","addressLocality":"San Francisco","addressRegion":"CA","postalCode":"94107","addressCountry":"US"},"contactPoint":[{"@type":"ContactPoint","contactType":"Customer Support","url":"https://support.cloudflare.com/","availableLanguage":["English"]},{"@type":"ContactPoint","contactType":"Sales","url":"https://www.cloudflare.com/contact/","availableLanguage":["English"]}]},"isPartOf":{"@type":"WebSite","@id":"https://developers.cloudflare.com/#website","name":"Cloudflare Docs","url":"https://developers.cloudflare.com/"}}
```
