Skip to content
Closed
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 @@ -31,6 +31,7 @@ TryCloudflare quick tunnels are currently not supported if a `config.yaml` confi
- Create a web server for a project on your laptop that you want to share with others on different networks
- Test browser compatibility for a new site by creating a free Tunnel and testing the link in different browsers
- Run speed tests from different regions by using a tool like Pingdom or WebPageTest to connect to the randomly-generated subdomain created by TryCloudflare
- Expose a local [Workers dev server](/workers/development-testing/expose-dev-server/) to receive webhooks or share with teammates — for example, `cloudflared tunnel --url http://localhost:8787`

### Why does Cloudflare provide this service for free?

Expand Down
190 changes: 190 additions & 0 deletions src/content/docs/workers/development-testing/expose-dev-server.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
---
pcx_content_type: how-to
title: Expose your dev server
description: Share your local Workers dev server with others using Cloudflare Tunnel.
sidebar:
order: 5
head: []
---

import { PackageManagers, Tabs, TabItem } from "~/components";

When you run `wrangler dev` or `vite dev` (with the [Cloudflare Vite plugin](/workers/vite-plugin/)), your Worker runs on a local HTTP server bound to `localhost:8787`. This means only your machine can reach it.

To share your dev server with teammates, test from a mobile device, or receive webhooks from external services, you can use [Cloudflare Tunnel](/cloudflare-one/networks/connectors/cloudflare-tunnel/) to create a public URL that routes traffic to your local server.

## How it works

[`cloudflared`](/cloudflare-one/networks/connectors/cloudflare-tunnel/downloads/) runs alongside your dev server and creates an outbound-only connection to the Cloudflare network. Cloudflare assigns a public URL that proxies requests through this connection to `localhost:8787` on your machine.

Your dev server stays on `localhost`. `cloudflared` handles TLS termination and encrypts the tunnel connection automatically. Hot reload continues to work because `wrangler dev` uses a stable proxy on port `8787` that persists across code changes.

## Prerequisites

- [Install `cloudflared`](/cloudflare-one/networks/connectors/cloudflare-tunnel/downloads/) on your machine.
- A working Workers project with `wrangler dev` or `vite dev` running.

## Quick tunnel (no account required)

A [quick tunnel](/cloudflare-one/networks/connectors/cloudflare-tunnel/do-more-with-tunnels/trycloudflare/) generates a temporary public URL on `trycloudflare.com`. No Cloudflare account is needed. This is useful for quick testing or sharing a preview link.

### Start your dev server

<PackageManagers type="exec" pkg="wrangler" args="dev" />

Or, if you are using the [Cloudflare Vite plugin](/workers/vite-plugin/):

<PackageManagers type="exec" pkg="vite" args="dev" />

By default, this starts a server on `http://localhost:8787`.

### Start a quick tunnel

In a separate terminal:

```sh
cloudflared tunnel --url http://localhost:8787
```

`cloudflared` prints a URL like `https://random-words.trycloudflare.com`. Anyone with this URL can reach your dev server.

### Send requests to the public URL

```sh
curl https://random-words.trycloudflare.com
```

The request travels through the Cloudflare network, through the tunnel, and reaches your local Worker.

:::note
Quick tunnels have a limit of 200 concurrent in-flight requests and do not support Server-Sent Events (SSE). For higher limits or persistent hostnames, use a [named tunnel](#named-tunnel-persistent-hostname).
:::

## Named tunnel (persistent hostname)

A named tunnel gives you a stable hostname on your own domain. This requires a Cloudflare account with a domain. You can create a named tunnel using the Cloudflare dashboard (recommended) or the [`cloudflared` CLI](/cloudflare-one/networks/connectors/cloudflare-tunnel/downloads/).

<Tabs>
<TabItem label="Dashboard (Recommended)">

Create and manage the tunnel from the Cloudflare dashboard:

1. Log in to the [Cloudflare dashboard](https://dash.cloudflare.com/?to=/:account/tunnels) and go to **Networking** > **Tunnels**.
2. Select **Create a tunnel**, choose **Cloudflared**, and give it a name (for example, `my-worker-dev`).
3. Install and run `cloudflared` using the command shown in the dashboard.
4. On the **Published applications** tab, add a public hostname (for example, `dev-worker.example.com`) and set the service to `HTTP` / `localhost:8787`.
5. Select **Save**.

For full details, refer to [Create a tunnel (dashboard)](/cloudflare-one/networks/connectors/cloudflare-tunnel/get-started/create-remote-tunnel/).

Start your dev server in a separate terminal:

```sh
npx wrangler dev
```

Your Worker is now reachable at `https://dev-worker.example.com`.

</TabItem>
<TabItem label="CLI">

Create and configure the tunnel locally with `cloudflared`:

```sh
cloudflared tunnel login
cloudflared tunnel create my-worker-dev
cloudflared tunnel route dns my-worker-dev dev-worker.example.com
```

Create `~/.cloudflared/config.yml`:

```yaml
tunnel: my-worker-dev
credentials-file: ~/.cloudflared/<TUNNEL_ID>.json

ingress:
- hostname: dev-worker.example.com
service: http://localhost:8787
- service: http_status:404
```

Replace `<TUNNEL_ID>` with the UUID printed when you created the tunnel.

Start your dev server in one terminal:

```sh
npx wrangler dev
```

In a second terminal, start the tunnel:

```sh
cloudflared tunnel run my-worker-dev
```

Your Worker is now reachable at `https://dev-worker.example.com`.

</TabItem>
</Tabs>

### Restrict access

Anyone who knows the hostname can reach your dev server. To restrict access, [create a Cloudflare Access application](/cloudflare-one/access-controls/applications/http-apps/self-hosted-public-app/) for the hostname and configure a policy that limits access to your team.

## Configuration

### Port matching

The port in the `cloudflared` command or configuration file must match the port your dev server listens on. If you change the dev server port, update the tunnel to match:

```sh
npx wrangler dev --port 3000
```

```sh
cloudflared tunnel --url http://localhost:3000
```

### Interface binding

By default, `wrangler dev` binds to `localhost`. Because `cloudflared` runs on the same machine and connects to `localhost`, this works without changes. You do not need `--ip 0.0.0.0`.

Only use `--ip 0.0.0.0` if `cloudflared` runs on a different machine on your network:

```sh
npx wrangler dev --ip 0.0.0.0 --port 8787
```

### Custom port with Vite

When using the [Cloudflare Vite plugin](/workers/vite-plugin/), configure the port in `vite.config.js`:

```js
import { defineConfig } from "vite";
import { cloudflare } from "@cloudflare/vite-plugin";

export default defineConfig({
plugins: [cloudflare()],
server: {
port: 8787,
},
});
```

Then point `cloudflared` at the same port.

## Common use cases

| Use case | Approach |
| ------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Share a preview link with a teammate | [Quick tunnel](#quick-tunnel-no-account-required) — send them the `trycloudflare.com` URL |
| Test from a mobile device on the same network | [Quick tunnel](#quick-tunnel-no-account-required) or [named tunnel](#named-tunnel-persistent-hostname) — open the URL on your phone |
| Receive webhooks from an external service (for example, Stripe or GitHub) | [Quick tunnel](#quick-tunnel-no-account-required) or [named tunnel](#named-tunnel-persistent-hostname) — set the webhook URL to the tunnel hostname |
| Persistent dev environment for a team | [Named tunnel](#named-tunnel-persistent-hostname) with a stable hostname and an [Access policy](/cloudflare-one/access-controls/applications/http-apps/self-hosted-public-app/) |

## Limitations

- [Quick tunnels](/cloudflare-one/networks/connectors/cloudflare-tunnel/do-more-with-tunnels/trycloudflare/) generate a new URL each time you restart `cloudflared`. For stable URLs, use a [named tunnel](#named-tunnel-persistent-hostname).
- Quick tunnels are capped at 200 concurrent in-flight requests.
- Quick tunnels do not support Server-Sent Events (SSE).
- If you have an existing `~/.cloudflared/config.yaml`, quick tunnels may not work. Rename the file temporarily or use a [named tunnel](#named-tunnel-persistent-hostname) instead.
2 changes: 2 additions & 0 deletions src/content/docs/workers/development-testing/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ Both Wrangler and the Cloudflare Vite plugin use [Miniflare](/workers/testing/mi
- [Get started with Wrangler](/workers/wrangler/install-and-update/)
- [Get started with the Cloudflare Vite plugin](/workers/vite-plugin/get-started/)

To share your dev server with others or receive external webhooks, refer to [Expose your dev server](/workers/development-testing/expose-dev-server/).

### Defaults

By default, running `wrangler dev` / `vite dev` (when using the [Vite plugin](/workers/vite-plugin/get-started/)) means that:
Expand Down