Cloudflare Tunnel Troubleshooting: DNS, 502 Errors & WebSockets

Updated on Aug 24, 2026
Mila H
11 MINS READ
Table of Contents
Cloudflare Tunnel Troubleshooting

Imagine checking your tunnel at 2 AM, the dashboard says everything is healthy, and your browser still shows a Bad Gateway error. This Cloudflare tunnel troubleshooting nightmare happens to many users.

This guide covers the exact problems that come up after deployment, including the tunnel connecting fine but your app refuses to load, DNS records point to the wrong place, 502/503 errors appear without a clear reason, and WebSocket apps break silently.

What You Need Before Cloudflare Tunnel Troubleshooting

Before going into Cloudflare tunnel troubleshooting, make sure you have:

  • SSH access to your origin server.
  • cloudflared installed, and a tunnel has already been created.
  • Your domain has been added to Cloudflare with nameservers pointing to Cloudflare.
  • Access to the Cloudflare Zero Trust dashboard.

If you have not set up your tunnel yet, start with the Cloudflare Tunnel without port forwarding guide, which covers installation, config, DNS routing, and Docker setup.

The important thing is that a healthy tunnel does not mean your app is reachable. The connection path looks like this:

Bash
Browser → Cloudflare Edge → cloudflared (your server) → Your Local App

When you see a 502 or unable to reach origin error, the tunnel itself is usually fine. The problem is almost always in the last hop, between cloudflared and your local app. This is where most users get stuck.

Cloudflare's official docs confirm that a 502 error on a tunnel means the tunnel is connected to Cloudflare's network, but cloudflared cannot reach the origin service defined in your ingress rule.

You can follow the steps below to start the Cloudflare tunnel troubleshooting.

Step 1. Check Your Tunnel Status

The first thing to do in any Cloudflare tunnel troubleshooting session is check the tunnel's status.

From the dashboard, navigate to Zero Trust > Networks > Connectors > Cloudflare Tunnels. Each tunnel shows one of four states:

Status Meaning What To Do
Healthy Active, four connections to Cloudflare No tunnel-level action needed
Inactive Created, but cloudflared never ran Run cloudflared tunnel run on the server
Down Was connected, now disconnected Check if cloudflared process is running
Degraded Running, but one connection failed Check logs and local firewall rules

Also, you can check the tunnel's status from the command line:

Bash
# List all tunnels and their statuscloudflared tunnel list # Get detailed connector info for a specific tunnelcloudflared tunnel info <TUNNEL-NAME-OR-UUID> # Check the systemd service statussudo systemctl status cloudflared # Stream live logs from the tunnelcloudflared tail <TUNNEL-UUID>

If the tunnel is Down, check whether cloudflared is actually running:

Bash
# For system service installssudo systemctl status cloudflared # For Docker installsdocker ps | grep cloudflareddocker logs loudflared-container-name>

Step 2. Verify Your Origin App Is Running

This step catches 50% of all tunnel problems. The tunnel shows healthy, but nobody checks if the app is alive on the origin side.

Check if your app is listening on the expected port:

Bash
ss -tlnp | grep <PORT>

For example, if your app should be on port 3000:

Bash
ss -tlnp | grep 3000

Test the app directly from the server itself:

Bash
curl -v http://localhost:3000

If your app is in Docker, check the container:

Bash
docker psdocker logs <your-app-container>

If curl fails locally, cloudflared will also fail. Fix the app first, then the tunnel will work.

Common reasons the app is down:

  • The app crashed silently after deployment.
  • A port mismatch: the app binds to 0.0.0.0:8080, but the tunnel config says localhost:3000.
  • Docker container exited due to an error.
  • The app only listens on a specific network interface, not localhost.

Step 3. Fix 502 Bad Gateway Errors

A 502 error during Cloudflare tunnel troubleshooting usually means cloudflared can reach Cloudflare, but it cannot reach the service you configured.

Check the Ingress Rule / Service URL

For locally-managed tunnels, open your config file:

Bash
sudo nano /etc/cloudflared/config.yml

A correct config looks like this:

YAML
tunnel: <YOUR-TUNNEL-UUID>credentials-file: /root/.cloudflared/<YOUR-TUNNEL-UUID>.json ingress:  - hostname: app.yourdomain.com    service: http://localhost:3000  - service: http_status:404

Common mistakes that cause a 502:

  • Wrong protocol: Writing https://localhost:3000 when the app serves plain HTTP, or the reverse.
  • Wrong port: The ingress rule says :3000 but the app is running on :8080.
  • Missing catch-all rule: Every config file must end with - service: http_status:404 or the tunnel will not start correctly.
  • Docker container name as URL: If using Docker, the service URL must match the container's network name, not localhost.

Validate Your Config Before Restarting

Validate ingress rules syntax:

Bash
cloudflared tunnel ingress validate

Test which rule matches a specific URL:

Bash
cloudflared tunnel ingress rule https://app.yourdomain.com

The Docker Network Trap

If your app runs in Docker, and cloudflared also runs in Docker, you cannot use localhost in the service URL. Use the Docker service name instead:

YAML
# Wrong: cloudflared container cannot reach localhost of another containerservice: http://localhost:8080 # Correct: use the Docker service name on the shared networkservice: http://myapp:8080

Both containers must be on the same Docker network.

Self-Signed Certificate Causing 502

If your origin uses HTTPS with a self-signed certificate, cloudflared will reject it by default, producing a 502. Fix it in the dashboard:

  • Go to Zero Trust > Networks > Tunnels.
  • Click your tunnel > Edit.
  • Open Published application routes > Edit the route.
  • Under Additional application settings > TLS, enable No TLS Verify.

Or you can add it to your config file:

YAML
ingress:  - hostname: app.yourdomain.com    service: https://localhost:443    originRequest:      noTLSVerify: true  - service: http_status:404

Step 4. Fix DNS Records Not Matching

DNS mismatches are a silent killer in Cloudflare tunnel troubleshooting. The tunnel is healthy, the app is running, but the domain does not resolve.

What the DNS Record Should Look Like

Every hostname you expose through a tunnel needs a CNAME record pointing to your tunnel's subdomain:

Bash
Type:   CNAMEName:   app (or your subdomain)Target: <UUID>.cfargotunnel.comProxy:  Enabled (orange cloud)

You can create it automatically with:

Bash
cloudflared tunnel route dns <TUNNEL-NAME> app.yourdomain.com

Or manually in Cloudflare Dashboard > DNS > Records.

Verify the DNS Record Is Correct

Bash
# Check what the subdomain resolves todig app.yourdomain.com # Check CNAME specificallydig CNAME app.yourdomain.com # Verify DNS is pointing to Cloudflare's networknslookup app.yourdomain.com 1.1.1.1

The output should show a CNAME pointing to something like:

Bash
<UUID>.cfargotunnel.com

Common DNS Issues

1. Existing A record conflicts: If an A record already exists for the same subdomain, the CNAME cannot be created. Delete the old A record first.

2. DNSSEC not disabled: If DNSSEC is enabled at your registrar but not properly configured with Cloudflare, DNS resolution fails silently.

3. Nameservers not pointing to Cloudflare: Your domain registrar must use Cloudflare's nameservers for the tunnel DNS routing to work.

4. Proxy toggled off (gray cloud): If the DNS record is set to DNS-only, traffic bypasses Cloudflare entirely. Set it to Proxied (orange cloud).

5. DNS propagation delay: After creating a new record, it can take several minutes for the change to propagate. Wait 5 to 10 minutes, then purge the cache:

Bash
# Purge Cloudflare's public DNS cachecurl "https://1.1.1.1/api/v1/purge?domain=app.yourdomain.com&type=CNAME"

Step 5. Fix 503 Service Unavailable Errors

A 503 during Cloudflare tunnel troubleshooting has two different meanings depending on what is in the error page HTML.

Check the page source in your browser:

  • If the HTML contains cloudflare or cloudflare-nginx, the issue is on Cloudflare's side. Check Security > Events for active blocks.
  • If the HTML does not contain cloudflare, your origin server generated the 503 directly. The app itself is rejecting or overloading.

To fix origin-side 503 errors, check server resource usage with the commands below:

Bash
topfree -hdf -h

Check app logs for overload or maintenance mode:

Bash
journalctl -u your-app-service -n 50

Restart the app:

Bash
sudo systemctl restart your-app-service

Also, check if any security rules in Cloudflare are blocking the tunnel's own requests:

  • Go to Security > Events in the Cloudflare dashboard.
  • Look for blocked requests matching your origin URL.
  • Temporarily disable WAF rules or rate-limiting rules to test.

Step 6. Fix WebSocket Apps Not Working

Broken WebSockets are one of the most frustrating parts of Cloudflare tunnel troubleshooting because the page loads, but real-time features stop working silently.

Enable WebSockets in Cloudflare Dashboard

Go to Cloudflare Dashboard > Your Domain > Network. Find the WebSockets toggle and switch it On.

This is a zone-level setting, not a tunnel-level setting. Without it, WebSocket upgrade requests will be dropped.

Set the Correct Service Protocol in Your Tunnel

In your tunnel config or dashboard, use http:// or https:// for the service URL, not ws:// or wss://. Cloudflare handles the WebSocket upgrade automatically when the app supports it:

YAML
ingress:  - hostname: app.yourdomain.com    service: http://localhost:3000   # WebSocket upgrade is handled automatically  - service: http_status:404

Test WebSocket Connectivity Locally First

Before blaming the tunnel, make sure the WebSocket endpoint works from inside the server:

Bash
# Install wscat if not availablenpm install -g wscat # Test the local WebSocket endpointwscat -c ws://localhost:3000/ws

If this fails, the problem is in your app, not the tunnel.

Nginx Reverse Proxy Behind the Tunnel

If your setup has cloudflared > Nginx > App, Nginx must pass the WebSocket headers correctly:

Bash
location /ws/ {    proxy_pass http://127.0.0.1:3000;    proxy_http_version 1.1;    proxy_set_header Upgrade $http_upgrade;    proxy_set_header Connection "Upgrade";    proxy_set_header Host $host;}

Without proxy_http_version 1.1 and the Upgrade headers, WebSocket connections will fail at the Nginx layer.

SSL Mode Mismatch Breaking WebSockets

An incorrect SSL/TLS mode can silently break WebSocket handshakes. Go to SSL/TLS > Overview in the Cloudflare dashboard:

  • If your origin has a valid certificate, use Full (Strict).
  • If your origin uses a self-signed cert, use Full.
  • Never use Off; it breaks WebSockets entirely.

Step 7. Read the Tunnel Logs

Logs are the fastest way to confirm what is actually failing during Cloudflare tunnel troubleshooting.

For system service logs:

Bash
# Recent logssudo journalctl -u cloudflared -n 100 # Follow live logssudo journalctl -u cloudflared -f # Enable debug-level logging (edit the service or config)cloudflared tunnel --loglevel debug run

For Docker logs:

Bash
docker logs cloudflared --tail 100 -f

You must look for:

Log Message What It Means Fix
connection refused App not running on that port Start or fix the app
dial tcp: no such host Wrong service hostname in ingress Fix service URL in config
x509: certificate signed by unknown authority Self-signed cert rejected Enable noTLSVerify
error="remote error: tls: handshake failure" SSL cert issue for the hostname Check Advanced Certificate for multi-level subdomains
WRN No ingress rules were defined Config not being read Check config file path and --config flag
too many open files File descriptor limit hit Increase ulimit on the server

Step 8. Check for Config File Not Being Read

This is a common issue, but hard to identify. cloudflared may start without errors, but use default settings instead of your config file, so your ingress rules are completely ignored.

Always specify the config path when running manually:

Bash
cloudflared tunnel --config /etc/cloudflared/config.yml run

When installing as a service, verify the service file includes your config path:

Bash
sudo cat /etc/systemd/system/cloudflared.service

The service ExecStart line should include --config /etc/cloudflared/config.yml.

Also, validate the config before restarting:

Bash
cloudflared tunnel --config /etc/cloudflared/config.yml ingress validate

Step 9. Fix SSL and Certificate Errors

SSL issues in Cloudflare tunnel troubleshooting appear as ERR_SSL_VERSION_OR_CIPHER_MISMATCH, ERR_TOO_MANY_REDIRECTS, or blank pages.

Multi-Level Subdomains

Cloudflare's Universal SSL only covers one level of subdomain, for example, app.domain.com. If you use a deeper subdomain like api.app.domain.com, you need an Advanced Certificate from SSL/TLS > Edge Certificates.

Redirect Loops

If you see ERR_TOO_MANY_REDIRECTS:

  • Check SSL/TLS mode in the Cloudflare dashboard; it must not be set to Flexible if your origin also enforces HTTPS.
  • The combination of Flexible SSL and HTTPS redirect on the origin creates an infinite loop.
  • Set SSL mode to Full or Full (Strict) to fix it.

Check Universal Certificate Status

  • Go to SSL/TLS > Edge Certificates.
  • Find the certificate with Type: Universal.
  • Make sure Status is Active.

Verify the Complete Cloudflare Tunnel Path

Before you finish your Cloudflare tunnel troubleshooting, you should always run a complete check. To do this, you can use the following checklist:

Bash
# 1. App is running locallycurl -v http://localhost:<PORT> # 2. Tunnel is healthycloudflared tunnel listcloudflared tunnel info <TUNNEL-NAME> # 3. DNS resolves correctlydig app.yourdomain.com # 4. Public URL loadscurl -v https://app.yourdomain.com # 5. Check Cloudflare trace for edge infocurl https://app.yourdomain.com/cdn-cgi/trace

The /cdn-cgi/trace returns Cloudflare edge connection details and is useful for confirming traffic is actually going through Cloudflare.

If you hit tunnel problems again and again, the main issue is often weak access to the origin server. With a reliable Linux VPS, you get full root, flexible firewall control, and debug commands. This direct access makes Cloudflare tunnel troubleshooting much quicker because you can see at each step whether the tunnel is fine or the app is broken.

Conclusion

The most important lesson in Cloudflare tunnel troubleshooting is that a connected tunnel is not the same as a working app. Always check the origin side, whether the app is running, whether the port matches, and whether the protocol is correct. DNS mismatches, wrong service URLs, disabled WebSocket settings, and self-signed certificate rejections cause all post-deploy failures.

We hope you enjoy this guide. If you still do not have a domain for your tunnel, you can register one quickly through PerLod domain registration.

The tunnel is connected to Cloudflare, but cloudflared cannot reach your local app. Check that the app is running and the port/protocol in your ingress rule is correct.

cloudflared is not reading your config file. Make sure you pass --config /path/to/config.yml when running the tunnel, or check that the systemd service file includes the correct path.

Cloudflare SSL mode is set to Flexible while your origin also enforces HTTPS, creating an infinite redirect loop. Change the SSL mode to Full or Full (Strict).