How to Configure DNS and Routes for a Cloudflare Tunnel
Cloudflare Tunnel can publish a service running on a Raspberry Pi, home server, or private network without forwarding an inbound port on the router. The cloudflared connector opens an outbound connection to Cloudflare, while a public hostname tells Cloudflare which local service should receive a request.
The setup has three parts:
app.example.com
↓ DNS
Cloudflare network
↓ Cloudflare Tunnel
http://localhost:8080
This guide focuses on the relationship between the public hostname, its DNS record, and the local service URL. It assumes that the domain is already active in Cloudflare and that a tunnel with a connected cloudflared instance already exists.
What a published application route does
A published application route maps a public hostname, such as app.example.com, to a service that cloudflared can reach, such as http://localhost:8080.
When the route is created through the Cloudflare dashboard, Cloudflare also creates a proxied CNAME record for the hostname. The record points to a tunnel-specific target in this form:
<TUNNEL-UUID>.cfargotunnel.com
The origin does not need a public IP address, and the DNS record must not point directly to the private address of the Raspberry Pi. Cloudflare receives the public request and sends it through the tunnel.
Before configuring DNS
Check the local service from the machine or container where cloudflared runs:
curl -I http://localhost:8080
Use the real protocol, host, and port of the origin. A successful response confirms that the application works locally before DNS and the tunnel are added to the path.
There is an important detail here: localhost always refers to the network environment in which cloudflared runs. If cloudflared is in a container and the application is in another container, localhost usually points to the cloudflared container itself. In that case, use a reachable container name or address on their shared network, for example:
http://web:8080
Add the public hostname in the dashboard
In the current Cloudflare dashboard:
- Open Networking → Tunnels.
- Select the tunnel used by the server.
- Open the Routes tab.
- Select Add route, then Published application.
- Enter the public hostname, for example
app.example.com. - Enter the local service URL, for example
http://localhost:8080. - Save the route.
Cloudflare should create the corresponding DNS record automatically. You can confirm this under the DNS records for the domain. The record should be proxied and its target should end with .cfargotunnel.com.
Cloudflare’s official documentation describes this as a published application route.
Add the DNS route with cloudflared
For a locally managed tunnel, the hostname can also be associated from the command line:
cloudflared tunnel route dns <TUNNEL-NAME-OR-UUID> app.example.com
This command creates or updates the DNS record that points the public hostname to the selected tunnel. It does not define which local application should receive the request. The tunnel configuration must still contain an ingress rule that maps the hostname to the origin service. A simple ingress configuration can look like this:
tunnel: <TUNNEL-UUID>
credentials-file: /etc/cloudflared/<TUNNEL-UUID>.json
ingress:
- hostname: app.example.com
service: http://localhost:8080
- service: http_status:404
The final catch-all rule is important. It defines what should happen when a request does not match any configured hostname.
After changing a locally managed configuration, validate the ingress rules and restart or reload the way your cloudflared instance is managed. The exact service command depends on the installation method.
Root domains and CNAME flattening
A subdomain such as app.example.com can use a normal CNAME record. The zone apex, meaning example.com without a subdomain, is a special case because traditional DNS rules do not normally allow a CNAME there alongside the other records required for the domain.
Cloudflare handles this with CNAME flattening. It allows an apex hostname to be connected to the tunnel while DNS clients receive resolved IP addresses instead of the CNAME target. Cloudflare enables flattening at the zone apex by default. The behavior is documented in CNAME flattening.
This is why a dig CNAME example.com query may not show the tunnel target even when the configuration is working correctly.
Verify DNS and the tunnel
Start by checking whether the public hostname resolves:
dig +short app.example.com A
dig +short app.example.com AAAA
For a proxied Cloudflare record, the answers normally contain Cloudflare addresses. They do not reveal the private origin address or necessarily display the underlying CNAME.
Next, test the application over HTTPS:
curl -I https://app.example.com
For more detail, include connection and response information:
curl -v https://app.example.com/ -o /dev/null
Also check the tunnel itself:
cloudflared tunnel info <TUNNEL-NAME-OR-UUID>
These tests answer different questions:
digchecks public DNS resolution,cloudflared tunnel infochecks whether connectors are registered,- local
curlchecks the origin service, - public
curlchecks the complete route through Cloudflare.
Common problems
The hostname does not resolve
Check whether the DNS record exists in the correct Cloudflare zone. A route created only in a local ingress file does not by itself guarantee that a public DNS record was created.
For a locally managed tunnel, run the cloudflared tunnel route dns command or create a proxied CNAME record pointing to <TUNNEL-UUID>.cfargotunnel.com.
Cloudflare Tunnel Error 1033
Cloudflare cannot find a healthy cloudflared connector for the tunnel. Check whether the connector process or service is running and whether cloudflared tunnel info reports an active connection.
Cloudflare Tunnel 502 Bad Gateway
The public DNS and tunnel may be working, but cloudflared cannot reach the configured origin. Check:
- whether the application is running,
- whether the protocol is correct (
httpversushttps), - whether the service listens on the configured port,
- whether
localhostrefers to the correct container or host, - whether a local firewall blocks the connection.
Test the exact origin URL from the same network environment as cloudflared.
If cloudflared runs alongside Docker containers and the origin is still unreachable, see Configuring firewalld for Docker Containers on Raspberry Pi for an example of checking the firewall and Docker bridge configuration.
The wrong application opens
Check the hostname and order of the ingress rules. More specific rules should appear before the catch-all rule, which must remain last.
DNS works, but HTTPS is not ready yet
Cloudflare provisions an edge certificate for the public hostname. Immediately after adding a new hostname, certificate issuance can take a short time. Confirm that the hostname is active in the dashboard before changing the origin configuration repeatedly.
Tunnel access is not the same as authentication
Cloudflare Tunnel removes the need to expose an inbound port directly, but a published hostname is public unless another access control is added. Administrative panels, dashboards, and private applications should not rely on the tunnel alone as their authentication layer.
For restricted services, use the application’s own strong authentication and consider a Cloudflare Access policy. Cloudflare notes that Access policies can require users to authenticate before reaching a published application.
Summary
The essential relationship is straightforward:
- The public hostname resolves through Cloudflare DNS.
- Its proxied CNAME is associated with a specific tunnel.
- The tunnel route maps the hostname to a service reachable by
cloudflared. - The origin remains private and does not require an inbound router port.
When troubleshooting, test each layer separately: local application, tunnel connector, DNS resolution, and finally the public HTTPS request. This makes it much easier to distinguish a DNS problem from an unavailable tunnel or an incorrect origin address.
If you need help diagnosing Cloudflare Tunnel, Docker networking, DNS, or a reverse proxy, see my Docker, Reverse Proxy and Application Deployments service.
