<page>
---
title: Overview · Cloudflare Workers VPC
description: Securely connect your private cloud to Cloudflare to build cross-cloud apps.
lastUpdated: 2026-03-02T15:59:53.000Z
chatbotDeprioritize: false
source_url:
  html: https://developers.cloudflare.com/workers-vpc/
  md: https://developers.cloudflare.com/workers-vpc/index.md
---

Securely connect your private cloud to Cloudflare to build cross-cloud apps.

Available on Free and Paid plans

Workers VPC allows you to connect your Workers to your private APIs and services in external clouds (AWS, Azure, GCP, on-premise, etc.) that are not accessible from the public Internet.

With Workers VPC, you can configure a [Cloudflare Tunnel](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/) to establish secure, private connections from your private networks to Cloudflare. Then, you can configure a [VPC Service](https://developers.cloudflare.com/workers-vpc/configuration/vpc-services/) for each service in the external private network you need to connect to, and use [VPC Service bindings](https://developers.cloudflare.com/workers-vpc/api/) to connect from Workers.

Note

Workers VPC is currently in beta. Features and APIs may change before general availability. While in beta, Workers VPC is available for free to all Workers plans.

* index.ts

  ```ts
  export default {
    async fetch(request, env, ctx) {
      // Access your private API through the service binding
      const response = await env.PRIVATE_API.fetch(
        "http://internal-api.company.local/data",
      );


        // Process the response from your private network
        const data = await response.json();


        return new Response(JSON.stringify(data), {
          headers: { "content-type": "application/json" },
        });
      },


  };
  ```

* wrangler.jsonc

  ```json
    {
      "$schema": "node_modules/wrangler/config-schema.json",
      "name": "WORKER-NAME",
      "main": "src/index.ts",
      "compatibility_date": "2025-02-04",
      "vpc_services": [
        {
          "binding": "PRIVATE_API",
          "service_id": "ENTER_SERVICE_ID",
          "remote": true
        }
      ]
    }
  ```

## Use cases

### Access private APIs from Workers applications

Deploy APIs or full-stack applications to Workers that connect to private authentication services, CMS systems, internals APIs, and more. Your Workers applications run globally with optimized access to the backend services of your private network.

### API gateway

Route requests to internal microservices in your private network based on URL paths. Centralize access control and load balancing for multiple private services on Workers.

### Internal tooling, agents, dashboards

Build employee-facing applications and MCP servers that aggregate data from multiple private services. Create unified dashboards, admin panels, and internal tools without exposing backend systems.

## Related products

**[Workers](https://developers.cloudflare.com/workers/)**

Build serverless applications and deploy instantly across the globe for exceptional performance, reliability, and scale.

**[Hyperdrive](https://developers.cloudflare.com/hyperdrive/)**

Connect to PostgreSQL and MySQL databases from Workers with connection pooling and caching built-in, available to all Workers plans.

</page>

<page>
---
title: 404 - Page Not Found · Cloudflare Workers VPC
chatbotDeprioritize: false
source_url:
  html: https://developers.cloudflare.com/workers-vpc/404/
  md: https://developers.cloudflare.com/workers-vpc/404/index.md
---

# 404

Check the URL, try using our [search](https://developers.cloudflare.com/search/) or try our LLM-friendly [llms.txt directory](https://developers.cloudflare.com/llms.txt).

</page>

<page>
---
title: Workers Binding API · Cloudflare Workers VPC
description: VPC Service bindings provide a convenient API for accessing VPC
  Services from your Worker. Each binding represents a connection to a service
  in your private network through a Cloudflare Tunnel.
lastUpdated: 2026-01-29T10:38:24.000Z
chatbotDeprioritize: false
source_url:
  html: https://developers.cloudflare.com/workers-vpc/api/
  md: https://developers.cloudflare.com/workers-vpc/api/index.md
---

VPC Service bindings provide a convenient API for accessing VPC Services from your Worker. Each binding represents a connection to a service in your private network through a Cloudflare Tunnel.

Each request made on the binding will route to the specific service that was configured for the VPC Service, while restricting access to the rest of your private network.

Note

Workers VPC is currently in beta. Features and APIs may change before general availability. While in beta, Workers VPC is available for free to all Workers plans.

## VPC Service binding

A VPC Service binding is accessed via the `env` parameter in your Worker's fetch handler. It provides a `fetch()` method for making HTTP requests to your private service.

Required roles

To bind a VPC Service in a Worker, your user needs `Connectivity Directory Bind` (or `Connectivity Directory Admin`). For role definitions, refer to [Roles](https://developers.cloudflare.com/fundamentals/manage-members/roles/#account-scoped-roles).

## fetch()

Makes an HTTP request to the private service through the configured tunnel.

```js
const response = await env.VPC_SERVICE_BINDING.fetch(resource, options);
```

Note

The [VPC Service configurations](https://developers.cloudflare.com/workers-vpc/configuration/vpc-services/#vpc-service-configuration) will always be used to connect and route requests to your services in external networks, even if a different URL or host is present in the actual `fetch()` operation of the Worker code.

The host provided in the `fetch()` operation is not used to route requests, and instead only populates the `Host` field for a HTTP request that can be parsed by the server and used for Server Name Indication (SNI), when the `https` scheme is specified.

The port provided in the `fetch()` operation is ignored — the port specified in the VPC Service configuration will be used.

### Parameters

* `resource` (string | URL | Request) - The URL to fetch. This must be an absolute URL including protocol, host, and path (for example, `http://internal-api/api/users`)

* `options` (optional RequestInit) - Standard fetch options including:

  * `method` - HTTP method (GET, POST, PUT, DELETE, etc.)
  * `headers` - Request headers
  * `body` - Request body
  * `signal` - AbortSignal for request cancellation

Absolute URLs Required

VPC Service fetch requests must use absolute URLs including the protocol (`http`/`https`), host, and path. Relative paths are not supported.

### Return value

Returns a `Promise<Response>` that resolves to a [standard Fetch API Response object](https://developer.mozilla.org/en-US/docs/Web/API/Response).

### Examples

#### Basic GET request

```js
export default {
  async fetch(request, env) {
    const privateRequest = new Request(
      "http://internal-api.company.local/users",
    );
    const response = await env.VPC_SERVICE_BINDING.fetch(privateRequest);
    const users = await response.json();


    return new Response(JSON.stringify(users), {
      headers: { "Content-Type": "application/json" },
    });
  },
};
```

#### POST request with body

```js
export default {
  async fetch(request, env) {
    const privateRequest = new Request(
      "http://internal-api.company.local/users",
      {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          Authorization: `Bearer ${env.API_TOKEN}`,
        },
        body: JSON.stringify({
          name: "John Doe",
          email: "john@example.com",
        }),
      },
    );


    const response = await env.VPC_SERVICE_BINDING.fetch(privateRequest);


    if (!response.ok) {
      return new Response("Failed to create user", { status: response.status });
    }


    const user = await response.json();
    return new Response(JSON.stringify(user), {
      headers: { "Content-Type": "application/json" },
    });
  },
};
```

#### Request with HTTPS and IP address

```js
export default {
  async fetch(request, env) {
    const privateRequest = new Request("https://10.0.1.50/api/data");
    const response = await env.VPC_SERVICE_BINDING.fetch(privateRequest);


    return response;
  },
};
```

## Next steps

* Configure [service bindings in your Wrangler configuration file](https://developers.cloudflare.com/workers-vpc/configuration/vpc-services/)
* Refer to [usage examples](https://developers.cloudflare.com/workers-vpc/examples/)

</page>

<page>
---
title: Configuration · Cloudflare Workers VPC
lastUpdated: 2025-11-04T21:03:20.000Z
chatbotDeprioritize: true
source_url:
  html: https://developers.cloudflare.com/workers-vpc/configuration/
  md: https://developers.cloudflare.com/workers-vpc/configuration/index.md
---

* [VPC Services](https://developers.cloudflare.com/workers-vpc/configuration/vpc-services/)
* [Cloudflare Tunnel](https://developers.cloudflare.com/workers-vpc/configuration/tunnel/)

</page>

<page>
---
title: Examples · Cloudflare Workers VPC
lastUpdated: 2025-11-04T21:03:20.000Z
chatbotDeprioritize: true
source_url:
  html: https://developers.cloudflare.com/workers-vpc/examples/
  md: https://developers.cloudflare.com/workers-vpc/examples/index.md
---

* [Access a private API or website](https://developers.cloudflare.com/workers-vpc/examples/private-api/)
* [Access a private S3 bucket](https://developers.cloudflare.com/workers-vpc/examples/private-s3-bucket/)
* [Route to private services from Workers](https://developers.cloudflare.com/workers-vpc/examples/route-across-private-services/)

</page>

<page>
---
title: Get started · Cloudflare Workers VPC
description: This guide will walk you through creating your first Workers VPC
  Service, allowing your Worker to access resources in your private network.
lastUpdated: 2026-02-02T18:38:11.000Z
chatbotDeprioritize: false
source_url:
  html: https://developers.cloudflare.com/workers-vpc/get-started/
  md: https://developers.cloudflare.com/workers-vpc/get-started/index.md
---

This guide will walk you through creating your first Workers VPC Service, allowing your Worker to access resources in your private network.

You will create a Workers application, create a Tunnel in your private network to connect it to Cloudflare, and then configure VPC Services for the services on your private network you want to access from Workers.

Note

Workers VPC is currently in beta. Features and APIs may change before general availability. While in beta, Workers VPC is available for free to all Workers plans.

## Prerequisites

Before you begin, ensure you have completed the following:

1. Sign up for a [Cloudflare account](https://dash.cloudflare.com/sign-up/workers-and-pages).
2. Install [`Node.js`](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm).

Node.js version manager

Use a Node version manager like [Volta](https://volta.sh/) or [nvm](https://github.com/nvm-sh/nvm) to avoid permission issues and change Node.js versions. [Wrangler](https://developers.cloudflare.com/workers/wrangler/install-and-update/), discussed later in this guide, requires a Node version of `16.17.0` or later.

Additionally, you will need:

* Access to a private network (your local network, AWS VPC, Azure VNet, GCP VPC, or on-premise networks)
* The **Connectivity Directory Bind** role to bind to existing VPC Services from Workers.
* Or, the **Connectivity Directory Admin** role to create VPC Services, and bind to them from Workers.

## 1. Create a new Worker project

Create a new Worker project using Wrangler:

* npm

  ```sh
  npm create cloudflare@latest -- workers-vpc-app
  ```

* yarn

  ```sh
  yarn create cloudflare workers-vpc-app
  ```

* pnpm

  ```sh
  pnpm create cloudflare@latest workers-vpc-app
  ```

For setup, select the following options:

* For *What would you like to start with?*, choose `Hello World example`.
* For *Which template would you like to use?*, choose `Worker only`.
* For *Which language do you want to use?*, choose `TypeScript`.
* For *Do you want to use git for version control?*, choose `Yes`.
* For *Do you want to deploy your application?*, choose `No` (we will be making some changes before deploying).

Navigate to your project directory:

```sh
cd workers-vpc-app
```

## 2. Set up Cloudflare Tunnel

A Cloudflare Tunnel creates a secure connection from your private network to Cloudflare. This tunnel will allow Workers to securely access your private resources. You can create the tunnel on a virtual machine or container in your external cloud, or even on your local desktop for the sake of this tutorial.

1. Navigate to the [Workers VPC dashboard](https://dash.cloudflare.com/?to=/:account/workers/vpc/tunnels) and select the **Tunnels** tab.

2. Select **Create** to create a new tunnel.

3. Enter a name for your tunnel (for example, `workers-vpc-tunnel`) and select **Save tunnel**.

4. Choose your operating system and architecture. The dashboard will provide specific installation instructions for your environment.

5. Follow the provided commands to download and install `cloudflared`, and execute the service installation command with your unique token.

The dashboard will confirm when your tunnel is successfully connected.

### Configuring your private network for Cloudflare Tunnel

Once your tunnel is connected, you will need to ensure it can access the services that you want your Workers to have access to. The tunnel should be installed on a machine that can reach the internal resources you want to expose to Workers VPC. In external clouds, this may mean configuring Access-Control-Lists, Security Groups, or VPC Firewall Rules to ensure that the tunnel can access the desired services.

Note

This guide provides a quick setup for Workers VPC.

For comprehensive tunnel configuration, monitoring, and management, refer to the [full Cloudflare Tunnel documentation](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/).

## 3. Create a VPC Service

Now that your tunnel is running, create a VPC Service that Workers can use to access your internal resources:

* Dashboard

  1. Navigate to the [Workers VPC dashboard](https://dash.cloudflare.com/?to=/:account/workers/vpc) and select the **VPC Services** tab.

  2. Select **Create** to create a new VPC Service.

  3. Enter a **Service name** for your VPC Service (for example, `my-private-api`).

  4. Select your tunnel from the **Tunnel** dropdown, or select **Create Tunnel** if you need to create a new one.

  5. Enter the **Host or IP address** of your internal service (for example, `localhost`, `internal-api.company.local`, or `10.0.1.50`).

  6. Configure **Ports**. Select either:

     * **Use default ports** for standard HTTP (80) and HTTPS (443)
     * **Provide port values** to specify custom HTTP and HTTPS ports

  7. Configure **DNS Resolver**. Select either:

     * **Use tunnel as resolver** to use the tunnel's built-in DNS resolution
     * **Custom resolver** and enter your DNS resolver IP (for example, `8.8.8.8`)

  8. Select **Create service** to create your VPC Service.

  The dashboard will display your new VPC Service with a unique Service ID. Save this Service ID for the next step.

* Wrangler CLI

  ```sh
  npx wrangler vpc service create my-private-api \
    --type http \
    --tunnel-id <YOUR_TUNNEL_ID> \
    --hostname <YOUR_HOSTNAME>
  ```

  Replace:

  * `<YOUR_TUNNEL_ID>` with your tunnel ID from step 2
  * `<YOUR_HOSTNAME>` with your internal service hostname (for example, `internal-api.company.local`)

  You can also:

  * Create services using IP addresses by replacing `--hostname <YOUR_HOSTNAME>` with `--ipv4 <YOUR_IPV4_ADDRESS>` (for example, `--ipv4 10.0.1.50`), `--ipv6 <YOUR_IPV6_ADDRESS>` (for example, `--ipv6 fe80::1`), or both for dual-stack configuration (`--ipv4 10.0.1.50 --ipv6 fe80::1`)
  * Specify custom ports by adding `--http-port <PORT>` and/or `--https-port <PORT>` (for example, `--http-port 8080 --https-port 8443`)

  The command will return a service ID. Save this for the next step.

If you encounter permission errors, refer to [Required roles](https://developers.cloudflare.com/workers-vpc/configuration/vpc-services/#required-roles).

## 4. Configure your Worker

Add the VPC Service binding to your Wrangler configuration file:

* wrangler.jsonc

  ```jsonc
  {
    "$schema": "./node_modules/wrangler/config-schema.json",
    "name": "workers-vpc-app",
    "main": "src/index.ts",
    // Set this to today's date
    "compatibility_date": "2026-03-09",
    "vpc_services": [
      {
        "binding": "VPC_SERVICE",
        "service_id": "<YOUR_SERVICE_ID>"
      }
    ]
  }
  ```

* wrangler.toml

  ```toml
  "$schema" = "./node_modules/wrangler/config-schema.json"
  name = "workers-vpc-app"
  main = "src/index.ts"
  # Set this to today's date
  compatibility_date = "2026-03-09"


  [[vpc_services]]
  binding = "VPC_SERVICE"
  service_id = "<YOUR_SERVICE_ID>"
  ```

Replace `<YOUR_SERVICE_ID>` with the service ID from step 3.

## 5. Write your Worker code

Update your Worker to use the VPC Service binding. The following example:

```ts
export default {
  async fetch(request, env, ctx): Promise<Response> {
    const url = new URL(request.url);


    // This is a simple proxy scenario.
    // In this case, you will need to replace the URL with the proper protocol (http vs. https), hostname and port of the service.
    // For example, this could be "http://localhost:1111", "http://192.0.0.1:3000", "https://my-internal-api.example.com"
    const targetUrl = new URL(`http://<ENTER_SERVICE_HOST>:<ENTER_SERVICE_PORT>${url.pathname}${url.search}`);


    // Create new request with the target URL but preserve all other properties
    const proxyRequest = new Request(targetUrl, {
      method: request.method,
      headers: request.headers,
      body: request.body,
    });


    const response = await env.VPC_SERVICE.fetch(proxyRequest);


    return response;
  },
} satisfies ExportedHandler<Env>;
```

## 6. Test locally

Test your Worker locally. You must use remote VPC Services, using either [Workers remote bindings](https://developers.cloudflare.com/workers/development-testing/#remote-bindings) as was configured in your `wrangler.jsonc` configuration file, or using `npx wrangler dev --remote`:

```sh
npx wrangler dev
```

Visit `http://localhost:8787` to test your Worker's connection to your private network.

## 7. Deploy your Worker

Once testing is complete, deploy your Worker:

```sh
npx wrangler deploy
```

Your Worker is now deployed and can access your private network resources securely through the Cloudflare Tunnel. If you encounter permission errors, refer to [Required roles](https://developers.cloudflare.com/workers-vpc/configuration/vpc-services/#required-roles).

## Next steps

* Explore [configuration options](https://developers.cloudflare.com/workers-vpc/configuration/) for advanced setups
* Set up [high availability tunnels](https://developers.cloudflare.com/workers-vpc/configuration/tunnel/hardware-requirements/) for production
* View [platform-specific guides](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/deployment-guides/) for AWS, Azure, GCP, and Kubernetes
* Check out [examples](https://developers.cloudflare.com/workers-vpc/examples/) for common use cases

</page>

<page>
---
title: Reference · Cloudflare Workers VPC
lastUpdated: 2025-11-04T21:03:20.000Z
chatbotDeprioritize: true
source_url:
  html: https://developers.cloudflare.com/workers-vpc/reference/
  md: https://developers.cloudflare.com/workers-vpc/reference/index.md
---

* [Limits](https://developers.cloudflare.com/workers-vpc/reference/limits/)
* [Pricing](https://developers.cloudflare.com/workers-vpc/reference/pricing/)
* [Troubleshoot and debug](https://developers.cloudflare.com/workers-vpc/reference/troubleshooting/)

</page>

<page>
---
title: Cloudflare Tunnel · Cloudflare Workers VPC
description: Cloudflare Tunnel creates secure connections from your
  infrastructure to Cloudflare's global network, providing the network
  connectivity that allows Workers to access your private resources.
lastUpdated: 2026-03-04T23:04:00.000Z
chatbotDeprioritize: false
source_url:
  html: https://developers.cloudflare.com/workers-vpc/configuration/tunnel/
  md: https://developers.cloudflare.com/workers-vpc/configuration/tunnel/index.md
---

Cloudflare Tunnel creates secure connections from your infrastructure to Cloudflare's global network, providing the network connectivity that allows Workers to access your private resources.

When you create a VPC Service, you specify a tunnel ID and target service. Workers VPC then routes requests from your Worker to the specified tunnel, which establishes a connection to the specified hostname or IP address, such that the target service receives the request and returns a response back to your Worker.

To allow members to create VPC Services that represent a target service reachable via a tunnel, you must assign them the **Connectivity Directory Admin** role. Members must possess **Connectivity Directory Bind** role to bind to existing VPC Services from worker.

The tunnel maintains persistent connections to Cloudflare, eliminating the need for inbound firewall rules or public IP addresses.

Note

This section provides tunnel configuration specific to Workers VPC use cases. For comprehensive tunnel documentation including monitoring and advanced configurations, refer to the [full Cloudflare Tunnel documentation](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/).

## Create and run tunnel (`cloudflared`)

Cloudflare Tunnel requires the installation of a lightweight and highly scalable server-side daemon, `cloudflared`, to connect your infrastructure to Cloudflare.

Version and Configuration

Ensure you are running `cloudflared` version 2025.7.0 or later (latest version recommended) to ensure proper DNS resolution and connectivity. Older versions are not supported.

Workers VPC also requires Cloudflare Tunnel to connect using the [QUIC transport protocol](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/configure-tunnels/run-parameters/#protocol) using `auto` or `quic`. Ensure outbound UDP traffic on port 7844 is allowed through your firewall for QUIC connections.

Cloudflare Tunnels can be created one of two ways:

1. **Remotely-managed tunnels (recommended):** Remotely-managed configurations are stored on Cloudflare, allowing you to manage the tunnel from any machine using the dashboard, API, or Terraform.
2. **Locally-managed tunnels:** A locally-managed tunnel is created by running `cloudflared tunnel create <NAME>` on the command line. Tunnel configuration is stored in your local cloudflared directory.

For Workers VPC, we recommend creating a remotely-managed tunnel through the dashboard. Follow the [Tunnels for Workers VPC dashboard setup guide](https://developers.cloudflare.com/workers-vpc/get-started/) to create your tunnel with provided installation commands shown in the dashboard.

For locally-managed tunnels, refer to the [`cloudflared` locally-managed tunnels](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/do-more-with-tunnels/local-management/) guide. For manual installation, refer to the [`cloudflared` downloads page](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/downloads/) for platform-specific installation instructions.

Note

Cloudflare Tunnels can either be configured for usage with [Cloudflare Zero Trust](https://developers.cloudflare.com/cloudflare-one/) or [Workers VPC](https://developers.cloudflare.com/workers-vpc/).

Use Tunnels with Zero Trust when you are exposing internal applications securely to your employees with Cloudflare Access and hostnames.

Use Tunnels with Workers VPC when you want to access private APIs, private databases, internal services or other HTTP services within your cloud or on-premise private network from Workers.

The same `cloudflared` instance can be used to cover both Zero Trust and Workers VPC use cases simultaneously.

Note

[Ingress configurations](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/do-more-with-tunnels/local-management/configuration-file/) for locally-managed tunnels are only relevant when using tunnels to expose services to the public internet, and are not required for Workers VPC as routing is handled by the VPC Service configuration.

## Cloud platform setup guides

For platform-specific tunnel deployment instructions for production workloads:

* [AWS](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/deployment-guides/aws/) - Deploy tunnels in Amazon Web Services
* [Azure](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/deployment-guides/azure/) - Deploy tunnels in Microsoft Azure
* [Google Cloud](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/deployment-guides/google-cloud-platform/) - Deploy tunnels in Google Cloud Platform
* [Kubernetes](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/deployment-guides/kubernetes/) - Deploy tunnels in Kubernetes clusters
* [Terraform](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/deployment-guides/terraform/) - Deploy tunnels using Infrastructure as Code

Refer to the full Cloudflare Tunnel documentation on [how to setup Tunnels for high availability and failover with replicas](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/configure-tunnels/tunnel-availability/).

Note

We do not recommend using `cloudflared` in autoscaling setups because downscaling (removing replicas) will break existing user connections to that replica. Additionally, `cloudflared` does not load balance across replicas; replicas are strictly for high availability and requests are routed to the nearest replica.

## Next steps

* Configure [VPC Services](https://developers.cloudflare.com/workers-vpc/configuration/vpc-services/) to connect your tunnels to Workers
* Review [hardware requirements](https://developers.cloudflare.com/workers-vpc/configuration/tunnel/hardware-requirements/) for capacity planning
* Review the [complete Cloudflare Tunnel documentation](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/) for advanced features

</page>

<page>
---
title: Access a private API or website · Cloudflare Workers VPC
description: This example demonstrates how to access a private REST API that is
  not exposed to the public internet. In this guide, we will configure a VPC
  Service for an internal API, create a Worker that makes requests to that API,
  and deploy the Worker to validate our changes.
lastUpdated: 2026-02-02T18:38:11.000Z
chatbotDeprioritize: false
source_url:
  html: https://developers.cloudflare.com/workers-vpc/examples/private-api/
  md: https://developers.cloudflare.com/workers-vpc/examples/private-api/index.md
---

This example demonstrates how to access a private REST API that is not exposed to the public internet. In this guide, we will configure a VPC Service for an internal API, create a Worker that makes requests to that API, and deploy the Worker to validate our changes.

## Prerequisites

* A virtual machine/EC2 instance running in your VPC/virtual network
* A private API or website running in your VPC/virtual network with security rules allowing access to the virtual machine that will be running `cloudflared`
* Workers account with Workers VPC access

## 1. Set up Cloudflare Tunnel

A Cloudflare Tunnel creates a secure connection from your private network to Cloudflare. This tunnel will allow Workers to securely access your private resources.

1. Navigate to the [Workers VPC dashboard](https://dash.cloudflare.com/?to=/:account/workers/vpc/tunnels) and select the **Tunnels** tab.

2. Select **Create** to create a new tunnel.

3. Enter a name for your tunnel (for example, `private-api-tunnel`) and select **Save tunnel**.

4. Choose your operating system and architecture. The dashboard will provide specific installation instructions for your environment.

5. Follow the provided commands to download and install `cloudflared` on your VM, and execute the service installation command with your unique token.

The dashboard will confirm when your tunnel is successfully connected. Note the tunnel ID for the next step.

## 2. Create the Workers VPC Service

First, create a Workers VPC Service for your internal API:

```bash
npx wrangler vpc service create api-service \
  --type http \
  --tunnel-id <YOUR_TUNNEL_ID> \
  --ipv4 10.0.1.50 \
  --http-port 8080
```

You can also create a VPC Service for a service using its hostname:

```bash
npx wrangler vpc service create api-service \
  --type http \
  --tunnel-id <YOUR_TUNNEL_ID> \
  --hostname internal-hostname.example.com
```

Note the service ID returned for the next step.

## 3. Configure your Worker

Update your Wrangler configuration file:

* wrangler.jsonc

  ```jsonc
  {
    "$schema": "./node_modules/wrangler/config-schema.json",
    "name": "private-api-gateway",
    "main": "src/index.js",
    // Set this to today's date
    "compatibility_date": "2026-03-09",
    "vpc_services": [
      {
        "binding": "INTERNAL_API",
        "service_id": "<YOUR_SERVICE_ID>",
        "remote": true
      }
    ]
  }
  ```

* wrangler.toml

  ```toml
  "$schema" = "./node_modules/wrangler/config-schema.json"
  name = "private-api-gateway"
  main = "src/index.js"
  # Set this to today's date
  compatibility_date = "2026-03-09"


  [[vpc_services]]
  binding = "INTERNAL_API"
  service_id = "<YOUR_SERVICE_ID>"
  remote = true
  ```

## 4. Implement the Worker

In your Workers code, use the VPC Service binding in order to send requests to the service:

```js
export default {
  async fetch(request, env, ctx) {
    try {
      // Fetch data from internal API and process it before returning
      const response = await env.INTERNAL_API.fetch("http://10.0.1.50:8080/api/data");


      // Use the response of the private API to perform more logic in Workers, before returning the final response
      return response;
    } catch (error) {
      return new Response("Service unavailable", { status: 503 });
    }
  },
};
```

This guide demonstrates how you could create a simple proxy in your Workers. However, you could use VPC Services to fetch APIs directly and manipulate the responses to enable you to build more full-stack and backend functionality on Workers.

## 5. Deploy and test

Now, you can deploy and test your Worker that you have created:

```bash
npx wrangler deploy
```

```bash
# Test GET request
curl https://private-api-gateway.workers.dev
```

## Next steps

* Add [authentication and authorization](https://developers.cloudflare.com/workers/examples/auth-with-headers/)
* Implement [rate limiting](https://developers.cloudflare.com/durable-objects/api/)
* Set up [monitoring and alerting](https://developers.cloudflare.com/analytics/analytics-engine/)
* Explore [other examples](https://developers.cloudflare.com/workers-vpc/examples/)

</page>

<page>
---
title: VPC Services · Cloudflare Workers VPC
description: 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.
lastUpdated: 2026-02-23T17:32:26.000Z
chatbotDeprioritize: false
source_url:
  html: https://developers.cloudflare.com/workers-vpc/configuration/vpc-services/
  md: https://developers.cloudflare.com/workers-vpc/configuration/vpc-services/index.md
---

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.

You can use bindings to connect to VPC Services from Workers. Every request made to a VPC Service using its `fetch` function will be securely routed to the configured service in the private network.

VPC Services enforce that requests are routed to their intended service without exposing the entire network, securing your workloads and preventing server-side request forgery (SSRF).

Members must possess **Connectivity Directory Bind** role to bind to existing VPC Services from Workers. Creating VPC Services requires members to possess the **Connectivity Directory Admin** role.

Note

Workers VPC is currently in beta. Features and APIs may change before general availability. While in beta, Workers VPC is available for free to all Workers plans.

## VPC Service configuration

A VPC Service consists of:

* **Type**: Currently only `http` is supported (support for `tcp` coming soon)
* **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.

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.

The `https` scheme can be used for an encrypted connection within your network, between the tunnel and your service. When the `https` scheme is specified, a hostname provided to the `fetch()` operation is utilized as the Server Name Indication (SNI) value.

VPC Services default to allowing both `http` and `https` schemes to be used. You can provide values for only one of `http_port` or `https_port` to enforce the use of a particular scheme.

When Workers VPC is unable to establish a connection to your service, `fetch()` will throw an exception.

Note

The [VPC Service configuration](https://developers.cloudflare.com/workers-vpc/configuration/vpc-services/#vpc-service-configuration) host and port(s) will always be used to connect and route requests to your services, even if a different host or port is present in the URL provided to the `fetch()` operation in the Worker code.

The host provided in the `fetch()` operation is not used to route requests, and instead only populates the `Host` field for a HTTP request, or `Host` and the Server Name Indication (SNI) value presented to your service for a HTTPS request.

The port provided in the `fetch()` operation is ignored — the port specified in the VPC Service configuration for the provided scheme will be used.

### Supported TLS certificates

When using the `https` scheme, the tunnel verifies the TLS certificate presented by your origin service. Workers VPC trusts the following certificate types:

* **Publicly trusted certificates** — Certificates issued by well-known public certificate authorities (for example, Let's Encrypt, DigiCert).
* **[Cloudflare Origin CA certificates](https://developers.cloudflare.com/ssl/origin-configuration/origin-ca/)** — Free certificates issued by Cloudflare that encrypt traffic between Cloudflare and your origin. Origin CA certificates are not trusted by browsers, but are trusted by Workers VPC when connecting to your private services.

If your origin service presents a certificate that is not issued by a publicly trusted CA or by Cloudflare Origin CA, the TLS handshake will fail and `fetch()` will throw an exception.

## Configuration example

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](https://developers.cloudflare.com/api/resources/connectivity/subresources/directory/subresources/services/), a type of service within the broader connectivity directory.

```jsonc
{
  "type": "http",
  "name": "human-readable-name",


  // Port configuration (optional - defaults to 80/443)
  "http_port": 80,
  "https_port": 443,


  // Host configuration
  "host": {
    "ipv4": "10.0.0.1",
    "ipv6": "fe80::",
    "network": {
      "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`.

```jsonc
{
  "type": "http",
  "name": "human-readable-name",


  // Port configuration (optional - defaults to 80/443)
  "http_port": 80,
  "https_port": 443,


  // Hostname Host (with DNS resolver)
  "host": {
    "hostname": "example.com",
    "resolver_network": {
      "tunnel_id": "0191dce4-9ab4-7fce-b660-8e5dec5172da",
      "resolver_ips": ["10.0.0.1"], // Optional
    },
  },
}
```

## Workers binding configuration

Once you have created a VPC Service, you can bind it to your Worker:

* wrangler.jsonc

  ```jsonc
  {
    "$schema": "./node_modules/wrangler/config-schema.json",
    "name": "my-worker",
    "main": "src/index.js",
    "vpc_services": [
      {
        "binding": "PRIVATE_API",
        "service_id": "e6a0817c-79c5-40ca-9776-a1c019defe70",
        "remote": true // When true, utilizes [remote bindings](/workers/development-testing/#remote-bindings) to allow access to the VPC Service during local development.
      }
    ]
  }
  ```

* wrangler.toml

  ```toml
  "$schema" = "./node_modules/wrangler/config-schema.json"
  name = "my-worker"
  main = "src/index.js"


  [[vpc_services]]
  binding = "PRIVATE_API"
  service_id = "e6a0817c-79c5-40ca-9776-a1c019defe70"
  remote = true
  ```

You can have multiple VPC service bindings:

* wrangler.jsonc

  ```jsonc
  {
    "vpc_services": [
      {
        "binding": "PRIVATE_API",
        "service_id": "daf43e8c-a81a-4242-9912-4a2ebe4fdd79",
        "remote": true
      },
      {
        "binding": "PRIVATE_DATABASE",
        "service_id": "453b6067-1327-420d-89b3-2b6ad16e6551",
        "remote": true
      },
      {
        "binding": "INTERNAL_CACHE",
        "service_id": "6c39b574-237e-49f4-852a-cea5a93ed8f9",
        "remote": true
      }
    ]
  }
  ```

* wrangler.toml

  ```toml
  [[vpc_services]]
  binding = "PRIVATE_API"
  service_id = "daf43e8c-a81a-4242-9912-4a2ebe4fdd79"
  remote = true


  [[vpc_services]]
  binding = "PRIVATE_DATABASE"
  service_id = "453b6067-1327-420d-89b3-2b6ad16e6551"
  remote = true


  [[vpc_services]]
  binding = "INTERNAL_CACHE"
  service_id = "6c39b574-237e-49f4-852a-cea5a93ed8f9"
  remote = true
  ```

## Required roles

Workers VPC uses the following account roles:

* `Connectivity Directory Read` to view Workers VPC Services and Tunnels.
* `Connectivity Directory Bind` to list/read services and bind them in Workers.
* `Connectivity Directory Admin` to create, update, and delete services.

For role definitions, refer to [Roles](https://developers.cloudflare.com/fundamentals/manage-members/roles/#account-scoped-roles).

If your roles were recently updated and commands are still failing, refresh Wrangler authentication:

```sh
npx wrangler logout
npx wrangler login
```

If you authenticate with an API token (`CLOUDFLARE_API_TOKEN`), ensure the token belongs to a user with the required roles.

## Next steps

* [Configure VPC Services with Terraform](https://developers.cloudflare.com/workers-vpc/configuration/vpc-services/terraform/) for managing VPC Services as infrastructure
* Set up [Cloudflare Tunnel](https://developers.cloudflare.com/workers-vpc/configuration/tunnel/) for your environment
* Learn about the [Service Binding API](https://developers.cloudflare.com/workers-vpc/api/)
* Refer to [examples](https://developers.cloudflare.com/workers-vpc/examples/) of common use cases

</page>

<page>
---
title: Access a private S3 bucket · Cloudflare Workers VPC
description: This example demonstrates how to access a private S3 bucket that is
  not exposed to the public internet. In this guide, we will configure a Workers
  VPC Service for an internal S3-compatible storage service, create a Worker
  that makes requests to that bucket, and deploy the Worker to validate our
  changes.
lastUpdated: 2026-02-02T18:38:11.000Z
chatbotDeprioritize: false
source_url:
  html: https://developers.cloudflare.com/workers-vpc/examples/private-s3-bucket/
  md: https://developers.cloudflare.com/workers-vpc/examples/private-s3-bucket/index.md
---

This example demonstrates how to access a private S3 bucket that is not exposed to the public internet. In this guide, we will configure a Workers VPC Service for an internal S3-compatible storage service, create a Worker that makes requests to that bucket, and deploy the Worker to validate our changes.

## Prerequisites

* A private S3-compatible storage service running in your VPC/virtual network (such as AWS S3 VPC endpoint, MinIO, or similar)
* A virtual machine/EC2 instance running in the same VPC as your S3 VPC endpoint
* Workers account with Workers VPC access

## 1. Set up Cloudflare Tunnel

A Cloudflare Tunnel creates a secure connection from your private network to Cloudflare. This tunnel will allow Workers to securely access your private resources.

1. Navigate to the [Workers VPC dashboard](https://dash.cloudflare.com/?to=/:account/workers/vpc/tunnels) and select the **Tunnels** tab.

2. Select **Create** to create a new tunnel.

3. Enter a name for your tunnel (for example, `s3-tunnel`) and select **Save tunnel**.

4. Choose your operating system and architecture. The dashboard will provide specific installation instructions for your environment.

5. Follow the provided commands to download and install `cloudflared` on your VM, and execute the service installation command with your unique token.

The dashboard will confirm when your tunnel is successfully connected. Note the tunnel ID for the next step.

## 2. Create the Workers VPC Service

First, create a Workers VPC Service for your internal S3 storage:

```bash
npx wrangler vpc service create s3-storage \
  --type http \
  --tunnel-id <YOUR_TUNNEL_ID> \
  --hostname s3.us-west-2.amazonaws.com
```

You can also create a Workers VPC Service using an IP address (for example, if using MinIO):

```bash
npx wrangler vpc service create s3-storage \
  --type http \
  --tunnel-id <YOUR_TUNNEL_ID> \
  --ipv4 10.0.1.60 \
  --http-port 9000
```

Note the service ID returned for the next step.

## 3. Configure S3 bucket policy

Configure your S3 bucket to allow anonymous access from your VPC endpoint. This works for unencrypted S3 objects:

```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowAnonymousAccessFromVPCE",
      "Effect": "Allow",
      "Principal": "*",
      "Action": ["s3:GetObject", "s3:ListBucket"],
      "Resource": [
        "arn:aws:s3:::your-bucket-name",
        "arn:aws:s3:::your-bucket-name/*"
      ],
      "Condition": {
        "StringEquals": {
          "aws:sourceVpce": "vpce-your-endpoint-id"
        }
      }
    }
  ]
}
```

### Testing S3 access directly

You can test S3 access directly from the VM where your Cloudflare Tunnel is running to verify the bucket policy is working correctly. These commands should work without any AWS credentials:

```bash
# Test listing bucket contents
curl -i https://s3.us-west-2.amazonaws.com/your-bucket-name/


# Test downloading a specific file
curl -i https://your-bucket-name.s3.us-west-2.amazonaws.com/test-file.txt
```

## 4. Configure your Worker

Update your Wrangler configuration file:

* wrangler.jsonc

  ```jsonc
  {
    "$schema": "./node_modules/wrangler/config-schema.json",
    "name": "private-s3-gateway",
    "main": "src/index.js",
    // Set this to today's date
    "compatibility_date": "2026-03-09",
    "vpc_services": [
      {
        "binding": "S3_STORAGE",
        "service_id": "<YOUR_SERVICE_ID>"
      }
    ]
  }
  ```

* wrangler.toml

  ```toml
  "$schema" = "./node_modules/wrangler/config-schema.json"
  name = "private-s3-gateway"
  main = "src/index.js"
  # Set this to today's date
  compatibility_date = "2026-03-09"


  [[vpc_services]]
  binding = "S3_STORAGE"
  service_id = "<YOUR_SERVICE_ID>"
  ```

## 5. Implement the Worker

In your Workers code, use the Workers VPC Service binding in order to send requests to the service:

```js
export default {
  async fetch(request, env, ctx) {
    try {
      // Fetch a file from the private S3 bucket via VPC endpoint
      const response = await env.S3_STORAGE.fetch("https://s3.us-west-2.amazonaws.com/my-bucket/data.json");


      // Use the response from S3 to perform more logic in Workers, before returning the final response
      return response;
    } catch (error) {
      return new Response("Storage unavailable", { status: 503 });
    }
  },
};
```

This guide demonstrates how you could access private object storage from your Workers. You could use Workers VPC Services to fetch files directly and manipulate the responses to enable you to build more full-stack and backend functionality on Workers.

## 6. Deploy and test

Now, you can deploy and test your Worker that you have created:

```bash
npx wrangler deploy
```

```bash
# Test GET request
curl https://private-s3-gateway.workers.dev
```

## Next steps

* Add [authentication and authorization](https://developers.cloudflare.com/workers/examples/auth-with-headers/)
* Implement [rate limiting](https://developers.cloudflare.com/durable-objects/api/)
* Set up [monitoring and alerting](https://developers.cloudflare.com/analytics/analytics-engine/)
* Explore [other examples](https://developers.cloudflare.com/workers-vpc/examples/)

</page>

<page>
---
title: Route to private services from Workers · Cloudflare Workers VPC
description: This example shows how to use Workers VPC to create a centralized
  gateway that routes requests based on URL paths, provides authentication and
  rate limiting, and load balances across internal services.
lastUpdated: 2026-02-02T18:38:11.000Z
chatbotDeprioritize: false
source_url:
  html: https://developers.cloudflare.com/workers-vpc/examples/route-across-private-services/
  md: https://developers.cloudflare.com/workers-vpc/examples/route-across-private-services/index.md
---

This example shows how to use Workers VPC to create a centralized gateway that routes requests based on URL paths, provides authentication and rate limiting, and load balances across internal services.

## Prerequisites

* Multiple private APIs or services running in your VPC/virtual network (we'll use a user service and orders service)
* Cloudflare Tunnel configured and running (follow the [Get Started guide](https://developers.cloudflare.com/workers-vpc/get-started/#2-set-up-cloudflare-tunnel) to set up or [create a tunnel from the dashboard](https://dash.cloudflare.com/?to=/:account/workers/vpc/tunnels))
* Workers account with Workers VPC access

## 1. Create the VPC Services

First, create services for your internal APIs using hostnames:

```bash
# Create user service
npx wrangler vpc service create user-service \
  --type http \
  --tunnel-id <YOUR_TUNNEL_ID> \
  --hostname user-api.internal.example.com


# Create orders service
npx wrangler vpc service create order-service \
  --type http \
  --tunnel-id <YOUR_TUNNEL_ID> \
  --hostname orders-api.internal.example.com
```

Note the service IDs returned for the next step.

## 2. Configure your Worker

Update your Wrangler configuration file:

* wrangler.jsonc

  ```jsonc
  {
    "$schema": "./node_modules/wrangler/config-schema.json",
    "name": "api-gateway",
    "main": "src/index.js",
    // Set this to today's date
    "compatibility_date": "2026-03-09",
    "vpc_services": [
      {
        "binding": "USER_SERVICE",
        "service_id": "<YOUR_USER_SERVICE_ID>"
      },
      {
        "binding": "ORDER_SERVICE",
        "service_id": "<YOUR_ORDER_SERVICE_ID>"
      }
    ]
  }
  ```

* wrangler.toml

  ```toml
  "$schema" = "./node_modules/wrangler/config-schema.json"
  name = "api-gateway"
  main = "src/index.js"
  # Set this to today's date
  compatibility_date = "2026-03-09"


  [[vpc_services]]
  binding = "USER_SERVICE"
  service_id = "<YOUR_USER_SERVICE_ID>"


  [[vpc_services]]
  binding = "ORDER_SERVICE"
  service_id = "<YOUR_ORDER_SERVICE_ID>"
  ```

## 3. Implement the Worker

In your Workers code, use the VPC Service bindings to route requests to the appropriate services:

```js
export default {
  async fetch(request, env, ctx) {
    const url = new URL(request.url);


    // Route to internal services
    if (url.pathname.startsWith('/api/users')) {
      const response = await env.USER_SERVICE.fetch("https://user-api.internal.example.com" + url.pathname);
      return response;
    } else if (url.pathname.startsWith('/api/orders')) {
      const response = await env.ORDER_SERVICE.fetch("https://orders-api.internal.example.com" + url.pathname);
      return response;
    }


    return new Response('Not Found', { status: 404 });
  },
};
```

## 4. Deploy and test

Now, you can deploy and test your Worker:

```bash
npx wrangler deploy
```

```bash
# Test user service requests
curl https://api-gateway.workers.dev/api/users


# Test orders service requests
curl https://api-gateway.workers.dev/api/orders
```

## Next steps

* Add [authentication and authorization](https://developers.cloudflare.com/workers/examples/auth-with-headers/)
* Implement [rate limiting](https://developers.cloudflare.com/durable-objects/api/)
* Set up [monitoring and alerting](https://developers.cloudflare.com/analytics/analytics-engine/)
* Explore [other examples](https://developers.cloudflare.com/workers-vpc/examples/)

</page>

<page>
---
title: Limits · Cloudflare Workers VPC
description: Standard Workers limits apply for request size, timeout, and subrequests.
lastUpdated: 2025-11-04T21:03:20.000Z
chatbotDeprioritize: false
source_url:
  html: https://developers.cloudflare.com/workers-vpc/reference/limits/
  md: https://developers.cloudflare.com/workers-vpc/reference/limits/index.md
---

## Service limits

| Resource | Limit |
| - | - |
| VPC Services per account | 1000 |

Standard Workers limits apply for request size, timeout, and subrequests.

Note

Workers VPC is currently in beta. Features and APIs may change before general availability. While in beta, Workers VPC is available for free to all Workers plans.

</page>

<page>
---
title: Pricing · Cloudflare Workers VPC
description: Workers VPC requires a Workers plan. See Workers pricing for current rates.
lastUpdated: 2025-11-04T21:03:20.000Z
chatbotDeprioritize: false
source_url:
  html: https://developers.cloudflare.com/workers-vpc/reference/pricing/
  md: https://developers.cloudflare.com/workers-vpc/reference/pricing/index.md
---

Workers VPC requires a Workers plan. See [Workers pricing](https://developers.cloudflare.com/workers/platform/pricing/) for current rates.

Free during Open Beta

Workers VPC is free during the open beta period. Standard Workers pricing applies for compute time and requests.

</page>

<page>
---
title: Troubleshoot and debug · Cloudflare Workers VPC
description: Troubleshoot and debug errors commonly associated with Workers VPC.
lastUpdated: 2026-03-04T23:04:00.000Z
chatbotDeprioritize: false
source_url:
  html: https://developers.cloudflare.com/workers-vpc/reference/troubleshooting/
  md: https://developers.cloudflare.com/workers-vpc/reference/troubleshooting/index.md
---

Troubleshoot and debug errors commonly associated with Workers VPC.

## Connection errors

Workers VPC may return errors at runtime when connecting to private services through Cloudflare Tunnel.

### Tunnel errors

| Error Message | Details | Recommended fixes |
| - | - | - |
| `Error: ProxyError: dns_error` | DNS resolution failed when attempting to connect to your private service through the tunnel. | This error may occur if your `cloudflared` version is outdated. Ensure you are running `cloudflared` version 2025.7.0 or later (latest version recommended). See [Cloudflare Tunnel update instructions](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/downloads/update-cloudflared/). |
| `Error: ProxyError: dns_error` | Cloudflare Tunnel may be configured with `http2` protocol (`TUNNEL_TRANSPORT_PROTOCOL:http2`), which works for Cloudflare Zero Trust [(see note)](https://developers.cloudflare.com/workers-vpc/configuration/tunnel/#create-and-run-tunnel-cloudflared) traffic but prevents DNS resolution from Workers VPC. | Workers VPC requires Cloudflare Tunnel to connect using the [QUIC transport protocol](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/configure-tunnels/run-parameters/#protocol). Ensure outbound UDP traffic on port 7844 is allowed through your firewall. |
| Requests not staying within VPC | Worker requests using `.fetch()` with a public hostname are routing out of the VPC to the hostname configured for the VPC Service. | Ensure your Worker code and the VPC Service use the internal VPC hostname for backend services, not a public hostname. |

## Permission errors

If you cannot view, create, or bind VPC Services and Tunnels in the dashboard or via Wrangler, ensure your user has the required roles.

Workers VPC uses the following account roles:

* `Connectivity Directory Read` to view Workers VPC Services and Tunnels.
* `Connectivity Directory Bind` to list/read services and bind them in Workers.
* `Connectivity Directory Admin` to create, update, and delete services.

For role definitions, refer to [Roles](https://developers.cloudflare.com/fundamentals/manage-members/roles/#account-scoped-roles).

If your roles were recently updated and commands are still failing, refresh Wrangler authentication:

```sh
npx wrangler logout
npx wrangler login
```

If you authenticate with an API token (`CLOUDFLARE_API_TOKEN`), ensure the token belongs to a user with the required roles.

</page>

<page>
---
title: Hardware requirements · Cloudflare Workers VPC
description: "For production use cases, we recommend the following baseline configuration:"
lastUpdated: 2025-11-04T21:03:20.000Z
chatbotDeprioritize: false
source_url:
  html: https://developers.cloudflare.com/workers-vpc/configuration/tunnel/hardware-requirements/
  md: https://developers.cloudflare.com/workers-vpc/configuration/tunnel/hardware-requirements/index.md
---

## Recommendations

For production use cases, we recommend the following baseline configuration:

* Run a cloudflared replica on two dedicated host machines per network location. Using two hosts enables server-side redundancy. See [tunnel availability and replicas](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/configure-tunnels/tunnel-availability/) for setup instructions.
* Size each host with minimum 4GB of RAM and 4 CPU cores.

This setup is usually sufficient to handle traffic from small-medium sized applications. The actual amount of resources used by cloudflared will depend on many variables, including the number of requests per second, bandwidth, network path, and hardware. If usage increases beyond your existing tunnel capacity, you can scale your tunnel by increasing the hardware allocated to the cloudflared hosts.

## Capacity calculator

To estimate tunnel capacity requirements for your deployment, refer to the [tunnel capacity calculator in the Zero Trust documentation](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/configure-tunnels/tunnel-availability/system-requirements/).

## Scaling considerations

Monitor tunnel performance and scale accordingly:

* **CPU utilization**: Keep below 70% average usage
* **Memory usage**: Maintain headroom for traffic spikes
* **Network bandwidth**: Ensure adequate throughput for peak loads
* **Connection count**: Scale cloudflared vertically when approaching capacity limits

## Next steps

* Configure [tunnel deployment](https://developers.cloudflare.com/workers-vpc/configuration/tunnel/)
* Set up [high availability](https://developers.cloudflare.com/workers-vpc/configuration/tunnel/) with multiple replicas

</page>

<page>
---
title: Configure with Terraform · Cloudflare Workers VPC
description: Learn how to manage VPC Services using the Cloudflare Terraform provider.
lastUpdated: 2026-02-23T17:32:26.000Z
chatbotDeprioritize: false
source_url:
  html: https://developers.cloudflare.com/workers-vpc/configuration/vpc-services/terraform/
  md: https://developers.cloudflare.com/workers-vpc/configuration/vpc-services/terraform/index.md
---

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](https://developers.cloudflare.com/terraform/).

This maps directly to the [connectivity directory](https://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://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://developers.cloudflare.com/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](https://developers.cloudflare.com/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](https://developers.cloudflare.com/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](https://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://developers.cloudflare.com/workers-vpc/api/).

For more details on managing Workers and bindings with Terraform, refer to [Workers Infrastructure as Code](https://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"
}
```

## 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).

</page>

