Skip to main content

Command Palette

Search for a command to run...

From Localhost to Global: Expose Your Development Server to the Internet with Cloudflare Tunnel

Updated
11 min read
From Localhost to Global: Expose Your Development Server to the Internet with Cloudflare Tunnel

Ever found yourself in one of these situations?

  • "Can you check my website?" but your app is running on localhost:3000

  • Need to test webhooks from external services but they can't reach your local machine

  • Want to show a client your work-in-progress without deploying to production

  • Working with a team and need to share your local development environment

Traditional solutions like ngrok work, but they're limited, expensive for permanent use, and give you random URLs that change every time. What if I told you there's a free, permanent solution that gives you a professional domain and enterprise-grade security?

Meet Cloudflare Tunnel – your gateway to making any localhost application accessible from anywhere in the world, with a custom domain, HTTPS, and zero configuration headaches.

What is Cloudflare Tunnel?

Cloudflare Tunnel creates a secure, outbound-only connection from your machine to Cloudflare's global network. Instead of opening ports on your router or dealing with dynamic IPs, the tunnel connects from inside your network to Cloudflare, which then serves your application to the world.

Think of it as a secure bridge between your localhost and the internet, with Cloudflare handling all the networking complexity.

Why Choose Cloudflare Tunnel Over Alternatives?

FeatureCloudflare Tunnelngrok (Free)Port Forwarding
Custom Domain✅ Your domain❌ Random URLs✅ Your domain
Permanent URLs✅ Never changes❌ Changes each restart✅ Static
HTTPS/SSL✅ Automatic✅ Basic⚠️ Manual setup
No Router Config✅ Works anywhere✅ Works anywhere❌ Complex setup
Multiple Services✅ Unlimited❌ 1 tunnel (free)✅ Multiple ports
Cost✅ Free✅ Free (limited)✅ Free
DDoS Protection✅ Enterprise grade❌ Basic❌ None
Bandwidth✅ Unlimited⚠️ Limited✅ Unlimited

Prerequisites

Before we begin, you'll need:

  • A domain name (can be purchased from Namecheap, Google Domains, etc.)

  • A free Cloudflare account

  • Your development application running locally

  • Basic command-line knowledge

Note: You can use any subdomain of your existing domain – no need to buy a separate one!

Step 1: Set Up Your Domain in Cloudflare

Add Your Domain to Cloudflare

  1. Sign up for a free Cloudflare account at cloudflare.com

  2. Add your domain:

    • Click "Add Site" in the dashboard

    • Enter your domain name (e.g., mydomain.com)

    • Choose the Free plan

  3. Update nameservers:

    • Cloudflare will provide you with nameservers

    • Go to your domain registrar (where you bought the domain)

    • Replace the existing nameservers with Cloudflare's

    • Wait for propagation (5 minutes to 24 hours)

Verify Domain Connection

Once your domain is active in Cloudflare, you'll see a green checkmark and can proceed to the next step.

Step 2: Install Cloudflare Tunnel (cloudflared)

On macOS

# Using Homebrew
brew install cloudflared

# Or download directly
curl -fsSL https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-darwin-amd64.tgz -o cloudflared.tgz
tar -xzf cloudflared.tgz
sudo mv cloudflared /usr/local/bin/

On Ubuntu/Debian Linux

# Download the .deb package
curl -fsSL https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb -o cloudflared.deb

# Install
sudo dpkg -i cloudflared.deb

On Windows

  1. Download cloudflared-windows-amd64.exe from the GitHub releases page

  2. Rename it to cloudflared.exe

  3. Move it to a directory in your PATH, or run from the download location

Verify Installation

cloudflared --version

You should see output like: cloudflared version 2025.8.1

Step 3: Authenticate with Cloudflare

Run the authentication command:

cloudflared tunnel login

This will:

  1. Open a browser window

  2. Prompt you to log into Cloudflare

  3. Ask you to select your domain

  4. Save authentication credentials to your machine

Success message: You'll see "You have successfully logged in" and credentials will be saved to ~/.cloudflared/cert.pem (macOS/Linux) or %USERPROFILE%\.cloudflared\cert.pem (Windows).

Step 4: Create Your First Tunnel

Create the Tunnel

cloudflared tunnel create my-dev-tunnel

Output example:

Tunnel credentials written to /Users/yourname/.cloudflared/12345678-abcd-1234-efgh-123456789012.json
Created tunnel my-dev-tunnel with id 12345678-abcd-1234-efgh-123456789012

Important: Save that tunnel ID! You'll need it for configuration.

Create Configuration File

Create a configuration file at ~/.cloudflared/config.yml (macOS/Linux) or %USERPROFILE%\.cloudflared\config.yml (Windows):

tunnel: 12345678-abcd-1234-efgh-123456789012
credentials-file: /Users/yourname/.cloudflared/12345678-abcd-1234-efgh-123456789012.json

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

Configuration explained:

  • tunnel: Your tunnel ID from the previous step

  • credentials-file: Path to the JSON file created

  • hostname: The subdomain you want to use

  • service: Your local application URL

  • The final service: http_status:404 catches all other requests

Step 5: Configure DNS

Link your subdomain to the tunnel:

cloudflared tunnel route dns my-dev-tunnel dev.yourdomain.com

This automatically creates a CNAME record in your Cloudflare DNS pointing dev.yourdomain.com to your tunnel.

Step 6: Start Your Local Application

Make sure your development server is running. Here are common examples:

Here you need to create your own service. As i’m providing only command to start the services of different web services during local development mode.

React Development Server

npm start
# Usually runs on http://localhost:3000

Next.js Development Server

npm run dev
# Usually runs on http://localhost:3000

Node.js/Express Server

node server.js
# Check your app's documentation for the port

Python Flask

flask run
# Usually runs on http://localhost:5000

Python Django

python manage.py runserver
# Usually runs on http://localhost:8000

Step 7: Run the Tunnel

Start your tunnel:

cloudflared tunnel run my-dev-tunnel

Success! Your localhost application is now accessible at https://dev.yourdomain.com 🎉

What Happens Behind the Scenes

  1. Outbound Connection: Your machine connects to Cloudflare (no inbound ports needed)

  2. DNS Resolution: dev.yourdomain.com resolves to Cloudflare's servers

  3. Traffic Routing: Cloudflare routes requests through the tunnel to your localhost

  4. SSL Termination: Cloudflare handles HTTPS automatically

  5. Response: Your local app responds, and Cloudflare serves it globally

Advanced Configurations

Multiple Applications on Different Subdomains

You can expose multiple localhost services with one tunnel:

tunnel: 12345678-abcd-1234-efgh-123456789012
credentials-file: /Users/yourname/.cloudflared/12345678-abcd-1234-efgh-123456789012.json

ingress:
  - hostname: api.yourdomain.com
    service: http://localhost:3001
  - hostname: frontend.yourdomain.com
    service: http://localhost:3000
  - hostname: admin.yourdomain.com
    service: http://localhost:4000
  - service: http_status:404

Path-Based Routing

Route different paths to different local services:

tunnel: 12345678-abcd-1234-efgh-123456789012
credentials-file: /Users/yourname/.cloudflared/12345678-abcd-1234-efgh-123456789012.json

ingress:
  - hostname: dev.yourdomain.com
    path: /api/*
    service: http://localhost:3001
  - hostname: dev.yourdomain.com
    path: /admin/*
    service: http://localhost:4000
  - hostname: dev.yourdomain.com
    service: http://localhost:3000
  - service: http_status:404

Custom Headers

Add custom headers for debugging or authentication:

tunnel: 12345678-abcd-1234-efgh-123456789012
credentials-file: /Users/yourname/.cloudflared/12345678-abcd-1234-efgh-123456789012.json

ingress:
  - hostname: dev.yourdomain.com
    service: http://localhost:3000
    originRequest:
      httpHeaderHost: dev.yourdomain.com
      httpHeaderFields:
        X-Forwarded-For: $CF_CONNECTING_IP
        X-Original-URL: $CF_RAY
  - service: http_status:404

Running Tunnel as a Background Service

On macOS/Linux

Install as a system service:

sudo cloudflared service install
sudo systemctl enable cloudflared
sudo systemctl start cloudflared

On Windows

Install as a Windows service:

cloudflared service install

Benefits of Running as a Service

  • Auto-start: Tunnel starts automatically when your computer boots

  • Background operation: Runs without keeping a terminal window open

  • Reliability: Automatically restarts if it crashes

  • System integration: Managed like other system services

Use Cases and Practical Examples

1. Client Demos and Reviews

Scenario: You're a freelance developer showing work to a client.

# config.yml for client demo
tunnel: your-tunnel-id
credentials-file: /path/to/credentials.json

ingress:
  - hostname: client-demo.yourdomain.com
    service: http://localhost:3000
  - service: http_status:404

Benefits:

  • Professional domain instead of localhost:3000

  • Client can access from anywhere

  • HTTPS by default (builds trust)

  • No need to deploy unfinished work

2. Webhook Development and Testing

Scenario: Testing Stripe webhooks, GitHub webhooks, or any external service that needs to reach your local app.

# config.yml for webhook testing
tunnel: your-tunnel-id
credentials-file: /path/to/credentials.json

ingress:
  - hostname: webhooks.yourdomain.com
    service: http://localhost:4000
  - service: http_status:404

Usage:

# Your webhook endpoint becomes:
# https://webhooks.yourdomain.com/stripe-webhook
# Instead of: http://localhost:4000/stripe-webhook

3. Team Development and Testing

Scenario: Multiple developers need to test the same backend API or frontend.

# config.yml for team development
tunnel: your-tunnel-id
credentials-file: /path/to/credentials.json

ingress:
  - hostname: team-api.yourdomain.com
    service: http://localhost:8080
  - hostname: team-frontend.yourdomain.com
    service: http://localhost:3000
  - service: http_status:404

4. Mobile App Development

Scenario: Testing your API with a mobile app that can't access localhost.

# config.yml for mobile testing
tunnel: your-tunnel-id
credentials-file: /path/to/credentials.json

ingress:
  - hostname: mobile-api.yourdomain.com
    service: http://localhost:5000
  - service: http_status:404

Security Considerations

Network Security

Pros:

  • No inbound ports opened on your router

  • Outbound-only connections (more secure)

  • Cloudflare's DDoS protection

  • Automatic HTTPS/TLS encryption

⚠️ Considerations:

  • Your development app is now public (add authentication if needed)

  • Environment variables and secrets should be properly managed

  • Consider IP restrictions for sensitive applications

Access Control

For sensitive development environments, add basic authentication:

// Example: Express.js with basic auth
const express = require('express');
const basicAuth = require('express-basic-auth');

const app = express();

// Add basic authentication
app.use(basicAuth({
    users: { 'dev': 'password123' },
    challenge: true
}));

// Your app routes
app.get('/', (req, res) => {
    res.send('Hello World!');
});

app.listen(3000);

IP Restrictions

Limit access to specific IP addresses:

# config.yml with IP restrictions
tunnel: your-tunnel-id
credentials-file: /path/to/credentials.json

ingress:
  - hostname: secure-dev.yourdomain.com
    service: http://localhost:3000
    originRequest:
      ipRules:
        - ip: 192.168.1.100/32
          action: allow
        - ip: 0.0.0.0/0
          action: deny
  - service: http_status:404

Troubleshooting Common Issues

Connection Refused

Error: dial tcp 127.0.0.1:3000: connect: connection refused

Solutions:

  1. Verify your local app is running: curl http://localhost:3000

  2. Check the port number in your config

  3. Make sure your app binds to 0.0.0.0:3000 not just 127.0.0.1:3000

DNS Not Propagating

Error: dns: no such host

Solutions:

  1. Wait up to 24 hours for DNS propagation

  2. Check DNS with: nslookup dev.yourdomain.com

  3. Verify CNAME record exists in Cloudflare DNS

  4. Try accessing from a different network or use a VPN

Tunnel Authentication Issues

Error: failed to request Cloudflare Tunnel connection

Solutions:

  1. Re-run cloudflared tunnel login

  2. Check credentials file path in config.yml

  3. Verify tunnel ID is correct

  4. Ensure domain ownership in Cloudflare

SSL Certificate Errors

Error: Certificate warnings in browser

Solutions:

  1. Set Cloudflare SSL mode to "Full" or "Flexible"

  2. Wait a few minutes for SSL provisioning

  3. Clear browser cache

  4. Check that you're using https:// not http://

Performance Optimization

Reduce Latency

  1. Choose Closest Cloudflare Data Center: Cloudflare automatically routes to the nearest location

  2. Enable Argo Smart Routing (paid feature): Routes traffic via fastest paths

  3. Use HTTP/2: Cloudflare enables this automatically

  4. Enable Brotli Compression: Available in Cloudflare dashboard

Optimize for Development

# Development-optimized config
tunnel: your-tunnel-id
credentials-file: /path/to/credentials.json

ingress:
  - hostname: dev.yourdomain.com
    service: http://localhost:3000
    originRequest:
      connectTimeout: 30s
      tlsTimeout: 30s
      tcpKeepAlive: 30s
      keepAliveTimeout: 90s
  - service: http_status:404

Monitoring and Logs

View Tunnel Status

Check if your tunnel is running:

# List all tunnels
cloudflared tunnel list

# Show tunnel info
cloudflared tunnel info my-dev-tunnel

# View tunnel logs
cloudflared tunnel --loglevel debug run my-dev-tunnel

Cloudflare Analytics

Access detailed analytics in your Cloudflare dashboard:

  • Traffic volume: Requests per day/hour

  • Response codes: Success/error rates

  • Geographic distribution: Where your users are located

  • Bandwidth usage: Data transfer statistics

Cost Comparison

SolutionSetup TimeMonthly CostCustom DomainHTTPSBandwidth
Cloudflare Tunnel10 minutesFreeUnlimited
ngrok Pro2 minutes$8-$20Limited
Serveo1 minuteFreeLimited
Port Forwarding30+ minutesISP costsManualISP limited

Best Practices

Development Workflow

  1. Separate Tunnels for Different Projects: Create individual tunnels for each project

  2. Use Descriptive Subdomains: api-v2.yourdomain.com instead of test.yourdomain.com

  3. Version Your Configurations: Keep config files in version control

  4. Document Team Access: Share tunnel URLs with team members

Configuration Management

# Organize multiple tunnel configs
mkdir ~/.cloudflared/projects/
mkdir ~/.cloudflared/projects/ecommerce/
mkdir ~/.cloudflared/projects/blog/

# Use project-specific configs
cloudflared tunnel --config ~/.cloudflared/projects/ecommerce/config.yml run ecommerce-tunnel

Environment-Specific Domains

# Development
dev-api.yourdomain.com -> localhost:3000

# Staging  
staging-api.yourdomain.com -> localhost:3001

# Feature branches
feature-auth.yourdomain.com -> localhost:3002

Conclusion

Cloudflare Tunnel transforms localhost development from a local-only experience to a globally accessible, production-like environment. Whether you're:

  • Sharing work with clients without deploying half-finished features

  • Testing webhooks from external services

  • Collaborating with remote team members on localhost applications

  • Developing mobile apps that need to connect to your local API

  • Learning web development and want to show friends your projects

This setup provides enterprise-grade features (custom domains, HTTPS, global CDN, DDoS protection) at zero cost, with a setup time of just 10 minutes.

The days of "works on my machine" are over. With Cloudflare Tunnel, your machine works everywhere.

Quick Setup Summary

# 1. Install cloudflared
brew install cloudflared  # or download for your OS

# 2. Authenticate  
cloudflared tunnel login

# 3. Create tunnel
cloudflared tunnel create my-tunnel

# 4. Configure DNS
cloudflared tunnel route dns my-tunnel dev.yourdomain.com  

# 5. Run tunnel
cloudflared tunnel run my-tunnel

Total time: Under 10 minutes
Total cost: $0
Result: Professional localhost hosting with your custom domain

Ready to make your localhost globally accessible? Your development workflow will never be the same! 🚀


Have questions about specific frameworks or need help with advanced tunnel configurations? Drop a comment below or connect with me on social media. Happy tunneling!