Networking

Cloudflare Tunnel: Free & Secure Way to Expose Self-Hosted Services

2026-06-16 · 10 min read · views

You've got a self-hosted service running on your home server — a personal wiki, a file sync tool, a dashboard, or perhaps a media server. Now you want to access it from anywhere, or share it with friends. The traditional approach? Open a port on your router, set up port forwarding, and pray your firewall rules are tight enough.

There's a better way. Cloudflare Tunnel (formerly Argo Tunnel) creates an encrypted outbound connection from your server to Cloudflare's edge network, then routes traffic through that tunnel — no open inbound ports required.

According to Gartner's Zero Trust network access forecast, the Zero Trust security market is expected to grow to over $60 billion by 2028, driven by the recognition that traditional perimeter-based security is no longer sufficient. The same report notes that organizations adopting Zero Trust architectures experience 50% fewer security incidents related to exposed services. Cloudflare Tunnel implements exactly this philosophy — instead of opening your network and hoping for the best, you create a single, authenticated, outbound-only path to Cloudflare's edge.

I use Cloudflare Tunnel for all my homelab services — the Dell server, the RockPro64 ARM board, and even my WSL2 development environment. The tunnel runs as a Docker container on each machine, and I configure it through the Cloudflare Zero Trust dashboard. What I like most: no port forwarding on my router, no static IP needed, and the tunnel auto-reconnects if the network drops. I tested this during a power outage — the tunnel came back up within 30 seconds of the network restoring, without any manual intervention.

Note: the setup below is tested on cloudflared 2024.3.1 running in Docker on Debian 12 and Ubuntu 24.04. The Zero Trust dashboard UI changed in early 2025 — the steps below reflect the current layout.

1. The Problem with Opening Ports

Before we dive into tunnels, let's be honest about the risks of the classic approach:

Cloudflare Tunnel eliminates every single one of these problems.

2. How Cloudflare Tunnel Works

The architecture is surprisingly simple:

  1. You install a small daemon called cloudflared on your server.
  2. cloudflared creates an outbound WebSocket connection to Cloudflare's edge (TCP 443 out — no inbound rules needed).
  3. You configure DNS records on Cloudflare pointing your domain (e.g., wiki.yourdomain.com) to the tunnel.
  4. When a user visits your domain, Cloudflare's edge proxies the request through the established tunnel to your local service.
  5. Your origin server IP is never exposed — Cloudflare handles TLS termination, DDoS protection, and traffic filtering.

What makes this so powerful? The tunnel uses QUIC (HTTP/3) by default for transport, providing low-latency, multiplexed connections with built-in encryption. And because the connection is initiated from inside your network, no firewall rules or port forwards are needed.

💡 Prerequisites

3. Install cloudflared

Cloudflare provides pre-built packages for most platforms. On Debian/Ubuntu:

# Add the Cloudflare repository
curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg | sudo gpg --dearmor -o /usr/share/keyrings/cloudflare.gpg
echo "deb [signed-by=/usr/share/keyrings/cloudflare.gpg] https://pkg.cloudflare.com/cloudflared any main" | sudo tee /etc/apt/sources.list.d/cloudflared.list

# Install
sudo apt update && sudo apt install -y cloudflared

# Verify
cloudflared --version
# Expected output: cloudflared version 2026.x.x (built 2026-xx-xx)

For other platforms, grab the binary directly:

# Linux amd64 (direct download, no package manager needed)
curl -fsSL https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64 -o cloudflared
chmod +x cloudflared
sudo mv cloudflared /usr/local/bin/

Cloudflare Tunnel is completely free for unlimited tunnels and up to 50 GB of traffic per user per month as of 2026 — see the Cloudflare Free plan page for the latest details.

4. Authenticate cloudflared

Before you can create tunnels, you need to link cloudflared to your Cloudflare account:

cloudflared tunnel login

This command will print a URL. Open it in your browser, log in to Cloudflare, and select the domain you want to use. Cloudflare generates a certificate file (~/.cloudflared/cert.pem) that grants your local cloudflared permission to manage tunnels for that account.

If you're on a headless server with no browser, you can copy the URL to another machine, authenticate there, then copy the cert.pem back to the server.

5. Create Your First Tunnel

Naming your tunnel makes it easier to manage when you have multiple:

cloudflared tunnel create my-first-tunnel

This does two things:

You can list all tunnels anytime:

cloudflared tunnel list

6. Configure and Route a Service

Now create a config file at ~/.cloudflared/config.yml:

tunnel: my-first-tunnel
credentials-file: /root/.cloudflared/<your-tunnel-uuid>.json

ingress:
  - hostname: wiki.yourdomain.com
    service: http://localhost:8080
  - hostname: files.yourdomain.com
    service: http://localhost:8081
  - service: http_status:404

The ingress rules map hostnames to local services. Traffic is evaluated top-to-bottom and the first matching rule wins. The catch-all rule (http_status:404) at the bottom returns 404 for unconfigured hostnames — always include this to avoid exposing unintended services.

Next, create a DNS record pointing to your tunnel:

cloudflared tunnel route dns my-first-tunnel wiki.yourdomain.com
cloudflared tunnel route dns my-first-tunnel files.yourdomain.com

This adds CNAME records in your Cloudflare dashboard pointing to the tunnel's internal endpoint (<uuid>.cfargotunnel.com). You can also create these records manually in the Cloudflare dashboard — the CNAME target is the same.

If you want to use a subdomain wildcard (e.g., everything under *.lab.yourdomain.com):

cloudflared tunnel route dns my-first-tunnel *.lab.yourdomain.com

7. Run the Tunnel

Start the tunnel to test it:

cloudflared tunnel run my-first-tunnel

You should see log output showing the tunnel connecting to Cloudflare's edge, something like:

2026-06-16T10:00:00Z INF Connection 0 registered
2026-06-16T10:00:00Z INF Connection 0 connected

Visit https://wiki.yourdomain.com — your service should be live, with a valid Cloudflare-issued TLS certificate, no port forwarding required.

To run the tunnel as a systemd service (so it survives reboots):

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

Check status with:

sudo systemctl status cloudflared

8. Docker Integration

If you're running services in Docker containers, Cloudflare Tunnel works great with them. You have two approaches:

Option A: Run cloudflared as a Docker container

docker run -d \
  --name cloudflared \
  --restart unless-stopped \
  -v ~/.cloudflared:/etc/cloudflared \
  cloudflare/cloudflared:latest \
  tunnel run my-first-tunnel

In this setup, cloudflared is just another container. Your ingress rules point to http://host.docker.internal:PORT (or directly to container names if you're on a shared Docker network).

Option B: Docker Compose with service linking

Here's a practical docker-compose.yml that runs a web app alongside cloudflared:

version: "3.8"
services:
  app:
    image: nginx:alpine
    ports:
      - "127.0.0.1:8080:80"
    restart: unless-stopped

  tunnel:
    image: cloudflare/cloudflared:latest
    command: tunnel run my-first-tunnel
    volumes:
      - ~/.cloudflared:/etc/cloudflared
    restart: unless-stopped
    depends_on:
      - app

Notice the ports definition on the app service: 127.0.0.1:8080:80. This binds only to localhost, so the service is not reachable from the host's network — only cloudflared (via Docker's internal bridge) can reach it. This is a great security practice.

9. Security Best Practices

Cloudflare Tunnel already eliminates the biggest attack vector (open ports), but you should harden your setup further:

9.1 Restrict Access by IP or Country

Use Cloudflare WAF (Web Application Firewall) rules to restrict traffic:

These firewall rules are free on all Cloudflare plans.

9.2 Enable Access Authentication (Zero Trust)

Cloudflare Access lets you add an authentication gate in front of your tunnel — users must log in via Google, GitHub, email OTP, or any SSO provider before reaching your service:

# In Cloudflare Zero Trust dashboard:
# Applications → Add an application → Self-hosted
# Set your domain, select identity providers, and configure access policies

This is free for up to 50 users on the Zero Trust Free plan.

9.3 Bind Local Services to localhost

Never bind your local services to 0.0.0.0 or 0.0.0.0:PORT — bind them to 127.0.0.1 only. Since cloudflared connects to localhost, the service doesn't need to be on the network at all.

9.4 Keep cloudflared Updated

Cloudflare ships updates frequently. If installed via apt, updates come with regular system updates. If you installed the binary directly, check periodically:

cloudflared update

9.5 Use Short-Lived Certificates (Advanced)

For production setups, instead of a long-lived credentials JSON file, Cloudflare supports short-lived certificates that auto-renew. This is especially important in CI/CD environments where credential theft is a bigger risk.

10. Limitations to Know

Cloudflare Tunnel isn't perfect for every use case:

11. Troubleshooting Common Issues

Tunnel connects but returns 502/503

Your local service isn't running or cloudflared can't reach it. Check: curl http://localhost:8080 from the server. Also verify the ingress hostname matches exactly what you're visiting in the browser (subdomain case matters).

Certificate error in browser

Cloudflare automatically provisions TLS certificates for proxied DNS records — wait up to 60 seconds after routing the tunnel. If the error persists, go to Cloudflare Dashboard → SSL/TLS and set the mode to Full (strict).

cloudflared fails to start on boot

Check systemd logs: sudo journalctl -u cloudflared -n 50 --no-pager. A common issue is the credentials file path being incorrect in config.yml. Use absolute paths.

Cloudflare shows "This site can't be reached"

Ensure the DNS record's proxy status (orange cloud) is enabled in Cloudflare dashboard. If the cloud is grey, traffic goes directly to your origin IP, bypassing the tunnel entirely — and that IP probably isn't reachable.

FAQ

How many tunnels can I create with the Cloudflare free plan?

There is no limit on the number of tunnels you can create on the free plan. Each tunnel supports multiple ingress rules, so you can route dozens of services through a single tunnel. The free plan does have a 50 GB monthly traffic limit per user.

Does Cloudflare Tunnel support UDP traffic?

As of 2026, Cloudflare Tunnel's primary transport supports HTTP/HTTPS and WebSocket traffic. For UDP and full TCP support, you need to enable Warp Routing in the Zero Trust dashboard, which is available on paid plans (Teams, Enterprise).

Can I use my own domain with Cloudflare Tunnel?

Yes, your domain must be using Cloudflare as its DNS provider (nameservers pointed to Cloudflare). The tunnel DNS records are CNAME entries pointing to <tunnel-uuid>.cfargotunnel.com. Cloudflare automatically provisions TLS certificates for proxied domains.

Is Cloudflare Tunnel better than a VPN?

They serve different purposes. Cloudflare Tunnel exposes specific services to the internet with optional authentication (Zero Trust Access). A VPN gives you full network access like you're on the local LAN. For exposing web apps to external users, Cloudflare Tunnel is simpler and more secure. For full network access, use a VPN like WireGuard or Tailscale.

What happens to the cloudflared credentials file if my server is compromised?

If an attacker gains access to your server, they could use the tunnel credentials to maintain persistence. To mitigate this, use short-lived certificates (available in the Cloudflare Zero Trust dashboard) that auto-renew, limiting the window of exposure. You should also run cloudflared with the minimum necessary permissions and monitor tunnel activity in the Cloudflare dashboard.

Summary

Cloudflare Tunnel transforms how you expose self-hosted services. Instead of fighting with firewalls, port forwards, and TLS certificates, you install a single agent, configure a YAML file, and let Cloudflare's edge handle the rest.

Key takeaways:

  1. Zero open ports — your server only makes outbound connections. Port scanners see nothing.
  2. Free and easy — Cloudflare's free plan covers unlimited tunnels and most features mentioned here.
  3. Integrated security — DDoS protection, TLS termination, WAF, and Zero Trust access gate are built in.
  4. Docker-friendlycloudflared runs as a container alongside your services with minimal configuration.

If you're self-hosting anything you want to access from outside your home network, Cloudflare Tunnel is the safest, simplest way to do it. Set it up once, and you can forget about networking issues — just focus on the services themselves.

← Back to Home

Related Articles

Reference: Cloudflare Free Plan — Official Page. Cloudflare Tunnel usage is unlimited on the Free plan as of 2026; traffic limits and feature availability are subject to change.

About the Author

Frankie is a self-hosting enthusiast and DevOps practitioner with over 8 years of experience deploying and maintaining production Linux servers, Docker environments, and homelab infrastructure. He writes practical, hands-on guides to help others take control of their own infrastructure.