If your Cloudflare Tunnel is Healthy but app.example.com fails, check the route's Service URL, origin certificate, and SSL/TLS encryption mode.
A Healthy status confirms only that cloudflared connects to Cloudflare. It does not test the route's service or the local origin.
This guide covers an origin that already serves HTTPS with a Let's Encrypt certificate. You can keep the existing certificate installed.
For an Apache origin that redirects HTTP to HTTPS, use these settings:
- Service URL:
https://localhost:443whencloudflaredruns on the Apache host - Origin Server Name: The hostname covered by the certificate, such as
app.example.com - Disable TLS certificate verification: Turned off
- Encryption mode: Leave Automatic SSL/TLS (recommended) selected, or choose Full (Strict)
The public hostname is the URL that visitors request. The Service URL is the address, protocol, and port that cloudflared can reach. These values are not interchangeable. Do not use a public hostname as the service URL when that hostname points to the Tunnel CNAME.
For example, http://localhost:80 uses HTTP for the local connection, while https://localhost:443 uses HTTPS. Replace these examples with the address and port used by your origin.
The connection between Cloudflare and cloudflared is encrypted independently of the zone SSL/TLS mode. cloudflared validates the local origin certificate through origin parameters.
The zone SSL/TLS mode does not change the Service URL. Configure the local protocol in the route, then configure certificate validation with originServerName and the other origin parameters.
If originServerName is empty, cloudflared expects the certificate to cover the host in the Service URL. For a service URL that uses localhost, set originServerName to the hostname covered by the certificate. This value also supplies the Server Name Indication (SNI) for the TLS connection.
Use the following decision tree to choose the local protocol and certificate settings:
flowchart TD
accTitle: Service URL and SSL/TLS mode decision tree
accDescr: Choose the Service URL from the origin protocol, then configure certificate validation for HTTPS origins.
A{Origin accepts HTTPS?}
A -->|No| B{HTTP redirects to HTTPS?}
B -->|No| C[Use HTTP service URL]
B -->|Yes| D{Keep the redirect?}
D -->|No| C
D -->|Yes| E[Configure an HTTPS listener]
A -->|Yes| F[Use HTTPS service URL]
E --> F
F --> G{Certificate covers service host?}
G -->|Yes| H[Keep TLS verification on]
G -->|No| I[Set Origin Server Name and keep verification on]
If the origin has no HTTPS listener, remove or adjust its redirect before keeping an HTTP Service URL. Do not point an HTTPS Service URL at an HTTP listener.
Use this table to compare common origin and zone settings:
| Origin behavior | Service URL | Origin parameters | Zone SSL/TLS guidance |
|---|---|---|---|
| HTTP only, with no redirect | http://127.0.0.1:80 |
No TLS parameters | Automatic, Flexible, Full, and Full (strict) do not change the local HTTP connection. |
| HTTP redirects to HTTPS | https://localhost:443, or remove the redirect and use HTTP |
Configure the route as HTTPS | Do not use Flexible to solve the redirect loop. |
HTTPS with a valid Let's Encrypt certificate for app.example.com |
https://localhost:443 |
Set originServerName: app.example.com. Keep Disable TLS certificate verification turned off and omit caPool. |
Choose the zone mode separately. It does not validate the local certificate. |
| HTTPS with a private certificate authority (CA) | https://localhost:443 |
Set originServerName and caPool. Keep Disable TLS certificate verification turned off. |
Choose the zone mode separately. Fix certificate trust first. |
For a public HTTPS hostname, Full (strict) is compatible with this configuration. However, cloudflared validates the local Let's Encrypt certificate independently. The zone mode does not replace the route's Service URL or originServerName settings.
Full also does not change the Tunnel service protocol or fix an origin certificate error. Do not switch to Flexible for either issue. Update the route's Service URL or origin parameters instead.
For a remotely-managed tunnel, update the route and its origin parameters in the dashboard:
-
In the Cloudflare dashboard ↗, go to Networking > Tunnels, then select your tunnel.
Go to Tunnels ↗ -
On Routes, select Edit route for
app.example.com. -
In Service URL, enter
https://localhost:443when the origin serves HTTPS. Usehttp://127.0.0.1:80only when the service speaks HTTP and does not redirect to HTTPS. -
Expand Additional application settings. Under TLS, set Origin Server Name to
app.example.comwhen the certificate covers that hostname.Keep Disable TLS certificate verification turned off. Leave CA Pool empty for a publicly trusted Let's Encrypt certificate. Set it only when the origin uses a private CA.
-
Select Save changes.
The route does not require you to remove an existing Let's Encrypt certificate. cloudflared can validate that certificate when the origin name and service protocol match.
The zone SSL/TLS mode is separate from the Tunnel route. It does not select the local protocol or fix a certificate mismatch between cloudflared and the origin.
To review or change the zone mode:
-
In the Cloudflare dashboard ↗, go to SSL/TLS > Overview.
Go to Overview ↗ -
On SSL/TLS Overview, select Configure.
-
Under Encryption mode, review the selected option. If Automatic SSL/TLS (recommended) is selected, leave it in place while troubleshooting this Tunnel route. Automatic mode does not change the route's Service URL.
-
To use a specific mode, select Full (Strict), then select Save. This zone setting does not replace certificate validation by
cloudflared. -
Do not select Flexible to resolve a local origin certificate mismatch. Update the Tunnel route's Service URL or origin parameters instead.
For details about available modes, refer to SSL/TLS encryption modes. If the origin redirects HTTP to HTTPS, an HTTP Service URL can cause a redirect loop. Refer to ERR_TOO_MANY_REDIRECTS for other redirect causes.
For a locally-managed tunnel, put the same settings in config.yml:
tunnel: <TUNNEL_UUID>
credentials-file: /path/to/<TUNNEL_UUID>.json
ingress:
- hostname: app.example.com
service: https://localhost:443
originRequest:
originServerName: app.example.com
- service: http_status:404This example keeps TLS verification enabled. It omits caPool because standard Let's Encrypt certificates are publicly trusted. For a private CA, add caPool: /path/to/ca.pem under originRequest.
On Windows, if cloudflared reports that it cannot load the system root certificate pool, set caPool to a local PEM bundle that contains the certificate authority.
Use noTLSVerify: true only as a temporary last resort while you fix certificate trust or the origin name. Turn it off after you resolve the underlying issue.
The catch-all http_status:404 rule is required at the end of the file. After editing config.yml, validate the ingress rules:
cloudflared tunnel ingress validateRun these checks from the public Internet and from the same host as cloudflared:
-
Check the public hostname and DNS. In the Cloudflare dashboard, go to DNS > Records for
Go to Records ↗example.com. Confirm thatapp.example.comis aCNAMEpointing to<TUNNEL_ID>.cfargotunnel.com.Inspect the exact hostname from a terminal:
dig CNAME app.example.com +short dig A app.example.com +short dig AAAA app.example.com +shortA proxied record may return Cloudflare addresses instead of the
CNAMEtarget. Use the dashboard to verify the target in that case.Cloudflare does not silently fall back from a Tunnel to an
AorAAAArecord. If the tunnel stops, the DNS record remains and visitors receive a1016error. Refer to Tunnel DNS records for more information. If traffic appears to go directly to the origin, check whether the exact hostname has anAorAAAArecord instead of the expected CNAME, or whether an explicit load balancer or another route serves it. -
Inspect redirect headers and statuses. From a client, request the public hostname and follow a limited number of redirects:
curl -sS -D - -o /dev/null https://app.example.com/ curl -sS -D - -o /dev/null -L --max-redirs 5 https://app.example.com/Look for repeated
Locationheaders and301,302,307, or308status codes. From thecloudflaredhost, test an HTTP listener directly:curl -sS -D - -o /dev/null -H "Host: app.example.com" http://127.0.0.1:80/If the origin returns an HTTPS
Locationheader, use the HTTPSService URLor change the origin redirect policy. An HTTPService URLsends every request to the origin over HTTP and can repeat the redirect indefinitely. -
Check the origin certificate and Server Name Indication (SNI). Run this from the host where
cloudflaredruns:openssl s_client -connect 127.0.0.1:443 -servername app.example.com -verify_hostname app.example.com -verify_return_error </dev/nullConfirm that the certificate includes
app.example.comand that the output containsVerify return code: 0 (ok). When the service URL useslocalhostbut the certificate coversapp.example.com, set Origin Server Name toapp.example.com. -
Stream Tunnel logs. If the Live logs tab is available in the tunnel detail page, open it and select Live. You can also use remote log streaming or run this command from an authenticated machine:
cloudflared tail <TUNNEL_UUID>Look for
connection refused, malformed HTTP responses,x509errors, and TLS handshake errors. These messages identify failures betweencloudflaredand the local origin, even when the Tunnel status remainsHealthy.
For protocol details, refer to supported Tunnel protocols. For all origin settings, refer to Tunnel origin parameters.