2 Cloudflared Tunnel Setup Guide

How to securely expose local services to the world through Cloudflare tunnels โ€” no port forwarding, no static IP, no problem.

Table of Contents


๐Ÿ“– Overview

Cloudflared creates secure tunnels to expose your local services to the internet through Cloudflare's network. This guide covers installation, tunnel creation, and configuration.


โš™๏ธ Step 0: Download Cloudflared

macOS

Install via Homebrew:

brew install cloudflared

Alternative: Download the latest release directly:

Windows

Install via winget:

winget install --id Cloudflare.cloudflared

Alternative: Download the latest release directly:

Type 32-bit 64-bit
Executable Download Download
Important

Instances of cloudflared do not automatically update on Windows. You will need to perform manual updates.

Docker

A Docker image of cloudflared is available on DockerHub.


๐Ÿชœ Step 1: Create & Route Your Tunnel

Important for Windows Users

Navigate to the cloudflared.exe directory and use it with .\cloudflared.exe instead of cloudflared:

cd path/to/cloudflared.exe

Tunnel Setup Commands

# Authenticate and obtain your cert.pem
cloudflared tunnel login

# Create a locally-managed tunnel named 'tunnel-name'
cloudflared tunnel create tunnel-name

# Check list of tunnels
cloudflared tunnel list

# Provision DNS CNAME for demo.kunj.dev โ†’ your tunnel
cloudflared tunnel route dns tunnel-name demo.kunj.dev

What These Commands Do

  1. cloudflared tunnel login โ€” Opens browser for Cloudflare authentication and downloads cert.pem
  2. cloudflared tunnel create tunnel-name โ€” Creates tunnel and generates credentials JSON file
  3. cloudflared tunnel list โ€” Shows all your created tunnels
  4. cloudflared tunnel route dns tunnel-name demo.kunj.dev โ€” Automatically adds CNAME record in Cloudflare DNS

Storage Location:


๐Ÿชœ Step 2: Prepare Host Configuration

Create Directory Structure

mkdir -p ./cloudflared

Copy Credentials File

Copy your <UUID>.json into ./cloudflared/ directory (you can rename it if desired).

Create Configuration File

Create ./cloudflared/config.yml with the following contents:

tunnel: <YOUR_TUNNEL_UUID>
credentials-file: /etc/cloudflared/<YOUR_TUNNEL_UUID>.json

ingress:
  - hostname: demo.kunj.dev        # Domain to route all traffic through tunnel
    service: http://localhost:3000    # Your local running service URL
  - service: http_status:404          # Return 404 for all other hosts

Configuration Explanation


๐Ÿชœ Step 3: Run Tunnel

Using Specific Config File

# To use specific tunnel config (e.g., tunnel-name.yml)
cloudflared tunnel --config /path/to/tunnel/tunnel-name.yml run

Using Default Config

# For default config (config.yml)
cloudflared tunnel run tunnel-name

๐Ÿ“ Complete Configuration Examples

Example 1: Single Service

File: ./cloudflared/config.yml

tunnel: abc123-def456-ghi789
credentials-file: /etc/cloudflared/abc123-def456-ghi789.json

ingress:
  - hostname: app.kunj.dev
    service: http://localhost:3000
  - service: http_status:404

Example 2: Multiple Services

File: ./cloudflared/config.yml

tunnel: abc123-def456-ghi789
credentials-file: /etc/cloudflared/abc123-def456-ghi789.json

ingress:
  - hostname: api.kunj.dev
    service: http://localhost:5000
  - hostname: app.kunj.dev
    service: http://localhost:3000
  - hostname: admin.kunj.dev
    service: http://localhost:8080
  - service: http_status:404

Example 3: Docker Service

File: ./cloudflared/config.yml

tunnel: abc123-def456-ghi789
credentials-file: /etc/cloudflared/abc123-def456-ghi789.json

ingress:
  - hostname: n8n.kunj.dev
    service: http://n8n:5678    # Docker service name
  - service: http_status:404

โš™๏ธ Docker Compose Integration

docker-compose.yml

version: '3.8'

services:
  cloudflared:
    image: cloudflare/cloudflared:latest
    container_name: cloudflared-tunnel
    command: tunnel --no-autoupdate run
    environment:
      - TUNNEL_TOKEN=${TUNNEL_TOKEN}
    restart: unless-stopped
    networks:
      - app-network

  app:
    image: your-app:latest
    container_name: your-app
    ports:
      - "3000:3000"
    networks:
      - app-network

networks:
  app-network:
    driver: bridge

Alternative: Using Config File in Docker

version: '3.8'

services:
  cloudflared:
    image: cloudflare/cloudflared:latest
    container_name: cloudflared-tunnel
    command: tunnel --config /etc/cloudflared/config.yml run
    volumes:
      - ./cloudflared:/etc/cloudflared
    restart: unless-stopped
    networks:
      - app-network

networks:
  app-network:
    driver: bridge

๐Ÿ“‹ Tunnel Management Commands

Essential Commands

# List all tunnels
cloudflared tunnel list

# Delete a tunnel
cloudflared tunnel delete tunnel-name

# Run tunnel with specific config
cloudflared tunnel --config /path/to/config.yml run

# Run tunnel in background (Linux/macOS)
nohup cloudflared tunnel run tunnel-name &

# Check tunnel info
cloudflared tunnel info tunnel-name

# Clean up tunnel connections
cloudflared tunnel cleanup tunnel-name

โš™๏ธ Running as a Service

Linux (systemd)

Create service file: /etc/systemd/system/cloudflared.service

[Unit]
Description=Cloudflare Tunnel
After=network.target

[Service]
Type=simple
User=root
ExecStart=/usr/local/bin/cloudflared tunnel --config /root/.cloudflared/config.yml run
Restart=on-failure
RestartSec=5s

[Install]
WantedBy=multi-user.target

Enable and start service:

sudo systemctl enable cloudflared
sudo systemctl start cloudflared
sudo systemctl status cloudflared

macOS (launchd)

Create plist file: ~/Library/LaunchAgents/com.cloudflare.cloudflared.plist

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.cloudflare.cloudflared</string>
    <key>ProgramArguments</key>
    <array>
        <string>/opt/homebrew/bin/cloudflared</string>
        <string>tunnel</string>
        <string>run</string>
        <string>tunnel-name</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <true/>
</dict>
</plist>

Load the service:

launchctl load ~/Library/LaunchAgents/com.cloudflare.cloudflared.plist
launchctl start com.cloudflare.cloudflared

Windows (Service)

# Install as Windows service
cloudflared service install

# Start the service
cloudflared service start

# Stop the service
cloudflared service stop

# Uninstall the service
cloudflared service uninstall

๐Ÿ› Troubleshooting

Common Issues

Issue: Tunnel not connecting

# Check tunnel status
cloudflared tunnel info tunnel-name

# View logs
cloudflared tunnel --loglevel debug run tunnel-name

Issue: DNS not resolving

# Verify DNS routing
cloudflared tunnel route dns tunnel-name demo.kunj.dev

# Check Cloudflare DNS settings in dashboard

Issue: Service not accessible

# Verify local service is running
curl http://localhost:3000

# Check config.yml ingress rules
# Ensure hostname and service URL are correct

Viewing Logs

# Basic logs
cloudflared tunnel run tunnel-name

# Debug logs
cloudflared tunnel --loglevel debug run tunnel-name

# For systemd (Linux)
sudo journalctl -u cloudflared -f

# For Docker
docker logs -f cloudflared-tunnel

๐Ÿ”’ Security Best Practices

  1. Protect credentials file โ€” Set proper permissions:

    chmod 600 ~/.cloudflared/<UUID>.json
    
  2. Use specific hostnames โ€” Don't use wildcards unless necessary

  3. Implement authentication โ€” Use Cloudflare Access for additional security layer

  4. Regular updates โ€” Keep cloudflared updated (especially on Windows)

  5. Monitor logs โ€” Regularly check tunnel logs for suspicious activity


๐Ÿ“‹ Quick Reference

Installation

# macOS
brew install cloudflared

# Windows
winget install --id Cloudflare.cloudflared

Setup

cloudflared tunnel login
cloudflared tunnel create tunnel-name
cloudflared tunnel route dns tunnel-name demo.kunj.dev

Run

cloudflared tunnel run tunnel-name

Management

cloudflared tunnel list
cloudflared tunnel info tunnel-name
cloudflared tunnel delete tunnel-name

๐Ÿ“ Real-World Use Cases

Use Case 1: Expose Local Development Server

Perfect for showing clients your work-in-progress without deploying.

ingress:
  - hostname: dev.kunj.dev
    service: http://localhost:3000
  - service: http_status:404

Use Case 2: Self-Hosted Services (n8n, Grafana, etc.)

ingress:
  - hostname: n8n.kunj.dev
    service: http://localhost:5678
  - hostname: grafana.kunj.dev
    service: http://localhost:3001
  - service: http_status:404

Use Case 3: IoT Device Access

ingress:
  - hostname: homeassistant.kunj.dev
    service: http://192.168.1.100:8123
  - service: http_status:404

๐Ÿ“– Additional Resources