Cloudflare Tunnel Troubleshooting Guide: Fix Origin Reachability, DNS, 502 Errors, and WebSockets
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.
Table of Contents
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:
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:
# List all tunnels and their status
cloudflared tunnel list
# Get detailed connector info for a specific tunnel
cloudflared tunnel info <TUNNEL-NAME-OR-UUID>
# Check the systemd service status
sudo systemctl status cloudflared
# Stream live logs from the tunnel
cloudflared tail <TUNNEL-UUID>
If the tunnel is Down, check whether cloudflared is actually running:
# For system service installs
sudo systemctl status cloudflared
# For Docker installs
docker ps | grep cloudflared
docker 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:
ss -tlnp | grep <PORT>
For example, if your app should be on port 3000:
ss -tlnp | grep 3000
Test the app directly from the server itself:
curl -v http://localhost:3000
If your app is in Docker, check the container:
docker ps
docker 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 sayslocalhost: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:
sudo nano /etc/cloudflared/config.yml
A correct config looks like this:
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:3000when the app serves plain HTTP, or the reverse. - Wrong port: The ingress rule says
:3000but the app is running on:8080. - Missing catch-all rule: Every config file must end with
- service: http_status:404or 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:
cloudflared tunnel ingress validate
Test which rule matches a specific URL:
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:
# Wrong: cloudflared container cannot reach localhost of another container
service: http://localhost:8080
# Correct: use the Docker service name on the shared network
service: 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:
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:
Type: CNAME
Name: app (or your subdomain)
Target: <UUID>.cfargotunnel.com
Proxy: Enabled (orange cloud)
You can create it automatically with:
cloudflared tunnel route dns <TUNNEL-NAME> app.yourdomain.com
Or manually in Cloudflare Dashboard > DNS > Records.
Verify the DNS Record Is Correct
# Check what the subdomain resolves to
dig app.yourdomain.com
# Check CNAME specifically
dig CNAME app.yourdomain.com
# Verify DNS is pointing to Cloudflare's network
nslookup app.yourdomain.com 1.1.1.1
The output should show a CNAME pointing to something like:
<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:
# Purge Cloudflare's public DNS cache
curl "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:
top
free -h
df -h
Check app logs for overload or maintenance mode:
journalctl -u your-app-service -n 50
Restart the app:
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:
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:
# Install wscat if not available
npm install -g wscat
# Test the local WebSocket endpoint
wscat -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:
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:
# Recent logs
sudo journalctl -u cloudflared -n 100
# Follow live logs
sudo journalctl -u cloudflared -f
# Enable debug-level logging (edit the service or config)
cloudflared tunnel --loglevel debug run
For Docker logs:
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:
cloudflared tunnel --config /etc/cloudflared/config.yml run
When installing as a service, verify the service file includes your config path:
sudo cat /etc/systemd/system/cloudflared.service
The service ExecStart line should include --config /etc/cloudflared/config.yml.
Also, validate the config before restarting:
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:
# 1. App is running locally
curl -v http://localhost:<PORT>
# 2. Tunnel is healthy
cloudflared tunnel list
cloudflared tunnel info <TUNNEL-NAME>
# 3. DNS resolves correctly
dig app.yourdomain.com
# 4. Public URL loads
curl -v https://app.yourdomain.com
# 5. Check Cloudflare trace for edge info
curl 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.
FAQs
Why does my tunnel show Healthy but the app returns 502?
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.
What does the No ingress rules were defined warning mean?
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.
Why do I get ERR_TOO_MANY_REDIRECTS?
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).