# cloudflared: the Cloudflare Tunnel client that reaches your origin without opening a port

> cloudflared is Cloudflare's Go client for Tunnel. It dials out to Cloudflare's edge and carries public hostnames or private traffic back to services you never expose. Here is how it is installed, how the connection is wired, and where it stops being the right tool.

**cloudflare/cloudflared** — Cloudflare Tunnel client

- Repository: https://github.com/cloudflare/cloudflared
- Website: https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/
- Stars: 15,916 · Forks: 1,455
- Language: Go
- License: Apache-2.0
- Published: 2026-09-21 · Updated: 2026-09-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/cloudflare-cloudflared

## The problem cloudflared solves, and who ends up running it

Most ways of publishing a service start by making the service reachable. You open a port, you write an ingress rule, you terminate TLS somewhere. cloudflared inverts that. The daemon runs next to your origin, dials out to the Cloudflare network, and Cloudflare sends client requests down that established connection. The README puts it plainly: the daemon "sits between Cloudflare network and your origin", and your origin "can remain as closed as possible". Nothing needs to listen on a public interface.

The people who end up running it are not only the ones publishing websites. The README separates two usages. Proxying to origins lives under cloudflared tunnel help. Reaching Tunnel-protected origins over TCP at Layer 4, for SSH or RDP, lives under cloudflared access help. That second group matters because it changes who installs what: the server side runs the tunnel, and the client side either runs cloudflared access or uses the WARP client instead. The README notes WARP can reach private origins behind Tunnels for Layer 4 traffic without requiring cloudflared access commands on the client machine.

There is a precondition that surprises people. Before using Tunnel you add a website to your Cloudflare account and move your nameservers to Cloudflare. The README is candid that this is a legacy requirement: Tunnel without a website is possible today, for private routing, but the account setup step is still expected. If you are evaluating cloudflared as a general-purpose tunnel for a domain you do not control, that is the first wall you hit.

## How the daemon, the edge and your origin fit together

The repository layout reflects the split. There is an ingress/ directory, a connection/ directory, an edgediscovery/ directory, and a flow/ directory. Those names describe the shape of the thing: cloudflared discovers Cloudflare edge addresses, establishes connections to them, and applies ingress rules that map incoming hostnames or paths onto local services. Traffic arrives from the edge over that connection and is handed to the origin. Nothing in that path requires an inbound firewall rule.

The transport is not a single protocol. The dependency list in go.mod includes quic-go, two WebSocket libraries (gorilla/websocket and nhooyr.io/websocket, plus gobwas/ws), and capnproto2. The README does not spell out which protocol is used when, so treat transport selection as documented elsewhere rather than in this repository's README. What the repository does show is that cloudflared is built to speak several of them.

Operationally, two things in the repository are worth knowing before you deploy. The metrics/ package exists and the Dockerfile passes CONTAINER_BUILD=1, which the comment says sets github.com/cloudflare/cloudflared/metrics.Runtime=virtual and changes how cloudflared binds the metrics server. In other words, the metrics behaviour differs between a container build and a normal build. The other is the updater: the Dockerfile's ENTRYPOINT is cloudflared --no-autoupdate, because a container should not update itself. On a host install, the update path is a real part of the design, and the README points at Cloudflare's update-cloudflared documentation for it.

## Installing cloudflared and running a first tunnel

The README lists the distribution channels: standalone binaries, a Docker image, and Debian, RPM, and Homebrew packages. macOS goes through Homebrew or a Darwin amd64 release. Linux binaries and Debian and RPM packages are linked from the downloads page. Windows has its own documented steps. Building from source needs the Go version named in the Development section, plus GNU Make and capnp, and the README gives the command as make cloudflared.

If you already have Go 1.26 or newer and the other build requirements, the source build is one command:

```bash
make cloudflared
```

The README states this builds cloudflared locally. The output binary is named cloudflared, unless you set FIPS=true, in which case the Makefile names it cloudflared-fips. For most readers the packaged install is faster than a source build, and the README's downloads page is the place it points to for Linux packages.

Once the binary is present, the README says you authenticate cloudflared into your Cloudflare account and then create Tunnels. The documented sequence is: authenticate, create a tunnel, then route traffic to it either through public DNS records in Cloudflare, through a Cloudflare Load Balancer, or through WARP client private traffic. The README links each of those steps to the Cloudflare Tunnel documentation rather than reproducing the commands here, so the exact subcommands belong to that documentation.

If you want to see the daemon run before committing an account and a domain, the README points at TryCloudflare, which it describes as a way to test Cloudflare Tunnel before adding a website to Cloudflare. That is the lowest-commitment first run, and it is the path to take if you are still deciding whether Tunnel fits.

For a container deployment, the Dockerfile builds the binary and copies it into a distroless base image, then sets USER 65532:65532 and ENTRYPOINT ["cloudflared", "--no-autoupdate"]. The default CMD is version, which means a container started with no arguments prints the version and exits. You supply the real command yourself.

```dockerfile
ENTRYPOINT ["cloudflared", "--no-autoupdate"]
CMD ["version"]
```

Those two lines are the image's actual entrypoint and default command. The README does not document a specific docker run invocation, so take the arguments from the Cloudflare Tunnel documentation rather than inventing flags.

## The one-year support window is the constraint that bites

The README's deprecation policy is unusually explicit and it should shape how you run cloudflared. Cloudflare supports versions within one year of the most recent release. Breaking changes unrelated to feature availability may be introduced that affect anything older than that. The README's own example: as of January 2023, support covered cloudflared 2023.1.1 back to 2022.1.1.

Read that against the release cadence visible in the repository. Releases arrive as 2026.9.1, 2026.9.0, 2026.8.3, so roughly several per month. A pinned version ages out of support in about a year, and the project reserves the right to break things once it does. If your deployment process treats a tunnel binary like a static appliance, you will be running unsupported software within twelve months. The README also states that removal of CLI flags, environment variables, configuration keys, or commands counts as a breaking change and must be announced in the Cloudflare Tunnel changelog before the release that removes them. That gives you a place to watch, but it also tells you removals do happen.

The update mechanism itself is part of the binary. The Dockerfile disables it with --no-autoupdate because containers should be rebuilt, not self-updated. On hosts, the updater is present, and the README directs you to Cloudflare's update-cloudflared documentation. Whichever route you take, the upgrade cost is not zero: it is a recurring operational task tied to a twelve-month clock.

Licensing is Apache-2.0, which permits commercial use and modification, with the usual obligations around notices and the absence of a patent or warranty grant beyond what the licence states. That is a description of the licence file, not legal advice; if your organisation has a policy on Apache-2.0 dependencies, this one falls under it.

## Where cloudflared is the wrong tool

The clearest limitation is the account requirement. Tunnel assumes Cloudflare is in the path. The README explains that you must add a website to your Cloudflare account and change your nameservers to Cloudflare, even though it acknowledges Tunnel without a website is possible today for private routing. If your organisation cannot move DNS to Cloudflare, or you need the same tunnel to work across two providers, cloudflared is not the answer. You are not buying a protocol; you are buying a path through one network.

The second limitation is client-side reach. cloudflared access exists for Layer 4 traffic, but the README frames it as something you may avoid entirely: the WARP client can reach private origins behind Tunnels for Layer 4 traffic without requiring cloudflared access commands on the client side. That is a real fork in the road. If your users cannot install WARP and you do not want to distribute cloudflared access, your Layer 4 story is weaker than the README's summary suggests.

Third, the README is thin on failure behaviour. It does not document rollback, it does not describe what happens to in-flight connections when a tunnel restarts, and it does not specify which transport is chosen under which conditions. The repository has the packages for retry and backoff (github.com/cloudflare/backoff is a direct dependency) and a diagnostic/ directory, which suggests the project takes observability seriously, but the README itself does not explain them. If you need documented failure semantics before adopting, this README will not give them to you, and you should read the Cloudflare Tunnel product documentation instead.

## What you would use instead, and how it differs

The obvious alternative is a self-hosted tunnel such as frp or a WireGuard-based mesh. The difference is not speed; it is who terminates the public side. With cloudflared, Cloudflare's edge accepts the client connection, applies its own TLS and DDoS handling, and forwards down the tunnel. Your origin never sees a public socket. With a self-hosted tunnel, you run the public endpoint yourself, which means you own the certificate, the IP reputation, the rate limiting, and the availability of that endpoint. You gain provider independence and lose the edge network.

A second alternative is a plain reverse proxy with a port forward. That is simpler and has no account requirement, but it puts a listening port on the internet, which is exactly the thing cloudflared's README says it removes. For a homelab service you do not care about, the reverse proxy wins on setup time. For anything where you would rather not publish an IP, the tunnel wins.

The third option is the WARP client alone. The README presents WARP as the way to reach private origins behind Tunnels for Layer 4 traffic without cloudflared access on the client. That is not a replacement for cloudflared, because something still has to run the tunnel on the origin side, but it is a replacement for the client-side binary, and it changes what you have to deploy to end users.

## Building on cloudflared from source

If you are contributing rather than deploying, the README's Development section lists the requirements: GNU Make, capnp, and Go 1.26 or newer, with optional capnpc-go, goimports, golangci-lint, and gomocks. The build is make cloudflared, tests are make test, formatting and linting are make fmt and make lint, and interface changes may require make mocks.

There is a hook installer worth knowing about because it prevents a class of CI failures:

```bash
make install-hooks
```

The README states this configures git to use the hooks in .githooks/, which run make fmt-check lint test before each push. The .githooks/ directory is present in the repository root, so the mechanism is real rather than aspirational. If you plan to send patches, running that once saves you a round trip with CI.

The Makefile also reveals how release artifacts are shaped. Version information is injected through linker flags from main.Version and main.BuildTime, and when PACKAGE_MANAGER is defined it also sets github.com/cloudflare/cloudflared/cmd/cloudflared/updater.BuiltForPackageManager. That matters if you build your own package: the updater behaves differently depending on how the binary was produced, so a hand-rolled build is not identical to the published one.

## Conclusion

Adopt cloudflared when your origin can make outbound connections and you want Cloudflare's edge to be the only public surface, and when a Cloudflare account with a zone is acceptable. Do not adopt it if you need a vendor-neutral tunnel, if you cannot add a website to Cloudflare, or if your team will not track the one-year support window on releases. Before rolling it out, check the current version against the deprecation policy, confirm the Docker image runs as user 65532, and decide whether you need cloudflared access or the WARP client for Layer 4 traffic.

## FAQ

### What does cloudflared do?

It is the command-line client for Cloudflare Tunnel, described in the README as a tunneling daemon that proxies traffic from the Cloudflare network to your origins. It runs next to your origin and connects outward, so the origin does not need an open inbound port.

### What is the difference between cloudflared and Cloudflare?

Cloudflare is the network and account; cloudflared is the client daemon you install on your side. The README describes the daemon as sitting between the Cloudflare network and your origin, receiving client requests that Cloudflare attracted and delivering them to you.

### How do I install cloudflared on Debian?

The README lists Debian and RPM packages for Linux, alongside standalone binaries, a Docker image and Homebrew. It links to Cloudflare's downloads page for the Linux packages rather than reproducing the package commands in the repository.

### How do I install cloudflared on Windows?

The README says Windows machines are covered by the steps on Cloudflare's downloads page, and the repository also contains cloudflared.wxs, an MSI definition. The README does not restate the Windows installation commands itself.

### How do I install cloudflared on Ubuntu?

Ubuntu installs follow the same Linux path the README describes: Debian packages, RPM packages or standalone binaries, all linked from Cloudflare's downloads page. The README does not give an Ubuntu-specific command sequence.

### How do I use cloudflared tunnel?

The README's sequence is to authenticate cloudflared into your Cloudflare account, create a Tunnel, then route traffic to it through public DNS records in Cloudflare, a Cloudflare Load Balancer, or WARP client private traffic. It links each step to the Cloudflare Tunnel documentation for the exact commands.

## Sources

- [cloudflare/cloudflared on GitHub](https://github.com/cloudflare/cloudflared)
- [License: Apache-2.0](https://github.com/cloudflare/cloudflared/blob/master/LICENSE)
- [Project website](https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/)
- [README](https://github.com/cloudflare/cloudflared/blob/master/README.md)
- [Releases](https://github.com/cloudflare/cloudflared/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/cloudflare-cloudflared
