PHPackages                             solution-forest/cloudflare-tunnel - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Authentication &amp; Authorization](/categories/authentication)
4. /
5. solution-forest/cloudflare-tunnel

ActiveLibrary[Authentication &amp; Authorization](/categories/authentication)

solution-forest/cloudflare-tunnel
=================================

Generic Composer bin wrapping cloudflared for local HTTPS tunnels (any local HTTP server; optional Laravel notes in README).

1.0.0(today)04↑2900%MITShellPHP &gt;=8.0

Since Aug 1Pushed todayCompare

[ Source](https://github.com/solutionforest/cloudflare-tunnel)[ Packagist](https://packagist.org/packages/solution-forest/cloudflare-tunnel)[ RSS](/packages/solution-forest-cloudflare-tunnel/feed)WikiDiscussions main Synced today

READMEChangelog (1)DependenciesVersions (6)Used By (0)

solution-forest/cloudflare-tunnel
=================================

[](#solution-forestcloudflare-tunnel)

[![License: MIT](https://camo.githubusercontent.com/08cef40a9105b6526ca22088bc514fbfdbc9aac1ddbf8d4e6c750e3a88a44dca/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d626c75652e737667)](./LICENSE)[![PHP](https://camo.githubusercontent.com/06b0f43df99ca0643c6975afaf5d3831f75b378994c1e8f023c09414447c0cb9/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d253345253344382e302d3737374242342e737667)](https://www.php.net/)[![GitHub](https://camo.githubusercontent.com/0386ea8040712c68a13a314c7ee19d645d700244b1dc8e1448036da8a341630c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4769744875622d736f6c7574696f6e666f72657374253246636c6f7564666c6172652d2d74756e6e656c2d3138313731372e737667)](https://github.com/solutionforest/cloudflare-tunnel)

Composer bin that wraps [`cloudflared`](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/) so any local HTTP server gets a public HTTPS URL in one command.

```
vendor/bin/cloudflare-tunnel
```

Contents
--------

[](#contents)

- [Features](#features)
- [Requirements](#requirements)
- [Installation](#installation)
- [Configuration](#configuration)
- [Testing](#testing)
- [Why](#why)
- [How it works](#how-it-works)
- [Use cases](#use-cases)
- [Laravel notes](#laravel-notes)
- [License](#license)

---

Features
--------

[](#features)

- **Composer `bin` entry point** — `vendor/bin/cloudflare-tunnel` after a `require-dev` install
- **Quick tunnels by default** — zero-setup `https://….trycloudflare.com` via Cloudflare’s [trycloudflare](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/do-more-with-tunnels/trycloudflare/) flow
- **Named tunnels** — set `TUNNEL_NAME` (or `CLOUDFLARE_TUNNEL_NAME`) to run a tunnel from `~/.cloudflared/config.yml` (or `CLOUDFLARED_CONFIG`)
- **Local URL resolution** — env → CLI → auto-detect → default `:8000`, with a printed reason for the choice
- **Auto-detect** — reads local `APP_URL` from `./.env` when it is `http://127.0.0.1:PORT` / `localhost:PORT`, else probes listening ports **8000**, **8080**, **3000**, **80** (`lsof` or `nc`)
- **Extra `cloudflared` args** — optional `CLOUDFLARED_EXTRA_ARGS` (space-separated)
- **Foreground helper UX** — streams `cloudflared` output, highlights the public URL when found, and reminds you to set `APP_URL`
- **Framework-agnostic** — Laravel, Node, static files, or anything listening on HTTP (not a Laravel package; no service provider)

---

Requirements
------------

[](#requirements)

- [`cloudflared`](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/) on `PATH`
- Bash 3.2+ (macOS system Bash is fine)
- Composer (to install the package and expose `vendor/bin/cloudflare-tunnel`)
- PHP ≥ 8.0 (Composer package constraint only; the binary is Bash)

---

Installation
------------

[](#installation)

### 1. Require the package (Packagist)

[](#1-require-the-package-packagist)

```
composer require --dev solution-forest/cloudflare-tunnel:^1.0
```

Or in `composer.json`:

```
{
  "require-dev": {
    "solution-forest/cloudflare-tunnel": "^1.0"
  }
}
```

```
composer update solution-forest/cloudflare-tunnel
```

No `repositories` entry is required — the package is on [Packagist](https://packagist.org/packages/solution-forest/cloudflare-tunnel).

Alternatives (path / VCS)**Path (local package development):**

```
{
  "repositories": [
    {
      "type": "path",
      "url": "packages/cloudflare-tunnel",
      "options": { "symlink": true }
    }
  ],
  "require-dev": {
    "solution-forest/cloudflare-tunnel": "*"
  }
}
```

**VCS (without Packagist):**

```
{
  "repositories": [
    {
      "type": "vcs",
      "url": "https://github.com/solutionforest/cloudflare-tunnel"
    }
  ],
  "require-dev": {
    "solution-forest/cloudflare-tunnel": "^1.0"
  }
}
```

### 2. Install `cloudflared`

[](#2-install-cloudflared)

```
brew install cloudflare/cloudflare/cloudflared
```

Other platforms: [Cloudflare downloads](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/).

### 3. Run

[](#3-run)

Start your local app, then:

```
vendor/bin/cloudflare-tunnel
```

Optional project script (this package does not ship Composer scripts; add them in the consuming app if you want):

```
{
  "scripts": {
    "tunnel": [
      "Composer\\Config::disableProcessTimeout",
      "vendor/bin/cloudflare-tunnel"
    ]
  }
}
```

```
composer run tunnel
```

When the public URL appears, set your app’s public base URL to that HTTPS origin (e.g. `APP_URL`), restart the local server, and clear any config cache.

---

Configuration
-------------

[](#configuration)

### CLI flags

[](#cli-flags)

FlagDescription`--url=URL`Local origin to expose (e.g. `http://127.0.0.1:9000`)`--port=PORT`Local port; host from `HOST` or `127.0.0.1``-h`, `--help`Show help```
vendor/bin/cloudflare-tunnel
vendor/bin/cloudflare-tunnel --port=9000
vendor/bin/cloudflare-tunnel --url=http://127.0.0.1:9000
```

### Environment variables

[](#environment-variables)

VariableDefaultPurpose`TUNNEL_LOCAL_URL`*(auto / default)*Full local origin (highest priority)`HOST` / `PORT``127.0.0.1` / *(unset)*Used when `TUNNEL_LOCAL_URL` / `--url` unset; `PORT` must be set to take this path`TUNNEL_NAME`*(empty)*Named tunnel; alias `CLOUDFLARE_TUNNEL_NAME``CLOUDFLARED_CONFIG``~/.cloudflared/config.yml`Named-tunnel config path`CLOUDFLARED_EXTRA_ARGS`*(empty)*Extra args passed to `cloudflared` (space-separated)```
TUNNEL_LOCAL_URL=http://127.0.0.1:8000 vendor/bin/cloudflare-tunnel
TUNNEL_NAME=my-app vendor/bin/cloudflare-tunnel
```

### Local URL resolution (first match wins)

[](#local-url-resolution-first-match-wins)

The script prints which URL was chosen and why.

PrioritySourceNotes1`TUNNEL_LOCAL_URL`Full URL2`--url=`CLI full URL3`PORT` / `--port=`Host from `HOST` or `127.0.0.1`4Auto-detectHeuristic below5Default`http://127.0.0.1:8000`**Auto-detect:**

1. If `./.env` has `APP_URL=http://127.0.0.1:PORT` or `http://localhost:PORT` (explicit port), use that host/port.
2. Else probe listening ports via `lsof` (or `nc`): **8000**, **8080**, **3000**, **80**.
3. Otherwise fall back to `http://127.0.0.1:8000`.

Port **5173** alone is treated as Vite, not the app — auto-detect does not prefer it as the tunnel target.

### Quick vs named tunnels

[](#quick-vs-named-tunnels)

ModeHowNotes**Quick** (default)No `TUNNEL_NAME`Random `https://….trycloudflare.com`; fine for short-lived OAuth/webhook labs**Named**`TUNNEL_NAME=…`Requires config at `CLOUDFLARED_CONFIG`; DNS/ingress must match your public hostname and local target---

Testing
-------

[](#testing)

This package ships no automated test suite and no dry-run / mock mode for `cloudflared`. Verify changes with the checks below.

### Syntax check

[](#syntax-check)

From the package root:

```
bash -n bin/cloudflare-tunnel
```

Exit `0` means the script parses under Bash.

### Help / missing binary smoke

[](#help--missing-binary-smoke)

```
bin/cloudflare-tunnel --help
# With cloudflared temporarily off PATH, expect a clear install error:
PATH=/usr/bin:/bin bin/cloudflare-tunnel
```

### Manual smoke (end-to-end)

[](#manual-smoke-end-to-end)

1. Start a local HTTP server on a known port (e.g. `php -S 127.0.0.1:8000` or `php artisan serve`).
2. In another terminal: `vendor/bin/cloudflare-tunnel` (or `bin/cloudflare-tunnel --port=8000` from the package tree).
3. Wait for a `https://….trycloudflare.com` URL in the output.
4. Open that URL in a browser and confirm it reaches the local app.
5. Stop with Ctrl+C.

### Optional Composer scripts

[](#optional-composer-scripts)

The package `composer.json` defines no scripts. Consuming projects may add a `tunnel` script (see [Installation](#installation)) and run `composer run tunnel` as a convenience wrapper — that is project-local, not part of this package’s release verification.

---

Why
---

[](#why)

Localhost is enough for most day-to-day work. It is not enough when something on the public internet must call you back:

- OAuth providers that require an `https://` redirect URI
- Webhooks from Stripe, GitHub, Slack, and similar services
- Sharing a WIP page with a teammate or testing on a phone

Alternatives exist. [Herd Expose](https://herd.laravel.com/docs) (`herd share`) is polished for Laravel Herd + Vite. [ngrok](https://ngrok.com/) is widely known and feature-rich. This package is a thin, Composer-installable wrapper around Cloudflare’s free quick tunnel (and optional named tunnels) — useful when you already have (or prefer) `cloudflared`, want a `vendor/bin` entry point, and do not need Herd or an ngrok account for the job.

It does not replace those tools; it is another path with the same job: local app → public HTTPS.

---

How it works
------------

[](#how-it-works)

 ```
flowchart LR
  subgraph local [Your machine]
    App["Local HTTP appe.g. :8000 / :3000"]
    Bin["vendor/bin/cloudflare-tunnel"]
    Cf["cloudflared"]
  end

  subgraph edge [Cloudflare]
    Quick["trycloudflare.comquick tunnel"]
    Named["Named hostnameTUNNEL_NAME + config.yml"]
  end

  Browser["Browser / OAuth / webhook"]

  App -->|"HTTP to local URL"| Cf
  Bin -->|"resolves local URLthen starts"| Cf
  Cf -->|"outbound tunnel"| Quick
  Cf -->|"outbound tunnel"| Named
  Quick -->|"HTTPS"| Browser
  Named -->|"HTTPS"| Browser
```

      Loading 1. The script resolves a **local origin** (env, CLI flags, auto-detect, or default `:8000`).
2. With no `TUNNEL_NAME`, it runs a **quick tunnel** and prints a `https://….trycloudflare.com` URL.
3. With `TUNNEL_NAME` set, it runs that **named tunnel** from `~/.cloudflared/config.yml` (or `CLOUDFLARED_CONFIG`).
4. You point OAuth redirect URIs / webhooks / `APP_URL` at the public HTTPS origin — not `http://localhost`.

---

Use cases
---------

[](#use-cases)

ScenarioWhy a tunnel helpsOAuth callbacksProviders reject `http://localhost` or require HTTPSWebhooksExternal services POST to a reachable URLShare WIPTeammate opens your branch without VPNMobile testingPhone hits the same app over HTTPSLaravel + Google OAuthLab Connect flows need a stable-enough HTTPS `APP_URL`Non-Laravel (Node, etc.)Same bin; no framework coupling---

Laravel notes
-------------

[](#laravel-notes)

This package is **not** Laravel-specific. When you use it with Laravel:

### Avoid `composer run dev` + Vite HMR behind the tunnel

[](#avoid-composer-run-dev--vite-hmr-behind-the-tunnel)

`composer run dev` / `php artisan dev` typically serves the app **and** Vite on `localhost:5173`. The tunnel can reach your app origin, but the browser on `https://….trycloudflare.com` still tries to load assets from `http://localhost:5173` → **mixed content / broken CSS &amp; JS**.

### Recommended flow (OAuth / webhooks)

[](#recommended-flow-oauth--webhooks)

1. Build assets: `npm run build`
2. Serve the app only: `php artisan serve` (or Herd’s PHP site)
3. In another terminal: `vendor/bin/cloudflare-tunnel` (or `composer run tunnel`)
4. Set `APP_URL` to the printed public HTTPS URL, then `php artisan config:clear` and restart the app server
5. Point OAuth redirect URIs at `${APP_URL}/…`

Do **not** fold the tunnel into default `composer run dev`: quick tunnels mint a new hostname every start (breaking `APP_URL` / redirect URIs), and public exposure should stay opt-in.

### Herd alternative

[](#herd-alternative)

Herd users may prefer [`herd share`](https://herd.laravel.com/docs) for Vite-aware public sharing instead of (or alongside) this helper.

---

License
-------

[](#license)

[MIT](./LICENSE) © Solution Forest

###  Health Score

40

—

FairBetter than 86% of packages

Maintenance100

Actively maintained with recent releases

Popularity5

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity42

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~0 days

Total

5

Last Release

0d ago

Major Versions

0.2.2 → 1.0.02026-08-01

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/68211796?v=4)[Solution Forest](/maintainers/solutionforest)[@solutionforest](https://github.com/solutionforest)

---

Top Contributors

[![solutionforestteam](https://avatars.githubusercontent.com/u/53035878?v=4)](https://github.com/solutionforestteam "solutionforestteam (5 commits)")

---

Tags

devoauthwebhookcloudflaretunnelcloudflared

### Embed Badge

![Health badge](/badges/solution-forest-cloudflare-tunnel/health.svg)

```
[![Health](https://phpackages.com/badges/solution-forest-cloudflare-tunnel/health.svg)](https://phpackages.com/packages/solution-forest-cloudflare-tunnel)
```

###  Alternatives

[league/oauth2-server

A lightweight and powerful OAuth 2.0 authorization and resource server library with support for all the core specification grants. This library will allow you to secure your API with OAuth and allow your applications users to approve apps that want to access their data from your API.

6.7k151.3M319](/packages/league-oauth2-server)[league/oauth2-client

OAuth 2.0 Client Library

3.8k132.3M1.4k](/packages/league-oauth2-client)[league/oauth1-client

OAuth 1.0 Client Library

995114.9M125](/packages/league-oauth1-client)[knpuniversity/oauth2-client-bundle

Integration with league/oauth2-client to provide services

84218.9M87](/packages/knpuniversity-oauth2-client-bundle)[socialiteproviders/manager

Easily add new or override built-in providers in Laravel Socialite.

42649.8M602](/packages/socialiteproviders-manager)[league/oauth2-google

Google OAuth 2.0 Client Provider for The PHP League OAuth2-Client

42524.2M188](/packages/league-oauth2-google)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
