Skip to content

david-arteaga/cl-tunnel

Repository files navigation

Cloudflare Quick Tunnel CLI (cl-tunnel)

A thin, opinionated wrapper around cloudflared to quickly manage ingress rules for a single Cloudflare Tunnel and map subdomains to local services.

Quick example

Assuming you’ve initialized the CLI with example.com:

Map api.example.com to http://localhost:3000 (supports http and web socket traffic by default):

cl-tunnel add api 3000

You can then access: https://api.example.com (after DNS propagation) which will be proxied to http://localhost:3000.

Note: Only single-level subdomains are supported (e.g., api.example.com). Nested subdomains like dev.api.example.com are not supported because Cloudflare only issues default SSL certs for one-level subdomains.

Installation

1. Prerequisites

  1. Install cloudflared (or see Cloudflare docs)
brew install cloudflared
  1. Login
cloudflared tunnel login
  1. Create a tunnel
cloudflared tunnel create <tunnel-name>

Example:

cloudflared tunnel create local-dev-mac-tunnel
  • This will create the required credentials file and write your Cloudflare Tunnel config under ~/.cloudflared/.

2. Install the CLI

Install via npm/yarn/pnpm/yarn (global)

npm install -g cl-tunnel

This package ships a single-file Bun-compiled executable at dist/cl-tunnel and exposes it via the npm bin field.

3. macOS service install (one-time)

Run the CLI to install and patch the cloudflared launch agent so it runs the tunnel reliably on macOS login:

cl-tunnel install-service

What this does:

  • Runs cloudflared service install which creates ~/Library/LaunchAgents/com.cloudflare.cloudflared.plist.
  • Patches the plist to execute cloudflared tunnel run (not just cloudflared), then restarts the launch agent.

Why the patch? There’s a long-standing macOS issue where the service may start without tunnel run. See the discussion here: cloudflared issue #327.

If you prefer Cloudflare’s official guidance on running as a service, refer to Cloudflare’s official guidance on running as a service.

4. Initialize the CLI config

Tell cl-tunnel which root domain you’ll be using for subdomains:

cl-tunnel init <your-root-domain>
# example:
cl-tunnel init example.com

This writes ~/.cl-tunnel/config.json with your domain. The CLI will combine this with your cloudflared config to manage ingress.

Usage

Map subdomains to local ports

  • Add a mapping: creates/updates an ingress rule and a DNS record for the subdomain.
cl-tunnel add <subdomain> <port>
# example: api.example.com -> http://localhost:3000
cl-tunnel add api 3000

# overwrite existing mapping if it exists
cl-tunnel add api 4000 --force
  • List mappings:
cl-tunnel list
  • Remove a mapping (removes the ingress rule; DNS removal is not yet automated):
cl-tunnel remove <subdomain>

What cl-tunnel add does (under the hood)

When you run cl-tunnel add <subdomain> <port>, the CLI performs the following steps:

  • Reads CLI config ~/.cl-tunnel/config.json to get your root domain (e.g., example.com).
  • Reads Cloudflare Tunnel config ~/.cloudflared/config.yml and validates its shape.
  • Appends or updates an ingress rule in ~/.cloudflared/config.yml:
    • Adds hostname: <subdomain>.<domain> with service: http://localhost:<port>
    • Sorts rules (hostnamed rules first, alphabetically) and de-duplicates by hostname
    • Keeps your fallback rule (e.g., - service: http_status:404) last
  • Writes the updated YAML back to ~/.cloudflared/config.yml.
  • Validates the config using cloudflared:
cloudflared tunnel ingress validate
  • If validation fails, the CLI restores the previous file contents (rollback) and exits.
  • Creates a DNS route for the subdomain to your tunnel UUID from the config:
cloudflared tunnel route dns <tunnel-uuid> <subdomain>
  • If DNS routing fails, the CLI restores the previous config and exits.
  • Restarts the macOS launch agent to apply changes:
launchctl kickstart -k gui/$(id - u)/com.cloudflare.cloudflared
  • If restart fails, the CLI restores the previous config, then restarts again to return to the prior state.

Notes:

  • DNS record removal is not automated by remove yet.

Helpful Cloudflare docs

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published