找回密码
 注册
查看: 1|回复: 1

Cloudflare Tunnel Setup

[复制链接]
发表于 昨天 22:22 | 显示全部楼层 |阅读模式
What Cloudflare Tunnel actually does

Cloudflare Tunnel flips the usual model of exposing a server to the internet. Instead of Cloudflare (or anyone else) initiating a connection to your machine, your machine initiates the connection to Cloudflare. The cloudflared daemon runs on your server, laptop, Raspberry Pi, or inside a container, and opens a persistent, encrypted outbound connection to the nearest Cloudflare data center. That connection stays open. When a visitor requests your hostname, the request lands on Cloudflare’s edge, gets matched against the ingress rules you defined for that tunnel, and gets forwarded back down the existing outbound tunnel to your local service.
The practical result: no inbound firewall rule, no port forward on your router, and no need for a static or even public IP address. Your origin server can sit behind carrier-grade NAT on a residential connection and still serve traffic reliably, because the connection direction never reverses. This is also why the setup plays well with mobile hotspots, CGNAT ISPs, and locked-down corporate networks where inbound traffic is blocked by policy — cloudflared only ever needs outbound HTTPS.
Cloudflare Tunnel is distinct from Cloudflare WARP, which is the client-side agent that runs on end-user devices and routes their traffic through Cloudflare’s network for policy enforcement. Tunnel is the server-side half: it’s what exposes a private origin or network to Cloudflare. The two are commonly paired — WARP-enrolled devices can reach an entire private subnet published through a tunnel using Cloudflare’s private network routing, without publishing each individual application hostname by hand.
Why teams are moving off port forwarding

Port forwarding has always carried a specific set of risks that most self-hosters accept without fully pricing in. Forwarding a port means the router hands a direct path from the public internet straight to a device on the local network. Every automated scanner sweeping IPv4 space eventually finds it, and from that point on the exposed service — not Cloudflare’s edge, not a CDN, just the raw application — is the only thing standing between an attacker and whatever’s running behind it. Unpatched software, weak default credentials, and misconfigured admin panels turn a convenience feature into an incident.
Cloudflare Tunnel changes the attack surface rather than just adding a layer on top of it. Because the origin never listens on a public port, there’s nothing for a port scanner to find in the first place — the only publicly resolvable address is Cloudflare’s own edge IP, which also happens to absorb the bulk of common Layer 3/4 DDoS traffic before it ever reaches your ingress rules. That doesn’t make an application immune to being compromised through legitimate-looking HTTP requests, but it removes an entire category of opportunistic, automated port-scanning attacks that have nothing to do with the application’s own security posture.
There’s also a practical, non-security reason this approach has spread through homelab and small-team setups so quickly: residential ISPs increasingly deploy carrier-grade NAT, which makes traditional port forwarding impossible without paying extra for a static IP or begging an ISP for one. An outbound-only tunnel sidesteps that constraint entirely, since it never needs the ISP to route anything inbound at all.
Prerequisites

Before starting, make sure the following are in place. None of this requires a paid Cloudflare plan.
  • A domain added to Cloudflare with active nameservers (the Free plan is sufficient)
  • cloudflared version 2026.9.1 or later (check with cloudflared --version after install)
  • A Linux, macOS, or Windows machine, or a Docker host, to run the connector
  • A local service to expose — this guide uses a self-hosted app on port 8080 as the running example
  • A Cloudflare account with the domain’s zone (no credit card required for the Free Zero Trust plan)
  • Root or sudo access on the host machine for the systemd service step
  • Roughly 45–60 minutes for the full walkthrough, including the Access policy at the end

If you don’t have a spare domain, Cloudflare’s registrar and most third-party registrars support adding a domain to a Cloudflare zone for free; DNS propagation typically completes within a few minutes to a few hours depending on your registrar and previous TTL settings.
Step 1: Install cloudflared

Cloudflare distributes cloudflared as standalone binaries, .deb and .rpm packages, a Homebrew formula, and a Docker image, covering Windows, macOS, Linux, ARM, and ARM64. Pick the method that matches your platform.
  1. # macOS (Homebrew)
  2. brew install cloudflared

  3. # Debian/Ubuntu
  4. curl -L --output cloudflared.deb https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
  5. sudo dpkg -i cloudflared.deb

  6. # Verify the install
  7. cloudflared --version
复制代码

Expected output looks like cloudflared version 2026.9.1 (built 2026-09-11). If the command isn’t found on Linux after the .deb install, confirm /usr/local/bin or /usr/bin is on your PATH — the package generally places the binary automatically, but minimal containers sometimes need a manual symlink.
Step 2: Authenticate cloudflared against your account

Named tunnels — the persistent, production-grade kind — need to be tied to your Cloudflare account and a specific zone. Run the login command, which opens a browser window for authentication and zone authorization.
  1. cloudflared tunnel login
复制代码

Select the domain you want to use in the browser prompt. On success, cloudflared writes a certificate file to ~/.cloudflared/cert.pem (or the equivalent path on Windows). That certificate is what authorizes this machine to create and manage tunnels for the zone — treat it like any other credential and don’t commit it to a repository.
Step 3: Create a named tunnel

With the certificate in place, create the tunnel itself. This generates a UUID and a credentials JSON file that cloudflared uses to authenticate the tunnel connection going forward.
  1. cloudflared tunnel create home-labcloudflared tunnel list
复制代码

Output example:
  1. ID                                   NAME       CREATED
  2. a1b2c3d4-e5f6-7890-abcd-ef1234567890 home-lab   2026-09-22T14:02:11Z

  3. Tunnel credentials written to /root/.cloudflared/a1b2c3d4-e5f6-7890-abcd-ef1234567890.json.
  4. cloudflared chose this file based on where your origin certificate was found.
  5. Keep this file secret. To revoke these credentials, delete the tunnel.</span>
复制代码

That credentials file is the single point of compromise for the tunnel — anyone with it can impersonate your connector. Restrict its permissions with chmod 600 and keep it out of version control and shared backups.
Step 4: Write the ingress configuration

Cloudflare Tunnel routes traffic based on an ingress block in a YAML config file, evaluated top to bottom, with the last rule acting as a catch-all. Create /etc/cloudflared/config.yml:
  1. tunnel: a1b2c3d4-e5f6-7890-abcd-ef1234567890
  2. credentials-file: /etc/cloudflared/a1b2c3d4-e5f6-7890-abcd-ef1234567890.json

  3. ingress:
  4.   - hostname: app.example.com
  5.     service: http://192.168.1.20:8080

  6.   - hostname: ssh.example.com
  7.     service: ssh://192.168.1.30:22

  8.   - service: http_status:404</span>
复制代码

Each hostname maps to a local service address. The final line, http_status:404, is mandatory in practice — without a catch-all rule, cloudflared will refuse to start or will silently drop unmatched requests. Before running anything, validate the syntax:
  1. cloudflared tunnel ingress validate
复制代码


Step 5: Route DNS to the tunnel

Each hostname in your ingress block needs a matching DNS record pointing at the tunnel. cloudflared can create this automatically:
  1. cloudflared tunnel route dns home-lab app.example.com
  2. <div>cloudflared tunnel route dns home-lab ssh.example.com</div>
复制代码
Step 6: Run the tunnel

Start the tunnel in the foreground first to confirm everything connects before wiring it into a service manager:
  1. cloudflared tunnel --config /etc/cloudflared/config.yml run home-lab
复制代码

A healthy connection produces log lines similar to:
  1. INF Starting tunnel tunnelID=a1b2c3d4-e5f6-7890-abcd-ef1234567890
  2. INF Connection registered connIndex=0 location=lhr08
  3. INF Connection registered connIndex=1 location=lhr03
  4. INF Registered tunnel connection connIndex=2
复制代码

cloudflared opens multiple redundant connections (typically four) to different edge locations for resilience. Visit https://app.example.com in a browser — traffic should now reach your local service with zero inbound firewall rules involved.
Step 7: Install cloudflared as a persistent systemd service

Running the tunnel in a foreground terminal is fine for testing but won’t survive a reboot or a closed SSH session. On Linux, install it as a systemd service:
  1. sudo cloudflared service install
  2. sudo systemctl enable --now cloudflared
  3. sudo systemctl status cloudflared
  4. journalctl -u cloudflared -f
复制代码

The service install command reads your existing config and credentials from the default cloudflared directory and registers a unit that starts on boot. Confirm the service user has read access to both the config file and the credentials JSON — a common failure here is a permissions mismatch after moving files into /etc/cloudflared/.
Step 8: Run cloudflared in Docker instead

If your workloads already live in containers, skip the CLI-managed tunnel and run cloudflared itself as a container, authenticated with a token generated from the Zero Trust dashboard rather than the local certificate file. This is the simpler path for anyone running Docker Compose stacks.
  1. services:
  2.   cloudflared:
  3.     image: cloudflare/cloudflared:2026.9.1
  4.     container_name: cloudflared
  5.     command: tunnel --no-autoupdate run
  6.     environment:
  7.       - TUNNEL_TOKEN=${TUNNEL_TOKEN}
  8.     restart: unless-stopped
  9.     networks:
  10.       - app-net

  11. networks:
  12.   app-net:
  13.     external: true
复制代码

Create the tunnel and its token in the Zero Trust dashboard under Networks > Tunnels, copy the token into a local .env file as TUNNEL_TOKEN=eyJ..., and point the ingress hostnames at your container service names (for example http://plex:32400) instead of raw IP addresses, since containers on the same Docker network resolve each other by name.
Step 9: Add Cloudflare Access in front of the tunnel

A tunnel alone only handles connectivity — it doesn’t gate who’s allowed in. For anything beyond a public marketing page, put a Cloudflare Access policy in front of the hostname. In the Zero Trust dashboard, go to Access > Applications, add a self-hosted application for app.example.com, and attach a policy.
  • Require login via an identity provider (Google, GitHub, Microsoft Entra, or a generic SAML/OIDC provider)
  • Restrict access to a specific email address or an entire email domain
  • Require a specific group membership synced from your identity provider
  • Enforce device posture checks (managed device, disk encryption, certain OS version)
  • Use a service token for machine-to-machine calls that shouldn’t go through a login screen

Once the policy is active, visiting the hostname redirects to a Cloudflare-hosted login page before any request reaches your origin server at all — the authentication happens at the edge, not in your application. Teams that need to block automated bot traffic on a public-facing hostname rather than gate it behind a login can layer in Cloudflare Turnstile as a lighter-weight alternative to a full Access policy. This is the layer that turns “no open ports” into “no open ports and no unauthenticated access,” which matters far more once SSH or RDP hostnames are involved.
Step 10: Publish SSH and RDP through the tunnel

The same ingress mechanism that routes HTTP traffic can front raw TCP services like SSH and RDP. Add entries to the ingress block:
  1. ingress:
  2.   - hostname: ssh.example.com
  3.     service: ssh://10.0.0.10:22
  4.   - hostname: desktop.example.com
  5.     service: rdp://10.0.0.20:3389
  6.   - service: http_status:404
复制代码

Connect through the tunnel with the cloudflared access ssh helper or an SSH config entry using ProxyCommand cloudflared access ssh --hostname %h. Never publish SSH or RDP without an Access policy in front of it — a bare tunnel hostname with no authentication layer is functionally the same exposure as forwarding the port directly, just with better DDoS protection.
Step 11: Test with a Quick Tunnel before committing to the named setup

For one-off testing or sharing a local dev server without touching DNS at all, cloudflared supports Quick Tunnels — no account, no config file, no login required.
  1. cloudflared tunnel --url http://localhost:3000
复制代码

This prints a random trycloudflare.com hostname that proxies to your local port for as long as the process stays running. It’s genuinely useful for demoing a build to a client or testing a webhook callback, but the hostname is temporary, unauthenticated by default, and disappears the moment you kill the process — it isn’t a substitute for a named tunnel in any production or even semi-permanent homelab context.
Step 12: Run cloudflared as a Kubernetes ingress

For clusters, cloudflared can run as a standard Deployment authenticated with a tunnel token, routing traffic to Kubernetes Services without exposing a NodePort or LoadBalancer at all.
  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4.   name: cloudflared
  5. spec:
  6.   replicas: 2
  7.   selector:
  8.     matchLabels:
  9.       app: cloudflared
  10.   template:
  11.     metadata:
  12.       labels:
  13.         app: cloudflared
  14.     spec:
  15.       containers:
  16.         - name: cloudflared
  17.           image: cloudflare/cloudflared:2026.9.1
  18.           args: ["tunnel", "--no-autoupdate", "run"]
  19.           env:
  20.             - name: TUNNEL_TOKEN
  21.               valueFrom:
  22.                 secretKeyRef:
  23.                   name: cloudflared-token
  24.                   key: token
复制代码

Running two replicas gives you redundant connectors to the same tunnel — if one pod is rescheduled, the other keeps serving traffic. Point the ingress rules at internal ClusterIP service DNS names (for example http://my-app.default.svc.cluster.local:80) rather than pod IPs, since those change on every restart.
Step 13: Verify, monitor, and rotate credentials

With the tunnel live, confirm its health and set up basic monitoring hygiene:
  1. cloudflared tunnel info home-lab
  2. cloudflared tunnel list
复制代码

In the Zero Trust dashboard under Networks > Tunnels, each tunnel shows connector health, uptime, and the data centers it’s connected to. Application-level Access logs — who logged in, from where, and whether the policy allowed or blocked the request — live under Logs > Access. Rotate the tunnel credentials periodically by deleting and recreating the tunnel if you suspect the credentials file has leaked; there’s no in-place key rotation for a locally-managed tunnel’s certificate.
Worth setting up early rather than after something goes wrong: alerting on connector disconnects. The Zero Trust dashboard supports notification rules that fire when a tunnel’s connector count drops to zero, which is the earliest signal that a homelab service has quietly gone offline — often hours or days before anyone notices manually. For anything you actually depend on daily, that alert is the difference between a five-minute fix and discovering the outage the next time you try to use the service yourself.



September 22, 2026 Nadia Dubois


来自圈子: 动手动脚
 楼主| 发表于 昨天 22:23 | 显示全部楼层
本帖最后由 Test 于 2026-9-24 22:25 编辑

Migrating from an existing port-forward setup

Moving a service that’s already publicly reachable through a forwarded port over to a tunnel is straightforward, but doing it out of order causes downtime. Follow this sequence rather than improvising:
  • Stand up the tunnel and ingress rule pointing at the service on a temporary hostname first, and confirm it works end to end before touching the production hostname.
  • Once confirmed, update the DNS record for the real hostname with cloudflared tunnel route dns — this overwrites the existing A record with a proxied CNAME to the tunnel.
  • Watch application logs for a few minutes to confirm real traffic is arriving through the tunnel rather than the old direct path.
  • Only after traffic is confirmed flowing through Cloudflare should you remove the router’s port-forward rule and close the corresponding firewall exception.
  • Wait out the DNS record’s previous TTL before assuming every client has picked up the change — cached resolvers elsewhere on the internet may still be pointed at the old IP for a while.
Keeping the old port-forward rule active for a short overlap window, rather than deleting it immediately, gives you a rollback path if something about the tunnel configuration turns out to be wrong once real traffic hits it.

Named tunnels vs. Quick Tunnels


It’s worth being explicit about when each mode fits, since mixing them up is one of the most common setup mistakes.

AttributeNamed tunnelQuick Tunnel
Setup requirement
Account login, tunnel create, config file
None — single command
Hostname
Your own domain, stable
Random trycloudflare.com subdomain
Persistence
Survives restarts as a service
Dies when the process exits
Access policy support
Full Zero Trust Access integration
Not supported
DNS control
Managed via cloudflared or dashboard
None
Intended use
Production, homelab, long-running services
Demos, quick tests, one-off sharing


Common use cases for a self-hosted setup

Cloudflare Tunnel has become a default recommendation in homelab communities specifically because it removes the router-configuration step that trips up so many first-time self-hosters. Typical deployments include media servers like Plex and Jellyfin, home automation dashboards such as Home Assistant, photo backup tools like Immich, file sync platforms like Nextcloud, internal admin dashboards, CI webhook receivers, and local development servers that need to be reachable from a phone or a third-party service mid-build. Many of these homelab stacks already run a network-wide ad blocker like Pi-hole alongside the tunnel, since both tools are commonly deployed on the same always-on hardware.
For media servers specifically, check the application’s own terms and any upload or transcoding limits before assuming every workload behaves identically once proxied through Cloudflare’s edge — large binary transfers and long-lived streaming connections don’t all behave the same way a lightweight dashboard does. Test with your actual traffic pattern rather than assuming.
Development teams have adopted the same pattern for a different reason: sharing an in-progress build with a designer, client, or QA tester who isn’t on the local network. Rather than deploying to a staging environment for every small change, a named tunnel pointed at a local dev server gives reviewers a stable, bookmarkable URL that updates the moment the local server reloads. Combined with an Access policy scoped to a specific list of reviewer email addresses, this avoids the common failure mode of a staging environment link leaking into a public issue tracker or chat log and being crawled by search engines or scrapers.

Pricing: what’s actually free


The tunnel connector itself carries no separate charge and no bandwidth metering tied to the tunnel feature. What can cost money is the Zero Trust plan tier once you exceed its free allowances for seats and certain Gateway features.

PlanPriceUser capNotes
Free
$0
Up to 50 users
Covers most homelab and solo-developer use cases
Pay-as-you-go / Standard
~$7/user/month (billed annually)
No cap
Average allowance of roughly 150,000 Gateway DNS queries per seat/month
Enterprise / Contract
Custom, negotiated
No cap
Extended log retention, SLA, dedicated support
For a single person running a tunnel in front of a handful of self-hosted apps, the Free plan’s 50-user cap is never going to be the binding constraint — you’ll stay on the free tier indefinitely unless you’re deploying Access policies across a team or organization. Confirm current entitlements on Cloudflare’s own Zero Trust pricing page before budgeting for a larger rollout, since plan terms are subject to change. For a broader look at how Cloudflare’s Zero Trust suite stacks up against enterprise SASE platforms, see our comparison of Cloudflare One, Zscaler, and Netskope.

Cloudflare Tunnel vs. the alternatives


Cloudflare Tunnel isn’t the only way to expose a private service without opening a port, and it isn’t always the right tool. The table below lines it up against the three most common alternatives.

ToolModelCostBest fit
Cloudflare Tunnel
Outbound connector to Cloudflare’s edge
Free connector; Access seats billable past 50 users
Public-facing apps needing identity-aware access control
ngrok
Managed reverse tunnel
Plan- and feature-dependent
Fast dev-server sharing, webhook testing
Tailscale Funnel
Publishes a node on an existing Tailscale mesh
Tied to current Tailscale plan
Teams already running a Tailscale mesh network
WireGuard + reverse proxy
Self-managed VPN on a public VPS
VPS hosting, bandwidth, and admin time
Full control, no dependency on a managed edge
If you’re already running a Tailscale mesh network for device-to-device access, Funnel is the natural extension for the handful of services you want public. If you want maximum independence from any managed provider, a self-hosted WireGuard VPN in front of your own reverse proxy remains the most control-heavy option, at the cost of maintaining a public IP, TLS certificates, and patching cadence yourself. Cloudflare Tunnel sits in between: less operational overhead than self-hosting, but with a dependency on Cloudflare’s edge being available and configured correctly.
The cost comparison against a self-managed VPS reverse proxy is worth spelling out, because it’s rarely a simple dollar-for-dollar swap. A basic VPS running Nginx or Caddy as a reverse proxy typically runs somewhere between $5 and $12 a month for a small instance, plus the ongoing time cost of patching the OS, renewing TLS certificates, monitoring uptime, and responding to the occasional security advisory. Cloudflare Tunnel removes the VPS line item entirely for anyone already running the origin service on hardware they own, since the connector runs directly on that hardware and the edge termination, TLS, and DDoS absorption are handled by Cloudflare. What you give up is provider independence — if Cloudflare’s edge has a regional issue, tunnel-routed traffic is affected the same way any service behind a CDN would be, whereas a VPS-hosted reverse proxy fails independently of any third party’s infrastructure.

Combining Tunnel with an existing reverse proxy


Most homelab setups already run Nginx Proxy Manager, Caddy, or Traefik to route multiple internal hostnames to different containers. Cloudflare Tunnel doesn’t replace that layer — it sits in front of it. Point a single ingress rule at your reverse proxy’s local listener rather than trying to route every hostname through cloudflared directly:
  1. ingress:
  2.   - hostname: "*.example.com"
  3.     service: http://192.168.1.5:80
  4.   - service: http_status:404
复制代码

This wildcard pattern hands every subdomain to your existing reverse proxy, which continues to handle its own internal routing logic. The key rule: only one layer should terminate and manage a given hostname’s TLS and routing — running Cloudflare’s proxy and your reverse proxy’s own certificate management on the same hostname simultaneously is a common source of redirect loops.

Private network routing: reaching a whole subnet through one tunnel


Publishing individual hostnames works well for a handful of applications, but it gets tedious once a homelab grows past a dozen services, several of which don’t speak HTTP at all — a network printer, a NAS admin interface, an internal database only meant for other machines on the LAN. Cloudflare’s private network routing, sometimes called WARP-to-Tunnel routing, solves this differently: instead of publishing each service as its own hostname, you route an entire private IP range through the tunnel and let devices running the WARP client reach anything in that range directly, the same way they would if they were physically on the local network.
Configure it by adding a private network route to the tunnel rather than an ingress hostname rule:
  1. cloudflared tunnel route ip add 192.168.1.0/24 home-lab
复制代码

Once that route exists, any device enrolled in your Zero Trust organization and running the WARP client can reach 192.168.1.0/24 as if it were on the same network — no per-service DNS record, no individual ingress rule. This is the right tool when the goal is “give my own devices transparent access to my home network,” and the wrong tool when the goal is “let a specific person authenticate into one specific web app,” which is what the Access-gated hostname pattern from earlier in this guide is built for. Most real deployments end up using both: hostname-based Access policies for anything meant to be reachable by other people, and private network routing for the admin’s own device-to-network access.

Common pitfalls

These are the mistakes that come up most often in setup walkthroughs and community threads.
  • Forgetting the catch-all ingress rule. Every config needs a final service: http_status:404 line, or cloudflared will refuse to start.
  • Leaving the credentials JSON world-readable. Run chmod 600 on the credentials file immediately after tunnel creation.
  • Publishing SSH or RDP with no Access policy. A tunnel without an authentication layer in front of it is not meaningfully more secure than a forwarded port.
  • Mixing Quick Tunnels and named tunnels. Quick Tunnel hostnames are temporary — don’t bookmark or hardcode a trycloudflare.com URL anywhere permanent.
  • Conflicting DNS records. An existing A or CNAME record on the target hostname will block tunnel route dns from succeeding; delete it first.
  • Pointing ingress at pod IPs in Kubernetes. Pod IPs change on every reschedule — always use a stable Service DNS name instead.
  • Running two reverse proxies on the same hostname. Let either Cloudflare’s proxy or your local reverse proxy manage a given hostname’s TLS — never both.



Troubleshooting


The most common failure modes and how to work through them:
  • Error 1033 (Argo Tunnel error). Cloudflare can’t reach a healthy connector. Run cloudflared tunnel info home-lab to check connection status, then inspect the connector’s own logs for a crash or disconnect.
  • Tunnel process starts but never registers. Check outbound egress on port 443/7844 isn’t blocked by a local firewall, corporate proxy, or ISP-level filtering; cloudflared needs outbound HTTPS and QUIC to reach Cloudflare’s edge.
  • DNS not resolving to the tunnel. Confirm the hostname sits in the same Cloudflare zone you authenticated against, and that tunnel route dns actually completed — check the DNS tab in the dashboard for the CNAME record.
  • 502 Bad Gateway. Cloudflare reached your connector, but the connector couldn’t reach the local service. Test directly from the host running cloudflared: curl -v http://192.168.1.20:8080. Check the port, protocol (http vs. https), and any local firewall on the origin machine.
  • Docker container can’t resolve service names. Confirm the cloudflared container is attached to the same Docker network as the target service, and reference it by container/service name, not localhost.
  • Access policy loops back to login repeatedly. Clear browser cookies for the hostname and confirm the identity provider integration in Zero Trust is correctly configured; a broken IdP callback URL is the usual culprit.
  • Config validates but the tunnel won’t start as a service. Check journalctl -u cloudflared -f for a permissions error — the systemd service user often can’t read a credentials file created under a different user’s home directory.
  • Multiple ingress rules matching unexpectedly. Rules are evaluated top-to-bottom and the first match wins; reorder more specific hostnames above wildcard rules.
  • Certificate errors between cloudflared and the local service. If the origin service uses a self-signed TLS certificate, add originServerName or set noTLSVerify: true on that specific ingress rule rather than disabling verification globally.
  • High latency compared to a direct connection. Traffic now makes an extra hop through Cloudflare’s edge; for most self-hosted apps this adds low single-digit milliseconds, but confirm the nearest edge location in the connector logs if latency seems unusually high, since a misconfigured DNS resolver can sometimes route the initial handshake to a distant data center.



Advanced tips


A few patterns worth adopting once the basic tunnel is stable:
  • Run redundant connectors. Deploy cloudflared on two separate machines pointed at the same tunnel credentials for automatic failover if one host goes down.
  • Use service tokens for automation. Machine-to-machine calls (CI pipelines hitting an internal API, for example) should authenticate with a Cloudflare Access service token rather than a human login flow.
  • Separate hostnames by trust level. Keep low-risk public pages on one hostname with no Access policy and administrative interfaces on a separate hostname with a strict policy — don’t rely on application-level path routing alone.
  • Pin the image version in Docker. Avoid tracking :latest in production; pin to a tested tag like 2026.9.1 and upgrade deliberately.
  • Use private network routing for whole-subnet access. Rather than publishing every device individually, WARP-to-Tunnel private routing lets enrolled devices reach an entire RFC1918 range through one tunnel.
  • Watch the Access audit logs. The Zero Trust dashboard’s Logs section records every authentication decision — review it periodically for unexpected access attempts.

Complete working example: a homelab dashboard behind Access


Putting the full pattern together — a Docker Compose stack running a dashboard app, cloudflared, and an Access policy gating the hostname:
  1. services:
  2.   dashboard:
  3.     image: ghcr.io/example/homelab-dashboard:latest
  4.     container_name: dashboard
  5.     restart: unless-stopped
  6.     networks:
  7.       - app-net

  8.   cloudflared:
  9.     image: cloudflare/cloudflared:2026.9.1
  10.     container_name: cloudflared
  11.     command: tunnel --no-autoupdate run
  12.     environment:
  13.       - TUNNEL_TOKEN=${TUNNEL_TOKEN}
  14.     restart: unless-stopped
  15.     depends_on:
  16.       - dashboard
  17.     networks:
  18.       - app-net

  19. networks:
  20.   app-net:
  21.     driver: bridge
复制代码

In the Zero Trust dashboard, the tunnel’s ingress rule points dashboard.example.com at http://dashboard:80 — the container’s service name resolves inside the shared Docker network. The Access application attached to that hostname requires login through your identity provider and restricts entry to a specific email domain. The result: a dashboard reachable from anywhere on the internet, with zero open inbound ports on the host and a login screen enforced entirely at Cloudflare’s edge before any request reaches the container.

Frequently asked questions


Is Cloudflare Tunnel actually free?
The tunnel connector and its bandwidth are free with no metered charge. Costs only appear if you need more than 50 Zero Trust seats or move to paid Access/Gateway features, which most solo and homelab setups never hit.
Does my domain have to be registered through Cloudflare?
No. The domain just needs to be added as a zone with Cloudflare’s nameservers active; it can be registered anywhere.
Can I run multiple services through one tunnel?
Yes — a single tunnel can host any number of ingress rules, each mapping a different hostname to a different local service or port.
What happens if Cloudflare has an outage?
Since all traffic routes through Cloudflare’s edge, an outage there would affect tunnel availability, the same dependency risk that applies to any provider sitting in front of your origin. This is the core trade-off against a self-managed reverse proxy.
Is a Quick Tunnel safe to leave running long-term?
No. Quick Tunnels are meant for short-lived testing, generate a random hostname with no Access policy support, and disappear the moment the process stops.
Can I tunnel a database connection?
Technically yes via TCP ingress rules, but exposing a database directly — even behind a tunnel — is generally poor practice. Put an application layer or strict Access service-token policy in front of any database access instead.
How is this different from a VPN?
A VPN like WireGuard connects a device to a private network broadly; Cloudflare Tunnel publishes specific services to specific hostnames, optionally gated by identity-aware Access policies, without granting broad network-level access.
Do I need a paid plan to use Access policies?
No — Access policies, including identity provider login and email restrictions, are available on the Free Zero Trust plan up to 50 users.
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|小黑屋|BC Morning Website ( Best Deal Inc. 001 )

GMT-8, 2026-9-25 14:27 , Processed in 0.012908 second(s), 16 queries .

Supported by BestDeal Online X5.0

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表