12 min read

Getting Started with Cloudflare Tunnel

Table of Contents

In this guide, you’ll learn how to securely share an application running on your server onto the internet using a Cloudflare Tunnel! This guide has been updated and simplified.

Why Use Cloudflare Tunnel?

  • Share local applications you’ve built with other people
  • Host applications from home servers without port forwarding

Alternatives to Cloudflare Tunnel

  • ngrok is another option, but it requires a paid plan for custom domains and persistent URLs. It’s easy to use but not as flexible as Cloudflare Tunnel. Note that ngrok is no longer open source. You can expect the free plan to be similar to Cloudflare’s TryCloudflare service.
  • tailscale is a popular closed source alternative. I’ve heard good things about it, but I’ve never tried it myself. Tailscale offers a tunnel-like feature that they call a Funnel.
  • headscale is an open-source alternative to Tailscale. You have to host it yourself.
  • pangolin is another open-source alternative. You can host it yourself or pay for their cloud service.

Prerequisites

Before we begin, ensure you have:

  • SSH access to your server
  • A Cloudflare account (free tier works perfectly)
  • A domain name (optional)

Installing cloudflared

Important: Please note it’s called cloudflared (with a ‘d’ at the end). Don’t let it trip you up!

Below are installation instructions for debian-based Linux distros. For other distros or operating systems, check the official Cloudflare documentation. As of this writing, the URL for the official documentation is located here.

  1. Add Cloudflare’s package signing key:
sudo mkdir -p --mode=0755 /usr/share/keyrings
curl -fsSL https://pkg.cloudflare.com/cloudflare-public-v2.gpg | sudo tee /usr/share/keyrings/cloudflare-public-v2.gpg >/dev/null
  1. Add Cloudflare’s repository to apt:
echo "deb [signed-by=/usr/share/keyrings/cloudflare-public-v2.gpg] https://pkg.cloudflare.com/cloudflared any main" | sudo tee /etc/apt/sources.list.d/cloudflared.list
  1. Update your package list and install cloudflared:
sudo apt-get update && sudo apt-get install cloudflared
  1. Verify successful installation:

You should see version information like cloudflared version 2025.x.x confirming successful installation.

cloudflared --version

Explanation:

  • Package signing verification: The signing key ensures you’re installing authentic Cloudflare software, not malware.
  • Repository integration: Adding Cloudflare’s repository to apt allows automatic updates through your usual apt upgrade command.
  • System-wide installation: Places cloudflared in /usr/local/bin/ making it accessible to all users and system services.

Instant Tunnels with TryCloudflare

Cloudflare has two options for setting up a tunnel. We’ll look at the easiest one first. Cloudflare calls this TryCloudflare. You likely won’t be using this for your server because of the reasons below, but it’s good to know about it in case you ever need to spin something up quickly.

Pros

  • No account needed
  • No configuration needed
  • HTTPS by default
  • DDoS protection

Cons

  • Changes to a new random URL every time you restart the tunnel
  • Maximum 200 concurrent request limit
  • No uptime guarantee (Designed for testing only, not production workloads)
  • Server-Sent Events streaming is not supported
  • No persistence (Tunnels disappear when you close the terminal or reboot)

Starting a TryCloudflare Tunnel

cloudflared tunnel --url http://localhost:8080

Cloudflare generates a random URL like https://seasonal-deck-organisms-sf.trycloudflare.com. This URL points to your local application running on port 8080.

Persistent Tunnels

Now we’ll go into persistent tunnels. This is what you’ll want to use for your server. Persistent tunnels require a Cloudflare account and some setup.

Step 1: Custom Domains

To use Cloudflare Tunnel with your own domain, you have two options:

Option A. Full DNS Setup

For full DNS setup, you need to switch your domain’s DNS entirely to Cloudflare. Doing this provides the following benefits:

  • Automatic DNS management: Cloudflare automatically creates and manages DNS records for new tunnels, so you don’t have to manually create DNS records
  • Dashboard: You can use the dashboard on Cloudflare’s website to manage DNS, tunnels, and security policies
  • Global load balancing: Traffic to your application is distributed across multiple servers automatically

Option B. Partial DNS Setup

Important: Partial DNS setup requires a paid Cloudflare plan.

You can use Cloudflare Tunnel with other DNS providers (eg. Namecheap, Porkbun, etc) by manually creating DNS records:

  • DNS record type: CNAME (or ALIAS for root domains)
  • Record name: Your subdomain (e.g., app for app.yourdomain.com)
  • Record value: subdomain.yourdomain.tld.cdn.cloudflare.net

Generally speaking, you’ll want to use the full DNS setup. If you prefer to keep your existing DNS provider, you must manually create DNS records that point to Cloudflare. I assume you will be using the full DNS setup for the rest of this guide.

Step 2: Different Methods to Create Persistent Tunnels

Cloudflare offers two ways to create persistent tunnels: using their online dashboard or using the command line. Note that the online dashboard method still requires you to use the command line, just to a lesser degree.

Option A. Dashboard Method

Pros:

  • Graphical interface: It’s a bit easier for beginners to use.
  • Remote management: Configure and monitor tunnels from anywhere without server access
  • Built-in monitoring: Real-time connection status and traffic analytics

Cons:

  • Doesn’t avoid the terminal: You have to switch back and forth between the browser and the terminal.

Process:

  1. Navigate to Zero Trust dashboard → Networks → Tunnels
  2. Click “Create a tunnel” → Choose “Cloudflared” connector
  3. Name your tunnel (e.g., “production-web-server”, “dev-api-server”)
  4. Copy the provided installation command containing your unique tunnel token
  5. Run the command on your server

Option B. Command Line Method

Pros:

  • Configuration files can be version-controlled with Git
  • More control over tunnel parameters and routing rules

Cons:

  • More setup is needed

Why I prefer the CLI method: I prefer the CLI method because the dashboard approach:

  • Hides important details for understanding how Cloudflare tunnels work
  • Requires switching between terminal and browser
  • Is relatively new and may change

For these reasons, we’ll focus on the command-line interface (CLI) method below.

Step 3: Creating a Tunnel

Authenticate with Cloudflare

cloudflared login
  1. This command will display a URL such as: https://dash.cloudflare.com/argotunnel?callback=....
  2. Open this URL in a browser.
  3. Authenticate by logging into your Cloudflare account and grant tunnel creation permissions.
  4. The cloudflared CLI tool creates a certificate file at ~/.cloudflared/cert.pem.

Security consideration: This certificate authorizes tunnel creation for your Cloudflare account. Treat it like a password.

Create Your Tunnel

  • Create a new tunnel with a descriptive name. This can be used to manage the tunnel later. This creates a JSON file containing tunnel-specific authentication tokens located at ~/.cloudflared/[tunnel-uuid].json. You’ll need this file path later.

    cloudflared tunnel create your-tunnel-name
  • List all tunnels and verify your new tunnel was created. You’ll see a unique identifier (eg. ed5bfe16-cb5f-449c-b2e9-7c300b749c79) for the tunnel. This is the tunnel UUID, which you’ll need later.

    cloudflared tunnel list

Step 4: Server Configuration File (CLI Method)

  • Create a new configuration file with your preferred text editor.

    vim ~/.cloudflared/config.yml
  • From here on out we’ll assume the tunnel UUID is ed5bfe16-cb5f-449c-b2e9-7c300b749c79. Make sure to replace this with your own tunnel UUID in the following steps.

  • Add the following to the config.yml file. The tunnel-UUID is the UUID of the tunnel you created earlier. Change the port in the url to the service you want to exposed to the internet. The credentials-file should point to the absolute path of the JSON file created when you made the tunnel.

    url: http://localhost:8188 # Change to the local service you want to expose
    tunnel: ed5bfe16-cb5f-449c-b2e9-7c300b749c79 # Change to your tunnel UUID
    credentials-file: /home/yourusername/.cloudflared/ed5bfe16-cb5f-449c-b2e9-7c300b749c79.json # Change to your credentials file path

Step 5: Configure the Tunnel DNS Route (CLI Method)

  • Now we’ll link the tunnel to a custom domain or subdomain. The format is cloudflared tunnel route dns <tunnel-uuid-or-name> <hostname>. Replace <tunnel-uuid-or-name> with your tunnel’s UUID or the name you gave it earlier. Replace <hostname> with the domain or subdomain you want to use (eg. app.yourdomain.com).

    cloudflared tunnel route dns ed5bfe16-cb5f-449c-b2e9-7c300b749c79 app.example.com
  • From here on out we’ll assume you’re using app.example.com as your hostname. Make sure to replace this with your own hostname in the following steps.

Explanation:

  • The command creates a CNAME record that points app.yourdomain.com to <tunnel-uuid>.cfargotunnel.com

Step 6: Running the Tunnel

  • Start the tunnel using the configuration file you created earlier. You can use the tunnel UUID or the tunnel name.

    cloudflared tunnel --config ~/.cloudflared/config.yml run ed5bfe16-cb5f-449c-b2e9-7c300b749c79
  • You can also add the loglevel flag for detailed logs.

    cloudflared tunnel --loglevel info --config ~/.cloudflared/config.yml run ed5bfe16-cb5f-449c-b2e9-7c300b749c79
  • If your internet service provider (ISP) doesn’t support QUIC (eg. Shaw Internet in Canada), you will need to specify HTTP/2 protocol instead. QUIC is a new protocol for HTTP/3.

    cloudflared tunnel --protocol http2 --config ~/.cloudflared/config.yml run ed5bfe16-cb5f-449c-b2e9-7c300b749c79
  • Next, go to https://app.example.com in your browser. You should see your local application being served over HTTPS. If this works, pat yourself on the back because you just successfully set up a Cloudflare Tunnel!

Step 7. Check Tunnel Status

  • You can check the tunnel status

    cloudflared tunnel info ed5bfe16-cb5f-449c-b2e9-7c300b749c79
  • You can also monitor live connection logs

    tail -f ~/.cloudflared/cloudflared.log

Troubleshooting

”Failed to create new quic connection”

This could either be because your firewall is blocking one of the ports cloudflared uses, or your ISP is blocking QUIC traffic. If you live in Canada, Shaw Internet blocks QUIC traffic by default as of this writing.

  • If you’re running Ubuntu on your server, it’ll be using UFW (Uncomplicated Firewall) as its firewall by default. Check if UFW is blocking port 7844, which is used by Cloudflare.
sudo ufw status verbose

# If port 7844 is not allowed, run the following to allow it:
sudo ufw allow out 7844/udp
  • To find out if your ISP blocks QUIC, you’ll have to search your ISP’s website. If your ISP is indeed blocking QUIC, you can force cloudflared to use HTTP/2 instead, which is more firewall-friendly.
  • QUIC provides better performance but it’s quite new and some ISPs block it. HTTP/2 over TCP is more universally supported.
# Force HTTP/2 protocol instead of QUIC
cloudflared tunnel --protocol http2 --config ~/.cloudflared/config.yml run your-tunnel-name

”Cannot determine default configuration path”

This may be because you did not specify the path to your configuration file.

# Correct command with explicit config path
cloudflared tunnel --config ~/.cloudflared/config.yml run ed5bfe16-cb5f-449c-b2e9-7c300b749c79

Quick Reference

Tunnel Commands

  • Run an existing tunnel over HTTP/2.
    cloudflared tunnel --protocol http2 --config ~/.cloudflared/config.yml run <Tunnel-UUID>
  • Lists all tunnels.
    cloudflared tunnel list
  • Find what port a tunnel is running on.
    cloudflared tunnel info <Tunnel-UUID>
  • Create a tunnel.
    cloudflared tunnel create <name>
  • Delete a tunnel.
    cloudflared tunnel delete <name>
  • Add a DNS record to a tunnel.
    cloudflared tunnel route dns <Tunnel-UUID> <hostname>
  • Remove a DNS record from a tunnel.
    cloudflared tunnel route remove <Tunnel-UUID> <hostname>

Restricting Access to Your Tunnel

One feature of Cloudflare tunnels I find particularly useful is being able to restrict access to your tunnel without configuring authentication on your local application.

You set this up inside the Cloudflare dashboard.

You can restrict access to your tunnel in different ways:

  • Restrict via OTP (One-Time Password) login handled by Cloudflare
  • Restrict to certain IP addresses
  • Restrict to certain geographical locations (not covered here)
  • Restrict via Cloudflare Access Groups (not covered here)

For instance, you have application A that you want to demo to client A and you have application B that you want to demo to client B. You don’t want to spend time setting up authentication since they’re just demo applications, but you do want them to be restricted to the intended client. You can point application A to a.example.com and application B to b.example.com. You then set an OTP access policy on a.example.com that only allows client A’s email address and another for b.example.com.

Setting up access restrictions

These instructions are accurate as of November 2025, but Cloudflare’s dashboard may change.

  • Go to the dashboard on Cloudflare’s website.
  • Go to the Zero Trust dashboard: https://one.dash.cloudflare.com
  • Click “Access” then “Applications”
  • Click “Add an application” then select “Self-hosted”
  • Fill out the following in the “Configure Application” form:
    • Application name: your-tunnel-name
    • Session Duration: 24 hours
      • This is how long users can stay logged in before needing to re-authenticate.
    • Application domain: app.yourdomain.com
    • Leave everything else as default.
  • Now fill out the following in the “Add Policies” form:
    • Policy name: your-tunnel-name
    • Selector:
      • Email: Enable email OTP login. “Value” would be the you allow access to the tunnel.
      • IP Ranges: Enable IP allowlisting. “Value” would be the IP addresses.