tunnelflare
v0.0.6
Published
A configurable Cloudflare Tunnel system for local development with branch-aware URLs.
Downloads
95
Maintainers
Readme
Tunnelflare
A configurable Cloudflare Tunnel system for local development with branch-aware URLs. Think ngrok, but with Vercel-style preview URLs and zero runtime costs.
Features
- 🚀 Branch-aware URLs: Automatic hostnames like
web-feature-auth-myrepo.example.com - 🏗️ Monorepo & Flat Repo Support: Works with both workspace-based monorepos and single-package repositories
- ⚙️ Zero Runtime Dependencies: Compiled Rust binary, no Node.js or other runtime required
- 📦 Self-contained: Credentials and config live in your repo
- 🎯 Package.json Driven: All configuration via
package.json, no separate config files - 💰 Free: Uses Cloudflare's free tier, no bandwidth costs
Installation
npm install -g tunnelflare
# or
pnpm add -g tunnelflare
# or
yarn global add tunnelflareYou'll also need cloudflared installed. The tool will provide OS-specific installation instructions if it's missing.
Quick Start
1. Install cloudflared
If you don't have cloudflared installed, the tool will show you how to install it for your OS.
2. Configure your project
You can either manually add tunnelflare configuration to your root package.json, or let the tool set it up automatically (see Automatic Setup below).
Manual configuration:
{
"tunnelflare": {
"tunnel": "local-dev",
"rootHostname": "example.com",
"credentialsFile": ".tunnelflare/your-tunnel-id.json"
}
}Or skip this step - the tool will guide you through setup on first run!
3. Enable for workspaces
For each workspace/package you want to expose, add "tunnelflare": true:
{
"name": "@myapp/web",
"tunnelflare": true,
"scripts": {
"dev": "next dev"
}
}Port Detection: The tool automatically detects the port from your dev script (looks for PORT=3000 pattern). No manual port configuration needed!
4. Run
tunnelflareThe tool will:
- Auto-detect your git branch and repo name
- Generate hostnames like
web-main-myrepo.example.com - Start the tunnel and share your services
Configuration
Root Package.json
All fields are required for the tool to run, but if any are missing, the tool will automatically guide you through setup.
{
"tunnelflare": {
"tunnel": "local-dev", // Required: Cloudflare tunnel name
"rootHostname": "example.com", // Required: Your domain
"credentialsFile": ".tunnelflare/..." // Required: Path to credentials JSON (relative to project root)
}
}Note: If credentialsFile is not specified, the tool will automatically create a tunnel, copy credentials to your project, and update this field during the setup flow.
Workspace Package.json
Simple (auto-generated hostname):
{
"tunnelflare": true
}Custom hostname:
{
"tunnelflare": {
"hostname": "api.example.com"
}
}Custom port (override auto-detection):
{
"tunnelflare": {
"port": 8080
}
}Note: Ports are automatically detected from your dev script (e.g., PORT=3000 next dev). Only specify a port manually if:
- Your dev script doesn't use the
PORT=format - You want to override the detected port
Automatic Setup
If configuration is incomplete, tunnelflare will guide you through setup:
- Checks if
cloudflaredis installed - Prompts for Cloudflare login (if needed)
- Creates a new tunnel (or uses existing)
- Copies credentials to your project
- Prompts for root hostname
- Updates
package.jsonautomatically
Hostname Generation
Hostnames follow the pattern: ${name}-${branch}-${repo}.${rootHostname}
name: Package name (with scope removed)branch: Git branch name (slashes replaced with dashes)repo: Repository namerootHostname: Your configured domain
Example:
- Package:
@myapp/web - Branch:
feature/auth - Repo:
myapp - Root:
example.com - Result:
web-feature-auth-myapp.example.com
Monorepo Support
Works with any monorepo structure that uses package.json workspaces:
{
"workspaces": ["apps/*", "packages/*"]
}Each workspace can independently enable tunnelflare.
Flat Repository Support
For single-package repositories, add "tunnelflare": true to your root package.json:
{
"name": "my-app",
"tunnelflare": true,
"scripts": {
"dev": "PORT=3000 next dev"
}
}Building from Source
If you want to build from source or contribute:
# Install Rust (if not already installed)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Clone the repository
git clone https://github.com/yourusername/tunnelflare.git
cd tunnelflare
# Build the binary
cargo build --release
# The binary will be at target/release/tunnelflare
# (or target/release/tunnelflare.exe on Windows)Cross-platform Building
Build for specific platforms:
# Linux
cargo build --release --target x86_64-unknown-linux-gnu
# macOS (Intel)
cargo build --release --target x86_64-apple-darwin
# macOS (ARM/Apple Silicon)
cargo build --release --target aarch64-apple-darwin
# Windows
cargo build --release --target x86_64-pc-windows-msvcDNS Setup
Since tunnelflare generates dynamic hostnames (e.g., web-feature-auth-myrepo.example.com), you need to configure DNS in Cloudflare to route traffic to your tunnel.
Option 1: Wildcard DNS (Recommended)
Create a wildcard CNAME record in Cloudflare DNS that points to your tunnel:
- Go to your Cloudflare dashboard → DNS
- Add a new record:
- Type: CNAME
- Name:
*(wildcard) - Target:
<your-tunnel-id>.cfargotunnel.com(replace with your actual tunnel ID) - Proxy status: Proxied (orange cloud)
Alternatively, you can use the cloudflared CLI to create the DNS route:
cloudflared tunnel route dns <tunnel-name> "*.<your-domain>"This allows any subdomain under your domain to work automatically.
Option 2: Manual DNS Records
For each specific hostname, create individual CNAME records. This is not practical for dynamic hostnames, so the wildcard approach is recommended.
Note: The tool doesn't automatically create DNS records. You'll need to set this up once in your Cloudflare dashboard. After that, all generated hostnames will work automatically.
Requirements
cloudflaredCLI installed (the tool will help you install it)- Cloudflare account (free tier works)
- A domain configured in Cloudflare DNS
- Wildcard DNS record (
*.yourdomain.com) pointing to your tunnel (see DNS Setup above) - Rust toolchain (only needed for building from source)
Multi-Tenant Application Development
Tunnelflare supports multi-tenant applications through a built-in proxy server that extracts tenant identifiers from hostnames and routes requests accordingly.
Use Case
When developing multi-tenant applications, you often need to test different tenants using subdomains like:
tenant1.web-feature-auth-myrepo.example.comtenant2.web-feature-auth-myrepo.example.com
The proxy mode enables this by:
- Generating a wildcard hostname pattern (
*.web-feature-auth-myrepo.example.com) - Starting a local proxy server that extracts the tenant from the hostname
- Routing requests to your application with tenant information in headers
Configuration
Enable proxy mode in a workspace's package.json:
{
"name": "@myapp/web",
"tunnelflare": {
"proxy": true
},
"scripts": {
"dev": "PORT=3000 next dev"
}
}You can also specify a custom proxy port:
{
"tunnelflare": {
"proxy": {
"port": 9999
}
}
}How It Works
Wildcard Hostname: When
proxy: trueis set, tunnelflare generates a wildcard hostname pattern like*.web-feature-auth-myrepo.example.cominstead of a specific hostname.Proxy Server: A local HTTP proxy server starts on the configured port (default: 9999) that:
- Listens for incoming requests from Cloudflare Tunnel
- Extracts the tenant identifier from the first subdomain (e.g.,
tenant1fromtenant1.web-feature-auth-myrepo.example.com) - Forwards the request to your application's actual port (e.g.,
localhost:3000)
Tenant Headers: The proxy adds the following headers to help your application identify the tenant:
X-Tenant: The extracted tenant identifierX-Forwarded-Host: The original hostname
Example
With the configuration above, requests to:
tenant1.web-feature-auth-myrepo.example.com→ Proxy extractstenant1, forwards tolocalhost:3000withX-Tenant: tenant1tenant2.web-feature-auth-myrepo.example.com→ Proxy extractstenant2, forwards tolocalhost:3000withX-Tenant: tenant2
DNS Setup
For multi-tenant applications, you'll need a wildcard DNS record:
# Using cloudflared CLI
cloudflared tunnel route dns <tunnel-name> "*.example.com"Or manually create a CNAME record:
- Type: CNAME
- Name:
*(wildcard) - Target:
<your-tunnel-id>.cfargotunnel.com - Proxy status: Proxied
Application Integration
In your application, read the tenant from the X-Tenant header:
// Express.js example
app.use((req, res, next) => {
const tenant = req.headers['x-tenant'];
req.tenant = tenant; // Use tenant for data isolation, etc.
next();
});Limitations
- Each workspace with
proxy: truegets its own proxy server instance - The proxy extracts the tenant from the first subdomain only
- Proxy servers run in the background and shut down when tunnelflare exits
