How do I set up Cloudflare Tunnel (cloudflared) to publish an internal app without opening inbound ports?
Edge Security & CDN

How do I set up Cloudflare Tunnel (cloudflared) to publish an internal app without opening inbound ports?

11 min read

Publishing an internal app through Cloudflare Tunnel with cloudflared lets you put Cloudflare’s global network in front of your service without opening a single inbound port on your firewall. Instead of exposing your network, you create an outbound-only tunnel from your environment to Cloudflare; all user traffic then flows through Cloudflare’s edge, where it can be authenticated, logged, and accelerated before reaching your app.

Quick Answer: Cloudflare Tunnel (via the cloudflared daemon) creates a secure, outbound-only connection from your internal environment to Cloudflare’s edge. You map a public hostname to your internal app, and Cloudflare routes traffic through that tunnel—so you never open inbound ports or manage complex ACLs on your perimeter.

The Quick Overview

  • What It Is: A secure, outbound-only tunnel service (Cloudflare Tunnel, powered by cloudflared) that connects internal web apps and services to Cloudflare’s connectivity cloud, eliminating the need to expose them directly to the Internet.
  • Who It Is For: Security and IT teams, DevOps engineers, and developers who want to publish internal apps, APIs, dashboards, and admin tools without VPN friction and without opening inbound firewall ports.
  • Core Problem Solved: It removes the attack surface created by open inbound ports and traditional reverse proxies, while still allowing users to reach internal apps via a simple HTTPS URL, protected and accelerated by Cloudflare.

How It Works

At a high level, you install cloudflared next to your internal app and authenticate it to your Cloudflare account. cloudflared then establishes an encrypted, outbound-only connection (Cloudflare Tunnel) to Cloudflare’s global network. You create a DNS record (typically a CNAME) for your app’s hostname and map it to the tunnel. When a user goes to that hostname, their HTTP(S) request is routed to the nearest Cloudflare data center, evaluated for security (and Zero Trust policies, if you enable Access), and then sent back down the tunnel to your internal app—no inbound ports, no direct exposure.

  1. Connect your environment with cloudflared:
    Install cloudflared on the server or network segment that can reach your internal app (e.g., a Linux VM in your data center, a Docker container in Kubernetes, or a small VM in your cloud VPC). Authenticate cloudflared to your Cloudflare account and create a named tunnel.

  2. Map a public hostname to your internal app:
    Within the tunnel configuration, define one or more routes that map a Cloudflare DNS hostname (e.g., internal-app.example.com) to your internal service (e.g., http://127.0.0.1:8080 or http://10.0.0.25:3000). Cloudflare automatically creates the required DNS record and associates it with the tunnel.

  3. Route user traffic through Cloudflare’s edge:
    When users hit https://internal-app.example.com, Cloudflare terminates TLS at the edge, applies security and Zero Trust policies (Cloudflare Access, WAF, bot defenses as needed), then forwards the request down the tunnel to your app. Responses travel back up the same path. Open inbound ports are no longer necessary; the only “public” artifact is the DNS record, which you can protect with authentication and logging.


Below is a practical, step-by-step view of how to set this up, plus how to layer in Cloudflare Access so your internal app “feels like SaaS” but never sits directly on the Internet.

Step 1: Prerequisites and basic architecture

Before you start:

  • You have a Cloudflare account and a domain (e.g., example.com) onboarded to Cloudflare DNS.
  • You have an internal web app reachable from the host where you’ll run cloudflared (for example, http://localhost:8080 or http://10.0.0.25:8080).
  • You can run a persistent service/daemon in your environment (VM, container, etc.).

Architecture in plain terms:

  • Your firewall remains outbound-only for this app. No new inbound rules, no port forwarding.
  • cloudflared runs inside your environment and initiates connections to Cloudflare’s edge.
  • Users connect to Cloudflare via HTTPS; Cloudflare routes the request internally over its network and down the tunnel to your app, using Argo Smart Routing to pick fast paths within the network.

Step 2: Install and authenticate cloudflared

Install cloudflared

On a typical Linux server:

# Debian/Ubuntu example
curl -L https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb -o cloudflared.deb
sudo dpkg -i cloudflared.deb

On macOS (Homebrew):

brew install cloudflare/cloudflare/cloudflared

On Windows (PowerShell, as Administrator):

choco install cloudflared

Or use Docker:

docker pull cloudflare/cloudflared:latest

Check that it installed correctly:

cloudflared --version

Authenticate cloudflared with your Cloudflare account

Run:

cloudflared login

This will:

  1. Open a browser window prompting you to log in to your Cloudflare account.
  2. Ask you to select the zone (domain) you want to use for the tunnel (e.g., example.com).
  3. Download a certificate file (typically cert.pem) that lets cloudflared create and manage tunnels for that zone.

This ties your local cloudflared instance to your Cloudflare account and DNS zone.

Step 3: Create a named Cloudflare Tunnel

Create a tunnel (give it a descriptive name aligned to the app or environment):

cloudflared tunnel create internal-app-tunnel

This command:

  • Creates a named tunnel in your Cloudflare account.
  • Generates a tunnel UUID and a credentials file (for example:
    /etc/cloudflared/<TUNNEL-UUID>.json).

You’ll reference this tunnel by name or UUID in the configuration file and when you run the service.

Step 4: Configure the tunnel to route traffic to your internal app

Cloudflare Tunnel uses a YAML configuration file, usually at /etc/cloudflared/config.yml (Linux) or a similar path depending on your OS.

Create or edit config.yml:

tunnel: internal-app-tunnel
credentials-file: /etc/cloudflared/<TUNNEL-UUID>.json

ingress:
  - hostname: internal-app.example.com
    service: http://127.0.0.1:8080
  # Catch-all rule for anything not matched above
  - service: http_status:404

Key pieces:

  • tunnel: Must match the name you created (internal-app-tunnel) or the tunnel UUID.
  • credentials-file: Path to the tunnel credentials JSON created earlier.
  • ingress:
    • hostname is the public DNS name users will visit.
    • service is your internal app endpoint, which can be:
      • http://localhost:8080 if the app is on the same host as cloudflared.
      • http://10.0.0.25:8080 or similar if the app is on another internal host reachable over your network.
    • The last rule (http_status:404) is a safety catch-all.

Cloudflare will create the DNS record for internal-app.example.com when you run the next command.

Step 5: Route your hostname through the tunnel

Create the DNS route:

cloudflared tunnel route dns internal-app-tunnel internal-app.example.com

This:

  • Creates a DNS record (typically a CNAME) for internal-app.example.com in your Cloudflare zone.
  • Associates that hostname with your named tunnel, so any request that hits that hostname will be sent through the tunnel.

At this point, the DNS is wired to the tunnel, but your tunnel still needs to be running.

Step 6: Run cloudflared as a service (persistent tunnel)

First, test-run the tunnel in the foreground:

cloudflared tunnel run internal-app-tunnel

You should see logs indicating that the tunnel is established and connected to multiple edge locations. Test your app by going to:

https://internal-app.example.com

If everything looks good, configure cloudflared to run as a service so the tunnel is always on.

Example: Linux systemd service

Cloudflare provides a helper:

sudo cloudflared service install

This typically:

  • Installs a cloudflared systemd unit.
  • Uses /etc/cloudflared/config.yml as the configuration.
  • Starts the service and enables it on boot.

You can then manage the tunnel with:

sudo systemctl status cloudflared
sudo systemctl restart cloudflared
sudo journalctl -u cloudflared -f

Step 7: Add Zero Trust protection with Cloudflare Access (optional but recommended)

Right now, your app is available over the Internet at internal-app.example.com, but you haven’t yet enforced who can see it. To avoid turning an “internal app” into a public one, pair Cloudflare Tunnel with Cloudflare Access:

  • Access applies Zero Trust checks at Cloudflare’s edge: every request is evaluated for identity and context before it reaches your app.
  • You can integrate with your identity provider (IdP) like Okta, Azure AD, Google Workspace, and others.
  • For users, your internal app feels like SaaS: they go to a URL, hit an SSO flow, and they’re in—no VPN client, no split-tunnel headaches.

Configure an Access application for your hostname

  1. In the Cloudflare dashboard, go to Zero Trust (Cloudflare One).
  2. Navigate to Access → Applications → Add an application.
  3. Select Self-hosted.
  4. For Application name:
    Internal App
  5. For Domain:
    internal-app.example.com
  6. Configure your Identity Providers (Okta, Azure AD, etc.) if you haven’t already.
  7. Add Access policies, for example:
    • Allow only users in your corporate email domain:
      • Action: Allow
      • Include: Emails ending in @yourcompany.com
    • Require MFA, device posture, or group membership for sensitive apps.
  8. Save the application.

Now:

  • When someone browses to https://internal-app.example.com, Cloudflare prompts them to authenticate via your chosen IdP.
  • Only after successful authentication and policy evaluation does Cloudflare forward the request down the tunnel.
  • Your internal app stays unaware of the public Internet; Cloudflare Access acts like a “bouncer” in front of the tunnel.

Features & Benefits Breakdown

Core FeatureWhat It DoesPrimary Benefit
Outbound-only Cloudflare TunnelUses cloudflared to establish an encrypted, outbound-only tunnel from your environment to Cloudflare.Eliminates the need to open inbound firewall ports or manage brittle ACLs for app publishing.
Hostname-to-service mapping (ingress)Maps a public Cloudflare DNS hostname to an internal service (HTTP, HTTPS, TCP) via YAML config.Lets internal apps “look like SaaS” behind a friendly URL without changing app code or topology.
Zero Trust enforcement via AccessEvaluates every request at the edge for identity and policy using your IdP before it hits your app.Replaces VPN-based access for internal apps with SSO, MFA, and detailed logging at Cloudflare’s edge.

Ideal Use Cases

  • Best for publishing internal web apps without VPN:
    Because Cloudflare Tunnel and Access let you expose tools like admin dashboards, intranet sites, or status pages via a URL, enforce SSO/MFA at the edge, and keep all firewall rules outbound-only.

  • Best for hybrid and multi-cloud environments:
    Because cloudflared can run wherever your workloads live (on-prem, cloud VMs, containers, Kubernetes), and Cloudflare’s connectivity cloud unifies access policies and routing across all of them without backhauling.

Limitations & Considerations

  • Not a replacement for every network path (by itself):
    Cloudflare Tunnel with cloudflared is ideal for HTTP(S) and many TCP-based apps, but if you need full WAN replacement, site-to-site, or broader SASE, consider combining it with broader Cloudflare One capabilities (e.g., Cloudflare Tunnel for Services + Magic WAN, WARP clients, etc.).

  • Requires stable outbound connectivity from your environment:
    If your environment has strict egress filtering, you must allow cloudflared to reach Cloudflare’s edge over HTTPS. Keep egress firewall rules updated and monitor cloudflared logs for connectivity issues.

Pricing & Plans

Cloudflare Tunnel is available across multiple plan tiers, and many teams start with lower-tier plans to validate the pattern, then move to Enterprise for scale, compliance, and advanced controls.

  • Standard Plans (Free/Pro/Business):
    Best for teams needing to securely publish a handful of internal apps, test Zero Trust patterns, or front individual services with Access and WAF protections. Good for pilot deployments, small teams, or departmental tools.

  • Enterprise Plan:
    Best for organizations needing large-scale tunnel deployments, formal SLAs, advanced Zero Trust and SASE capabilities, detailed logging and analytics, support for regulated environments, and integration with broader Cloudflare One (Cloudflare Access, Gateway, Magic WAN, Magic Firewall).

For tailored pricing, architecture guidance, and deployment best practices across multiple regions and environments, you can talk directly to Cloudflare’s Enterprise team.

Frequently Asked Questions

Do I really not need to open any inbound ports on my firewall?

Short Answer: Correct—Cloudflare Tunnel with cloudflared works with outbound-only connectivity; no inbound ports or public IP exposure are required.

Details:
cloudflared runs from inside your environment and dials out to Cloudflare’s edge over HTTPS, forming a secure, persistent tunnel. Cloudflare never connects directly to your internal IP over the public Internet—traffic traverses the established tunnel. From an attacker’s perspective, your app has no open ports; the only visible artifact is a DNS name that terminates at Cloudflare’s network, where you can enforce Zero Trust policies and logging. This eliminates a major attack vector: open inbound ports that listen for unauthenticated traffic.

Can I use Cloudflare Tunnel for non-HTTP services (SSH, RDP, databases)?

Short Answer: Yes, but you’ll configure the tunnel and Access differently for TCP/SSH/RDP than for pure web apps.

Details:
Cloudflare Tunnel supports more than just HTTP(S). You can:

  • Use Cloudflare Access with cloudflared for SSH or RDP, so developers and admins reach internal servers through Cloudflare’s edge rather than via a traditional VPN.
  • Expose TCP-based services (e.g., databases) with specific configuration, usually pairing cloudflared on the client side to connect through the tunnel securely.

The core pattern stays the same: no inbound ports to your network, an outbound tunnel from inside, and request-level or session-level access controls applied at Cloudflare’s edge. For broad coverage of web apps, SSH, RDP, and more under a single Zero Trust fabric, Cloudflare Tunnel works as part of Cloudflare One.

Summary

Setting up Cloudflare Tunnel with cloudflared to publish an internal app is about changing the direction of trust: you stop inviting the Internet into your network via open ports, and instead let a small, authenticated agent (cloudflared) call out to Cloudflare’s connectivity cloud. A named tunnel, a simple YAML config, and a DNS hostname are enough to route user traffic through Cloudflare’s edge, where you can enforce Zero Trust via Cloudflare Access, apply WAF and other protections, and log every request. Your internal app remains on private IP space with outbound-only firewall rules—yet behaves to users like any modern SaaS application.

Next Step

Get Started