← Lab Notes
July 2, 2026 homelabnetworkingcloudflare

Networking Basics #6: Cloudflare Tunnels vs Open Ports (and the Two-Cloudflared 502 Mystery)

Discover why Breadtoasting.com uses Cloudflare tunnels instead of opening inbound ports, and how a misconfiguration led to intermittent errors.


Overview

In this installment of my Homelab series, I'll be discussing the decision to use Cloudflare tunnels for hosting websites, rather than exposing ports directly on our router. This approach offers several benefits but also comes with some tradeoffs that we've had to navigate.

flowchart LR
  V[Visitor] --> CF[Cloudflare edge]
  CF -- outbound tunnel --> CD[cloudflared in the lab]
  CD --> N[nginx then the services]

Background

Traditional self-hosting often involves forwarding web traffic (ports 80 and 443) from your home router to a reverse proxy running on your server. While this method is straightforward, it exposes your public IP address to the internet, making you vulnerable to constant scanning and DDoS attacks that can directly impact your home connection.

At Breadtoasting.com, we decided to take a different approach by using Cloudflare tunnels. This method keeps our home IP hidden from the internet while still allowing us to serve web content securely.

How It Works

Traditional Self-Hosting

Traditionally, you might configure your router to forward incoming requests on ports 80 and 443 to an internal server running a reverse proxy like NGINX. This setup is simple but poses security risks:

# Example of port forwarding in a router config (hypothetical)
# Forwarding HTTP traffic from the public IP to the internal server
iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination <internal_server_ip>

Cloudflare Tunnels

Instead, we use a Cloudflare tunnel container that establishes an outbound connection to Cloudflare's edge network. When a visitor requests breadtoasting.com, the request is terminated at Cloudflare's edge and then forwarded through the established tunnel to our NGINX server.

The key advantage here is that our home IP address never appears in any DNS records or web ports from the internet's perspective. All traffic goes through Cloudflare, which handles TLS termination, caching static assets, and absorbing junk traffic.

Benefits

  1. No Port Forwarding for Web: We don't need to expose port 80/443 on our router.
  2. Hidden Origin IP: Our home IP is never exposed.
  3. Cloudflare Absorbs Junk Traffic: Cloudflare handles DDoS protection and caching, reducing the load on our server.
  4. Free TLS Certificates: Cloudflare provides free Let's Encrypt certificates for all domains.

Tradeoffs

  1. Cloudflare Sees All Traffic: Since Cloudflare terminates TLS at their edge, they have visibility into your traffic.
  2. Dependence on Third Party: You're reliant on the availability and performance of Cloudflare.
  3. WebSockets and Long-Lived Connections: These require careful handling as they rely on persistent connections through the tunnel.
  4. Game Server Traffic (UDP): UDP-based game server traffic uses forwarded ports directly, bypassing the tunnel.

Results

War Story: The Two-Cloudflared 502 Mystery

One of the more interesting challenges we faced was intermittent 502 errors that only some visitors experienced. After some investigation, I discovered a peculiar issue with our Cloudflare tunnel setup:

  1. Initial Setup: We had installed a native Cloudflared process during early experiments and later deployed another one in Docker.
  2. Dual Connections: Both processes were connected to the same tunnel, and Cloudflare was load balancing requests between them.
  3. Misconfiguration: The native Cloudflared process pointed to an outdated configuration file.

Troubleshooting

To resolve this issue, I followed these steps:

  1. Identify Processes:

    ps aux | grep cloudflared
    docker ps
    
  2. Kill and Uninstall the Native Process:

    sudo kill <native_cloudflared_pid>
    sudo apt-get remove --purge cloudflared
    
  3. Keep the Docker Container:
    Ensure only the Cloudflared container is running.

Lesson Learned

A tunnel is essentially a process, and processes can be duplicated. It's crucial to check both ps aux and docker ps when troubleshooting issues with your tunnel setup.

Lessons Learned

  1. Process Duplication: Always verify that you have only one active Cloudflared process.
  2. Configuration Management: Keep your configurations up-to-date and consistent across all instances of the tunnel service.
  3. Dependency Awareness: Be aware of dependencies on third-party services like Cloudflare, especially when it comes to security and performance.

By adopting this approach, we've significantly improved the security and reliability of our homelab setup while minimizing the risks associated with traditional port-forwarding methods.

Was this useful?