npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@kyndlo/cftunnel

v1.0.0

Published

CLI + library to manage Cloudflare Tunnels, ingress routes, and DNS records for AI agents

Downloads

131

Readme

cftunnel

A CLI + library to manage Cloudflare Tunnel traffic routing, built for AI agents to programmatically expose local services to the internet.

Built with the official Cloudflare Node.js SDK and Commander.js.

Overview

cftunnel lets you create Cloudflare Tunnels, configure ingress routes (hostname-to-service mappings), manage DNS records, and run cloudflared -- all from a single CLI that outputs JSON for easy parsing by AI agents and scripts. It also exports every operation as a library function for direct use in Node.js/TypeScript code.

What it does

Internet → Cloudflare Edge → Cloudflare Tunnel → cloudflared → localhost:PORT
              (DNS CNAME)      (ingress route)     (connector)   (your app)
  1. Tunnel - A secure outbound-only connection from your machine to Cloudflare's edge
  2. Ingress Route - Maps a public hostname to a local service (e.g. app.example.comhttp://localhost:3000)
  3. DNS CNAME - Points your domain at the tunnel (app.example.com<tunnel-id>.cfargotunnel.com)
  4. cloudflared - The connector daemon that maintains the tunnel connection

Installation

npx (zero-install)

npx cftunnel tunnel list

Global install

npm i -g cftunnel

As a library

npm i cftunnel

Prerequisites

  • Node.js >= 18
  • A Cloudflare account with a registered domain
  • A Cloudflare API Key + account email, or an API Token with these permissions:
    • Account > Cloudflare Tunnel > Edit
    • Zone > DNS > Edit
  • cloudflared installed (the run command will auto-detect from PATH or use the cloudflared npm package)

Getting your credentials

| Credential | Where to find it | |---|---| | API Key | Cloudflare Dashboard → My Profile → API Tokens → Global API Key | | API Token | Cloudflare Dashboard → My Profile → API Tokens → Create Token | | Account ID | Cloudflare Dashboard → any domain → Overview → right sidebar | | Zone ID | Cloudflare Dashboard → your domain → Overview → right sidebar | | Email | The email address on your Cloudflare account |

Authentication

cftunnel supports two auth methods:

API Token (Bearer auth)

export CLOUDFLARE_API_TOKEN=your-api-token
# or
npx cftunnel tunnel list --api-token your-api-token

API Key + Email (Global key auth)

export CLOUDFLARE_API_KEY=your-api-key
export [email protected]
# or
npx cftunnel tunnel list --api-key your-api-key --api-email [email protected]

Account ID

Required for all tunnel operations:

export CLOUDFLARE_ACCOUNT_ID=your-account-id
# or
npx cftunnel tunnel list --account-id your-account-id

CLI Commands

Quickstart (all-in-one)

Create a tunnel, configure routing, set up DNS, and get the run token in a single command:

npx cftunnel quickstart \
  --name my-app \
  --hostname app.example.com \
  --service http://localhost:8080 \
  --zone-id your-zone-id

Output:

{
  "tunnel_id": "uuid",
  "tunnel_name": "my-app",
  "hostname": "app.example.com",
  "service": "http://localhost:8080",
  "dns_record": "record-id",
  "token": "eyJ...",
  "run_cmd": "cloudflared tunnel run --token eyJ...",
  "install_cmd": "sudo cloudflared service install eyJ..."
}

Tunnel Management

# Create a new tunnel
npx cftunnel tunnel create my-tunnel
npx cftunnel tunnel create my-tunnel --config-src local

# List all tunnels
npx cftunnel tunnel list
npx cftunnel tunnel list --name my-tunnel

# Get tunnel details
npx cftunnel tunnel get <tunnel-id>

# Delete a tunnel
npx cftunnel tunnel delete <tunnel-id>

# Get the cloudflared run token
npx cftunnel tunnel token <tunnel-id>

Ingress Route Management

Ingress routes control how traffic arriving at the tunnel is forwarded to local services.

# List current routes
npx cftunnel route list <tunnel-id>

# Add a route (appends before the catch-all 404)
npx cftunnel route add <tunnel-id> --hostname app.example.com --service http://localhost:8080
npx cftunnel route add <tunnel-id> --hostname api.example.com --service http://localhost:3000 --path "/v1/*"

# Remove a route by hostname
npx cftunnel route remove <tunnel-id> --hostname app.example.com

# Replace all routes at once
npx cftunnel route set <tunnel-id> \
  --route app.example.com=http://localhost:8080 \
  --route api.example.com=http://localhost:3000

Supported service protocols: http://, https://, unix://, tcp://, ssh://, rdp://, unix+tls://, smb://, http_status:<code>

DNS Management

# Create a CNAME record pointing to a tunnel
npx cftunnel dns create --zone-id <zone-id> --hostname app.example.com --tunnel-id <tunnel-id>

# List DNS records for a zone
npx cftunnel dns list --zone-id <zone-id>

# Delete a DNS record
npx cftunnel dns delete <record-id> --zone-id <zone-id>

Run cloudflared

# Run cloudflared in the foreground
npx cftunnel run <tunnel-id>

# Install cloudflared as a system service (persists across reboots)
npx cftunnel run <tunnel-id> --install-service

Library API

Every CLI operation is also available as a library function:

import {
  createClient,
  createTunnel,
  listTunnels,
  getTunnel,
  deleteTunnel,
  getTunnelToken,
  listRoutes,
  addRoute,
  removeRoute,
  setRoutes,
  createDNS,
  listDNS,
  deleteDNS,
  quickstart,
} from 'cftunnel';

// Create a client (reads from env vars if no opts provided)
const client = createClient({ apiKey: '...', apiEmail: '...' });

// Create a tunnel
const tunnel = await createTunnel(client, {
  accountId: '...',
  name: 'my-app',
});

// Add a route
await addRoute(client, {
  accountId: '...',
  tunnelId: tunnel.id,
  hostname: 'app.example.com',
  service: 'http://localhost:3000',
});

// Create DNS
await createDNS(client, {
  zoneId: '...',
  hostname: 'app.example.com',
  tunnelId: tunnel.id,
});

// Or do it all at once
const result = await quickstart(client, {
  accountId: '...',
  name: 'my-app',
  hostname: 'app.example.com',
  service: 'http://localhost:3000',
  zoneId: '...',
  onProgress: (msg) => console.error(msg),
});
console.log(result.run_cmd);

End-to-End Examples

Expose a local web app

# 1. Start your app
python3 -m http.server 3000 &

# 2. Set credentials
export CLOUDFLARE_API_KEY=your-key
export [email protected]
export CLOUDFLARE_ACCOUNT_ID=your-account-id

# 3. One-shot setup
npx cftunnel quickstart \
  --name web-app \
  --hostname app.example.com \
  --service http://localhost:3000 \
  --zone-id your-zone-id

# 4. Run the tunnel connector
npx cftunnel run <tunnel-id-from-output>

# Site is now live at https://app.example.com

Add a second service to an existing tunnel

# Add API backend on a subdomain
npx cftunnel route add <tunnel-id> \
  --hostname api.example.com \
  --service http://localhost:4000

# Create DNS for it
npx cftunnel dns create \
  --zone-id <zone-id> \
  --hostname api.example.com \
  --tunnel-id <tunnel-id>

Multiple services on one tunnel

npx cftunnel route set <tunnel-id> \
  --route app.example.com=http://localhost:3000 \
  --route api.example.com=http://localhost:4000 \
  --route admin.example.com=http://localhost:5000

Output Format

All commands output JSON to stdout. Status/progress messages go to stderr. This makes it easy to parse output programmatically:

# Get tunnel ID from create output
TUNNEL_ID=$(npx cftunnel tunnel create my-app | jq -r '.id')

# Get the run token
TOKEN=$(npx cftunnel tunnel token $TUNNEL_ID | jq -r '.token')

# Run it
cloudflared tunnel run --token $TOKEN

Global Flags

| Flag | Env Var | Description | |---|---|---| | --api-token | CLOUDFLARE_API_TOKEN | Cloudflare API token (bearer auth) | | --api-key | CLOUDFLARE_API_KEY | Cloudflare API key (requires --api-email) | | --api-email | CLOUDFLARE_EMAIL | Cloudflare account email | | --account-id | CLOUDFLARE_ACCOUNT_ID | Cloudflare account ID |

Architecture

cftunnel/
├── src/
│   ├── index.ts              # Library exports (public API)
│   ├── cli.ts                # CLI entry point (commander setup)
│   ├── client.ts             # Cloudflare client factory + auth
│   ├── utils.ts              # printJSON, exitError, parseRoute
│   ├── commands/
│   │   ├── tunnel.ts         # CLI: tunnel create/list/get/delete/token
│   │   ├── route.ts          # CLI: route list/add/remove/set
│   │   ├── dns.ts            # CLI: dns create/list/delete
│   │   ├── run.ts            # CLI: run cloudflared
│   │   └── quickstart.ts     # CLI: all-in-one
│   └── lib/
│       ├── types.ts          # All interfaces
│       ├── tunnel.ts         # Core: tunnel operations
│       ├── route.ts          # Core: ingress route operations + merge helpers
│       ├── dns.ts            # Core: DNS operations
│       └── quickstart.ts     # Core: quickstart orchestration
├── package.json
├── tsconfig.json
└── tsup.config.ts

Built on:

License

MIT