Setting up a Cloudflare Zero Trust Tunnel

Learn how to securely expose your self-hosted server to the public internet using Cloudflare Zero Trust Tunnels with this beginner-friendly guide.

đź‘€ my LinkedIn
Riley Hilliard
Riley Hilliard · Director of High Fives
5 min read ·
Copied to clipboard
Setting up a Cloudflare Zero Trust Tunnel

* My Security Before a Zero Trust Tunnel

Self-hosting is empowering, but exposing your server to the public internet can feel like leaving your front door wide open. Enter Cloudflare Zero Trust Tunnels—a secure, outbound-only connection that eliminates the need for open ports or complex firewall rules. In this guide, we’ll walk you through setting up a Cloudflare Tunnel using cloudflared, so you can safely share your services with the world.

Why Use Cloudflare Zero Trust Tunnels?

Before diving into the setup, let’s explore why you might want to setup a Cloudflare Zero Trust Tunnel:

FeatureBenefit
No Open PortsKeeps your server hidden from attackers by eliminating inbound connections
Encrypted TrafficEnsures all data is secure in transit
Simplified SetupNo need for complex NAT or firewall rules
Dynamic DNS ManagementAutomatically adapts to IP changes
Granular Access ControlRestrict access based on identity or device posture

Step-by-Step Guide to Setting Up a Cloudflare Tunnel

Prerequisites

Before starting, ensure you have the following:

  1. A free Cloudflare account.
  2. Ownership of a domain with nameservers pointed to Cloudflare’s DNS.
  3. A self-hosted service running locally (e.g., a web app on http://localhost:3000).
  4. cloudflared installed on your server.

To install cloudflared, run:

On Debian/Ubuntu

sudo apt update && sudo apt install -y cloudflared

On Fedora Asahi Remix on Apple Silicon

Download the latest cloudflared RPM package for your architecture from the Cloudflare GitHub Releases page:

wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-aarch64.rpm

Install the package using dnf:

sudo dnf install ./cloudflared-linux-aarch64.rpm

Verify the installation:

cloudflared --version

On MacOS

Install cloudflared via Homebrew:

brew install cloudflare/cloudflare/cloudflared

Create a Tunnel

  1. Log in to the Cloudflare Zero Trust Dashboard.
  2. Navigate to Zero Trust > Access > Tunnels and click Create a Tunnel.
  3. Name your tunnel (e.g., my-tunnel) and save it.

Cloudflare will provide you with a token for authentication.

Configure and Run the Tunnel

On your server, authenticate and create the tunnel:

cloudflared tunnel login
cloudflared tunnel create my-tunnel

This generates a credentials file (e.g., ~/.cloudflared/<UUID>.json) used to securely connect to Cloudflare.

Next, create a configuration file: ~/.cloudflared/config.yml

tunnel: # <UUID>, the same UUID as the credentials file (~/.cloudflared/<UUID>.json)
credentials-file: # path to the credentials file, eg /home/user/.cloudflared/<UUID>.json

ingress:
  - hostname: # domain entering the tunnel, eg workhub.so
    service:  # local machine port of the service that should be exposed, eg http://localhost:3000
  
  # An example of a catch-all rule:
  - service: http_status:404

A more realistic looking config file might look like this:

tunnel: 123-456-789-10987-654321
credentials-file: /root/.cloudflared/123-456-789-10987-654321.json

ingress:
  - hostname: workhub.so
    service:  http://localhost:3000
  
  - service: http_status:404

Start the tunnel:

cloudflared tunnel run my-tunnel

Set Up DNS

In the Cloudflare dashboard:

  1. Go to DNS settings for your domain.
  2. Add a CNAME record pointing your-domain.com to <UUID>.cfargotunnel.com.

Your service is now accessible at https://your-domain.com.

Advanced Features

Granular Access Control

Enhance security by enabling Zero Trust policies:

  1. In the Cloudflare Zero Trust dashboard, navigate to Access > Applications.
  2. Add an application and configure policies (e.g., Google authentication or one-time PINs).

Run as a Service

By following these steps, your Cloudflare Tunnel will automatically reconnect after a reboot, ensuring uninterrupted access to your self-hosted services in the event of a system restart:

macOS

sudo cloudflared service install --system
sudo launchctl load /Library/LaunchDaemons/com.cloudflare.cloudflared.plist

Check logs for troubleshooting:

  • Errors: tail -f /Library/Logs/com.cloudflare.cloudflared.err.log
  • Output: tail -f /Library/Logs/com.cloudflare.cloudflared.out.log

Linux

cloudflared service install
sudo systemctl start cloudflared
sudo systemctl enable cloudflared

Check the status of the service: sudo systemctl status cloudflared

To restart the service after configuration changes, use: sudo systemctl restart cloudflared

Troubleshooting

If you encounter issues, give the following a try:

  • Check DNS: Triple check that the DNS record for your domain/subdomain points correctly to your tunnel. For example, a CNAME record should point to <Tunnel-UUID>.cfargotunnel.com.
  • Check Firewall: Ensure that outbound traffic from your server is not blocked by a firewall: ping 8.8.8.8 and/or curl https://www.cloudflare.com from the host machine
  • Run with Debug: Run cloudflared with debug logging enabled: cloudflared tunnel -- loglevel debug run <tunnel-name> and look for any warnings or errors indicating connectivity issues
  • Verify Ports: Verify that your router allows outbound connections on required ports (e.g., TCP/UDP port 7844 for QUIC).
  • Check Config: Double check your config.yml has the right entries:
ingress:
  - hostname: <the same domain/subdomain in your CNAME entry>
    service: <the exact address your services lives at, for example https://localhost:3000>
  • Restart Services: Restart both cloudflared and your origin service: sudo systemctl restart cloudflared
  • Check Logs in Cloudflare: Inspect Cloudflare Dashboard Logs: In the Cloudflare dashboard, check for logs under “Zero Trust” → “Access” → “Logs” for any blocked requests or errors.
  • Test with No-TLS Mode: Temporarily disable TLS between Cloudflare and your origin by setting the service to HTTP in the ingress rule.
# config.yml
. . . add this . . . 
    originRequest:
      noTLSVerify: true
IssuePossible Fix
TimeoutCheck local service accessibility and router/firewall rules
ERR_CONNECTION_REFUSEDVerify DNS configuration and ensure the service is running
SSL/TLS ErrorsEnable no-tls-verify or configure valid SSL certificates
Service Bound to localhostUpdate service binding to an accessible IP (e.g., 0.0.0.0)
Tunnel Not ReconnectingAdd automatic restart settings (restart: always) if using Docker

Final Thoughts

With Cloudflare Zero Trust Tunnels, you can securely expose self-hosted services without compromising security or performance. Whether you’re hosting a personal blog or testing an internal app, this solution simplifies connectivity while keeping threats at bay.

About the Author

đź‘€ my LinkedIn Riley Hilliard
Riley Hilliard
Director of High Fives

At 13, I secretly drilled holes in my parents' wood floor to route a 56k modem line to my bedroom for late-night Age of Empires marathons. That same scrappy curiosity carried through 3 acquisitions, 9 years as a LinkedIn Staff Engineer building infrastructure for 1B+ users, and now fuels my side projects, like WorkHub.so.

Copied to clipboard

🎯 More Awesome Content Headed Your Way!

If you enjoyed this article, these fresh picks might be right up your alley!

Looking for an amazing place to work or study? We've got you covered.

Nice work, you made it to the bottom! Give that scrolling finger a break by clicking one last link below — you’ve earned it!

WorkHub will always be free

Discover the best places to work or study, complete with all the details you need to get started.

  • Find coffee shops and public spaces near you
  • Discover cozy places to work or study
  • View amenities like WiFi speeds, power outlets, and more
Give it a try!