Pyflared is a CLI tool for creating and managing Cloudflare Tunnels. No more manual token juggling or complex configurations β just simple commands to expose your local services to the internet. It also works as a Python library!
- π Quick Tunnels β Spin up instant, temporary public URLs for local services with a single command
- π DNS-Mapped Tunnels β Create persistent tunnels with automatic DNS record management
- π§Ή Automatic Cleanup β Orphan tunnel and stale DNS record detection & removal
- π SSH over Cloudflare β Expose and connect to SSH servers through Cloudflare Tunnels
- ποΈ Token Management β Store and manage multiple Cloudflare API tokens locally
- π¦ Batteries Included β Bundles the
cloudflaredbinary, no separate installation required - π³ Docker Ready β Run as a container with minimal setup
uv tool install pyflaredpip install pyflareddocker pull ghcr.io/azmainmahatab/pyflared:latest
docker run --rm ghcr.io/azmainmahatab/pyflared --helpExpose a local service instantly with a temporary trycloudflare.com URL:
pyflared tunnel quick 8000This creates a public URL (e.g., https://random-name.trycloudflare.com) pointing to localhost:8000.
Create a persistent tunnel with your own domain:
pyflared tunnel mapped api.example.com=localhost:8000 web.example.com=localhost:3000This will:
- Create a new Cloudflare Tunnel
- Configure DNS records for your domains
- Route traffic to your local services
Note: Requires a Cloudflare API token with tunnel and DNS permissions. Set via
CLOUDFLARE_API_TOKENenvironment variable or enter when prompted.
Remove stale tunnels and DNS records left behind by pyflared:
pyflared tunnel cleanupServe your local SSH daemon through a Cloudflare Tunnel:
pyflared ssh serve ssh.example.comConnect to it from another machine:
pyflared ssh connect user@ssh.example.compyflared --helpShow the bundled cloudflared version.
Create a quick tunnel to a local service with a temporary trycloudflare.com URL.
| Option | Description |
|---|---|
--verbose -v |
Show detailed cloudflared logs |
Create DNS-mapped tunnel(s). See Mapping Format for all supported DOMAIN=SERVICE syntaxes.
| Option | Description |
|---|---|
--tunnel-name -n |
Custom tunnel name (default: auto-generated). See Tunnel Naming Behavior |
--force -f |
Take over DNS from other tunnels even if named |
--verbose -v |
Show detailed cloudflared logs |
Remove orphan tunnels and DNS records.
| Option | Description |
|---|---|
--all -a |
Delete ALL tunnels and DNS records, not just orphans |
--force -f |
Bypass confirmation prompt when deleting all resources |
--verbose -v |
Show detailed cloudflared logs |
Expose local SSH server through a Cloudflare Tunnel.
| Option | Description |
|---|---|
--tunnel-name -n |
Custom tunnel name. See Tunnel Naming Behavior |
--force -f |
Take over DNS from other tunnels even if named |
--verbose -v |
Show detailed cloudflared logs |
Add a Cloudflare SSH host entry to your ~/.ssh/config.
Remove a previously added SSH config entry.
Connect to a remote host using SSH through Cloudflare. Extra SSH arguments are passed through.
ProxyCommand helper for use in ~/.ssh/config:
Host myhost
ProxyCommand pyflared ssh proxy %h
List all stored Cloudflare API tokens.
Add a new API token (prompts securely for the token value).
Remove a stored token by its friendly name.
Remove all stored tokens.
The --tunnel-name / -n flag on tunnel mapped and ssh serve controls the tunnel lifecycle:
Without --tunnel-name (default) |
With --tunnel-name |
|
|---|---|---|
| Lifecycle | Ephemeral β tunnel and DNS records are automatically deleted on shutdown (Ctrl+C) | Persistent β tunnel and DNS records are preserved across runs |
| Next run | A brand-new tunnel is created every time | Reuses the existing tunnel if the same name exists |
| DNS protection | None β DNS records are disposable | Named tunnels protect their DNS records from being claimed by other tunnel setups |
| Force override | N/A | Use --force / -f to override DNS owned by another named tunnel |
Tip: Use unnamed tunnels for development and quick testing. Use named tunnels for long-lived services where you want DNS stability and protection across restarts.
The DOMAIN=SERVICE pairs used in tunnel mapped support a variety of formats.
# Port only β inferred as http://localhost:<port>
pyflared tunnel mapped app.com=8000
# Host and port
pyflared tunnel mapped app.com=localhost:3000
# Explicit scheme
pyflared tunnel mapped app.com=http://backend:9000
pyflared tunnel mapped secure.com=https://localhost:443# Route a subdomain path to a specific backend path
pyflared tunnel mapped app.com/api=localhost:8000
# Port with backend path
pyflared tunnel mapped api.com=8000/v1/apiWell-known ports are automatically mapped to the correct protocol:
# SSH (port 22) β ssh://
pyflared tunnel mapped ssh.example.com=22
# PostgreSQL (5432), Redis (6379), MongoDB (27017) β tcp://
pyflared tunnel mapped db.com=5432
pyflared tunnel mapped redis.com=6379pyflared tunnel mapped sock.com=/var/run/app.sock| Syntax | Behavior |
|---|---|
https://localhost:443 |
Auto-disables TLS verification (local backend) |
https://backend:443?verify_tls=false |
Explicitly disable TLS verification |
https://localhost?verify_tls=true |
Force TLS verification even for localhost |
https://backend:443?verify_tls=api.internal.com |
Verify against a custom server name |
# Cloudflare built-in test page
pyflared tunnel mapped test.com=hello_world
# HTTP status code response
pyflared tunnel mapped app.com=http_status:404
# Bastion mode (SSH browser rendering)
pyflared tunnel mapped bastion.com=bastion| Variable | Description |
|---|---|
CLOUDFLARE_API_TOKEN |
Your Cloudflare API token for tunnel management |
For DNS-mapped tunnels, your API token needs the following permissions:
- Account > Cloudflare Tunnel > Edit
- Zone > DNS > Edit
If you see an Error 525 page ("SSL handshake failed") immediately after creating a tunnel, don't worryβthis is a temporary issue. Cloudflare's edge network may take a few moments to fully propagate the tunnel configuration.
What to do: Simply wait 1-2 minutes and refresh the page. The error will resolve automatically once the tunnel is fully established.
- Python 3.12+
- Hatch
git clone https://github.com/AzmainMahatab/pyflared.git
cd pyflared
hatch env createhatch testhatch run types:checkhatch buildPyflared is distributed under the terms of the MPL-2.0 license.
- cloudflared β The official Cloudflare Tunnel client
- Typer β CLI framework
Made with β€οΈ by Azmain Mahatab