Skip to content
Open
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
11 changes: 11 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
name: ci
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with: { go-version: '1.22' }
- run: make test
- run: make build
21 changes: 21 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: release
on:
push:
tags: ['v2*']
permissions:
contents: write
jobs:
goreleaser:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 0 }
- uses: actions/setup-go@v5
with: { go-version: '1.22' }
- run: make test
- uses: goreleaser/goreleaser-action@v6
with:
version: '~> v2'
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,4 @@ examples/**/out/
*.tmp
*.temp
.cache/
/cfex
25 changes: 25 additions & 0 deletions .goreleaser.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
version: 2
project_name: cfex
before:
hooks:
- go mod tidy
builds:
- id: cfex
main: ./cmd/cfex
binary: cfex
env: [CGO_ENABLED=0]
goos: [darwin, linux]
goarch: [amd64, arm64]
ldflags: ["-s -w -X main.version={{.Version}}"]
archives:
- id: cfex
formats: [tar.gz]
name_template: "cfex_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
files: [LICENSE, README.md]
checksum:
name_template: checksums.txt
changelog:
disable: true
release:
extra_files:
- glob: ./install.sh
9 changes: 9 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.PHONY: build test install
build:
go build -o cfex ./cmd/cfex
# The suite is fail-closed: it refuses to run unless CFEX_CONFIG is under the temp dir.
test:
go vet ./...
CFEX_CONFIG=$$(mktemp -d)/config.yaml go test -count=1 ./...
install:
go install ./cmd/cfex
159 changes: 56 additions & 103 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,144 +1,97 @@
# cfex - Cloudflare Exposer CLI
[![Discord](https://img.shields.io/badge/AgentNexus-join%20the%20community-5865F2?logo=discord&logoColor=white)](https://discord.gg/V9C2kvHC8D)

Expose your local services to the internet using your domain names via Cloudflare's tunneling technology. With cfex, you can create instant HTTPS endpoints for any local service without port forwarding or static IPs.
Put a local port on your own domain, over HTTPS, with one command. cfex drives [`cloudflared`](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/) for the tunnels and DNS routes, and manages every tunnel on your machine.

## What is cfex?
> The original bash version is preserved as the [v1.0.0 release](https://github.com/muthuishere/cfex-cli/releases/tag/v1.0.0) (legacy). v2 is the maintained version.

cfex (Cloudflare Exposer CLI) simplifies creating secure tunnels between your local development environment and the internet. It leverages Cloudflare’s tunnel technology to:
- Expose local services via HTTPS endpoints.
- Use custom domain names for development and testing.
- Access your services behind firewalls or NAT.
- Test webhooks and APIs locally without additional setup.
## Instant: `cfex <domain>:<port>`

---
```bash
cfex dev.yourdomain.com:3000 # React/Vue/Angular dev server -> https://dev.yourdomain.com
cfex api.yourdomain.com:8080 # local API server
cfex webhook.yourdomain.com:4000 # webhook testing
cfex api.yourdomain.com 8080 # same thing, two arguments
cfex secure.yourdomain.com:8443 --https [--verify-cert] # HTTPS origin (auto-detected when omitted)
```

## Why cfex?
It runs in the foreground. Press **Ctrl+C**: the tunnel and the DNS record it created are removed. Add `--keep` to make it permanent (same as `cfex add`).

When developing web applications, cfex is useful for:
- **Sharing local development servers**: Share your work with clients or team members.
- **Webhook testing**: Test external integrations directly from your local environment.
- **Accessing local services on mobile**: Use your app on other devices.
- **Demoing features**: Quickly share links for feedback without deploying.
## Durable: `cfex add`

With cfex, you can:
```bash
# Share your React app
cfex dev.yourdomain.com:3000 # https://dev.yourdomain.com

# Expose your API
cfex api.yourdomain.com:8080 # https://api.yourdomain.com

# Test webhooks
cfex webhook.yourdomain.com:4000 # https://webhook.yourdomain.com
cfex add 3000 dev.yourdomain.com # survives reboots (launchd on macOS, systemd user unit on Linux)
cfex add 8080 api.yourdomain.com # many routes share one cfex-owned tunnel
cfex list # EVERYTHING on this machine, with live HTTP status
cfex stop dev.yourdomain.com # stop serving, keep config + DNS (cfex start to resume)
cfex delete dev.yourdomain.com # asks y/N on a terminal; --yes for scripts; no terminal and no --yes = dry run
cfex status | doctor | troubleshoot
cfex import <script|tunnel> # adopt an existing tunnel into the config; serving is not changed
```

---
`add` appends ONE ingress rule to cfex's own tunnel (a pure, unit-tested merge that never touches other routes) and creates the CNAME with `cloudflared tunnel route dns`, which never overwrites an existing record. Changing a route restarts the connector, so routes on that tunnel reconnect for a second or two.

## Quick Start
`list` shows managed routes plus everything else cloudflared-ish here: account tunnels with their ingress rules, launchd jobs, `~/.cloudflared` scripts, live HTTP status. Classes: `managed`, `instant`, `PROTECTED`, `client`, `adopted`, `unmanaged`. Put tunnels you never want touched under `protected:` / `client:` in the config; cfex only stops/deletes what it created.

### Prerequisites
1. **Cloudflare Account with Registered Domain**: [Sign up for free](https://dash.cloudflare.com/).
2. **cloudflared Installed**: [Install cloudflared](https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/installation/).
3. **jq Installed**:
- macOS: `brew install jq`
- Ubuntu/Debian: `sudo apt install jq`
4. **Cloudflare API Token**: [Create API Token](https://dash.cloudflare.com/profile/api-tokens) with:
- Permissions: `Zone-DNS Edit` and `Zone-Read`
- Zone: Include the domain you want to use.
## Install

### Installation
```bash
# Install cfex
curl -sSL https://raw.githubusercontent.com/muthuishere/cfex-cli/main/install.sh | bash
curl -sSL https://github.com/muthuishere/cfex-cli/releases/latest/download/install.sh | bash
```

### Authenticate Cloudflared
Downloads the release binary for your OS/CPU (macOS and Linux, amd64 and arm64), verifies its checksum, installs it to `/usr/local/bin` (or `~/.local/bin`) and installs the agent skill. Binaries and checksums are on the [releases page](https://github.com/muthuishere/cfex-cli/releases). From source: `go install github.com/muthuishere/cfex-cli/cmd/cfex@latest`.

Prerequisites: a Cloudflare account with a domain, and [cloudflared](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/) installed.

### Authenticate cloudflared (once)
```bash
cloudflared tunnel login
```
This command:
- Opens Cloudflare's login page.
- Creates a certificate at `~/.cloudflared/cert.pem`.
Opens Cloudflare's login page: log in, pick the PRIMARY domain you want to tunnel, authorize. This writes `~/.cloudflared/cert.pem`; afterwards you can tunnel any subdomain of that domain. If you forget, cfex starts this guided login for you.

### Set API Token
```bash
export CLOUDFLARE_API_KEY='your-api-token'
```
For persistence:
### API token (optional)
cfex works with cloudflared alone. An API token adds: DNS ownership checks (`managed-by: cfex` stamped on the records it creates), deleting DNS records on `delete`/Ctrl+C cleanup, remote ingress in `list`, and zone validation. `cfex doctor` tells you which features are on.

Create one at <https://dash.cloudflare.com/profile/api-tokens>: *Create Token* → *Edit zone DNS* template → *Zone Resources: Include → Specific zone* → your domain. Then:
```bash
echo 'export CLOUDFLARE_API_KEY="your-api-token"' >> ~/.bashrc # or ~/.zshrc
source ~/.bashrc # or ~/.zshrc
export CLOUDFLARE_API_TOKEN='your-api-token' # CLOUDFLARE_API_KEY also works; add it to ~/.zshrc or ~/.bashrc to persist
```
Or let cfex fetch it from your secret manager: `token_cmd: "op run --"` in the config (cfex re-runs itself under that command; the token only exists in its environment).

---
## Agent skill

## Usage

### Expose Services
```bash
# React/Vue/Angular dev server
cfex dev.yourdomain.com:3000
`cfex skill install` copies [`skills/cfex/SKILL.md`](skills/cfex/SKILL.md) to `~/.claude/skills/cfex` and `~/.agents/skills/cfex`, so coding agents know the commands and the safety rules (`cfex skill uninstall` removes it).

# Local API server
cfex api.yourdomain.com:8080
## Uninstall

# Webhook testing
cfex webhook.yourdomain.com:4000
```

### Manage Tunnels
```bash
# List tunnels
cfex list

# Delete tunnel(s)
cfex delete domain.com

# Show help
cfex --help
cfex uninstall # or ./uninstall.sh
```
Removes the binary and the skill, then asks (default: no) whether to stop the cfex service, remove cfex's config, and remove cloudflared's own files in `~/.cloudflared`. Flags for scripts: `--stop-service --purge-config --purge-cloudflared`. Tunnels and DNS records in your Cloudflare account are never deleted; run `cfex delete` first if you want them gone.

---

## Troubleshooting

1. **Installation Issues**:
- Verify `cloudflared` and `jq` are installed.
- Check permissions for installation directories.

2. **Authentication Issues**:
- Ensure the API token is set and valid.
- Re-run `cloudflared tunnel login` if needed.
## Configuration

3. **DNS Issues**:
- Allow time for DNS propagation.
- Verify domain ownership and permissions.
`~/.config/cfex/config.yaml` (every key optional; see [`config.example.yaml`](config.example.yaml)): `default_zone`, `tunnel_name`, `service_label`, `token_env`, `token_cmd`, `protected`, `client`. State and logs: `~/.local/share/cfex/`.

4. **Connection Issues**:
- Ensure the service is running on the specified port.
- Check for port conflicts or firewall settings.
## Troubleshooting

---
1. **Installation**: verify `cloudflared` is installed (`cfex doctor`); check permissions on the install directory.
2. **Authentication**: re-run `cloudflared tunnel login`; if you use an API token, make sure it is exported and valid.
3. **DNS**: allow time for propagation; make sure the domain is in your Cloudflare account and the hostname has no existing record (cfex never overwrites one).
4. **Connection**: make sure the service is running on the port you gave (cfex warns when nothing listens); check port conflicts and firewalls.

## Platform Support
- **Linux**
- **macOS**
- **Windows** (via WSL):
- Install WSL: `wsl --install` in PowerShell (Admin).
- Restart your computer.
- Follow Linux setup instructions.
## Platform support
- **Linux** and **macOS** (amd64, arm64). The durable service uses systemd (user) and launchd.
- **Windows** via WSL: `wsl --install` in an elevated PowerShell, restart, then follow the Linux steps.

---
## Development
`make build` · `make test` (the suite refuses to run unless `CFEX_CONFIG` points under the temp dir) · releases are built by GoReleaser from a `v2*` tag.

## Alternatives
- **ngrok**: Subscription required for custom domains.
- **LocalTunnel**: Free, but lacks features like DNS management.
- **cloudflared**: The native client that cfex simplifies.

cfex provides a streamlined solution for exposing your local services using Cloudflare, making it ideal for developers working with custom domains and secure tunnels.
- **ngrok**: subscription required for custom domains.
- **LocalTunnel**: free, but lacks DNS management.
- **cloudflared**: the native client that cfex simplifies.

## Community

Questions, ideas, or built something with this? Join **[AgentNexus](https://discord.gg/V9C2kvHC8D)** — a Discord
for people building with AI agents and open tools. This project lives in **#cfex-cli**.
Questions, ideas, or built something with this? Join **[AgentNexus](https://discord.gg/V9C2kvHC8D)**, a Discord for people building with AI agents and open tools. This project lives in **#cfex-cli**.
Loading
Loading