# Cloudflare Tunnel (cloudflared): expose an internal service without opening ports

Source: https://srvscripts.com/guides/cloudflare-tunnel-cloudflared/
Updated: 2026-10-03
Publisher: srvScripts (https://srvscripts.com/)

Publishing an internal dashboard, a self-hosted git server or a staging site normally means a public IP, a port forward and a certificate. Cloudflare Tunnel inverts that: a small daemon called cloudflared makes an outbound connection to Cloudflare’s edge, and requests for a hostname in your zone are relayed down that connection to the local service. Nothing listens on the internet, the origin address is never exposed, and Cloudflare terminates TLS with its own certificate. This tutorial sets up a named tunnel on an AlmaLinux 9 or Ubuntu 24.04 host and publishes an application on port 8080.

In short: Install the cloudflared package, run cloudflared tunnel login to authorise it against your Cloudflare account, create a named tunnel with cloudflared tunnel create app, write a config file that maps a public hostname to…

**Short answer:** Install the cloudflared package, run `cloudflared tunnel login` to authorise it against your Cloudflare account, create a named tunnel with `cloudflared tunnel create app`, write a config file that maps a public hostname to `http://localhost:8080`, publish the DNS record with `cloudflared tunnel route dns app app.example.com`, then install and start the systemd service. The hostname resolves to Cloudflare, traffic flows through the outbound tunnel, and you never open an inbound port.

## Install cloudflared

Cloudflare publishes packages for RPM and DEB systems. On AlmaLinux 9 add the Cloudflare repository and install with `dnf install cloudflared`; on Ubuntu 24.04 add the apt repository and key, then `apt install cloudflared`. Confirm the binary works with `cloudflared --version`. The host needs outbound HTTPS and, for best performance, outbound UDP 7844 so the tunnel can use QUIC; it falls back to HTTP/2 over TCP 443 if UDP is blocked.

## Authorise and create the tunnel

Run `cloudflared tunnel login` and open the URL it prints in a browser. Choose the zone the hostname belongs to; a certificate file is written to `~/.cloudflared/cert.pem`. Then create the tunnel:

```
cloudflared tunnel create app
cloudflared tunnel list
```

The create command prints a tunnel UUID and writes a credentials JSON file next to the certificate. Keep both files private; anyone with them can attach to the tunnel.

## Write the configuration

Create `/etc/cloudflared/config.yml` and copy the credentials file into `/etc/cloudflared/` so the service does not depend on a user home directory:

```
tunnel: 6ff42ae2-765d-4adf-a3d2-4d4b6d3e2b0c
credentials-file: /etc/cloudflared/6ff42ae2-765d-4adf-a3d2-4d4b6d3e2b0c.json

ingress:
  - hostname: app.example.com
    service: http://localhost:8080
  - hostname: git.example.com
    service: https://10.0.20.15:443
    originRequest:
      noTLSVerify: true
  - service: http_status:404
```

Ingress rules are evaluated in order and the last rule must be a catch-all. Services can be HTTP, HTTPS, SSH, RDP or raw TCP, and they can point at other hosts on the LAN, which makes one tunnel host enough for a whole office. Validate the file with `cloudflared tunnel ingress validate`.

Publish the DNS records so the hostnames point at the tunnel:

```
cloudflared tunnel route dns app app.example.com
cloudflared tunnel route dns app git.example.com
```

Each command creates a proxied CNAME to `<uuid>.cfargotunnel.com` in the zone. If a record already exists, delete it first or the command refuses.

## Run it as a service

Install the systemd unit and start it:

```
cloudflared --config /etc/cloudflared/config.yml service install
systemctl enable --now cloudflared
systemctl status cloudflared
journalctl -u cloudflared -f
```

The log should show connections registered to several Cloudflare edge locations. If it loops on connection errors, the host cannot reach the edge on 443 or 7844; check the local firewall’s outbound policy. On a cPanel server with CSF, add the UDP port to `UDP_OUT` in `/etc/csf/csf.conf` and restart with `csf -ra`.

## Protect it with Access and verify

A tunnel makes a service reachable to anyone who knows the hostname, so for anything internal add a Cloudflare Access application in the Zero Trust dashboard: define the application by hostname, then a policy allowing your identity provider group or one-time PIN emails. Requests then hit a login page before reaching the tunnel. Verify from outside the network:

```
dig +short app.example.com
curl -sI https://app.example.com | head -3
```

The address returned is Cloudflare’s, not yours, and the response should be the application or the Access login page. The Zero Trust dashboard shows the tunnel as healthy with the connector count. The classic pitfall is a service configured as `https://localhost` while the application only speaks HTTP, which produces a 502 from the edge; match the scheme to what the origin listens on. Tunnel hostnames must also be proxied, so if you later toggle the orange cloud off in DNS the tunnel stops working.

## Cloudflare Tunnel at a glance

**Official documentation:** [Cloudflare developer docs](https://developers.cloudflare.com/), [AlmaLinux wiki](https://wiki.almalinux.org/), [Linux man pages](https://man7.org/linux/man-pages/).

**Related guides:** [Troubleshoot MTU, fragmentation and slow VPN throughput](https://srvscripts.com/guides/vpn-mtu-fragmentation/) · [Fix Cloudflare errors 521, 522 and 525 on cPanel servers](https://srvscripts.com/guides/cloudflare-error-521-522-525-cpanel/) · [Set up a site-to-site WireGuard VPN between pfSense and OPNsense](https://srvscripts.com/guides/site-to-site-wireguard-pfsense-opnsense/).

## Frequently asked questions

### Does Cloudflare Tunnel also work for SSH and RDP, not just websites?

Yes. Set the ingress service to `ssh://localhost:22` or `rdp://host:3389` and have clients connect through cloudflared in proxy mode or through the browser-rendered terminal in Zero Trust.

### How long does it take to set up a Cloudflare Tunnel?

Installing cloudflared, creating the tunnel, writing the config and starting the service takes about fifteen minutes. DNS changes made through the route command are live within a minute.

### Can I undo a tunnel and go back to a port forward?

Yes. Stop and disable the service, run `cloudflared tunnel delete app`, remove the CNAME records, and reinstate the DNS A record and firewall rules for the origin; nothing on the origin server is altered by the tunnel.
