How to Install and Use Cloudflared on Linux to Securely Expose Local Services

Exposing local development environments, self-hosted web applications, or remote SSH servers to the internet traditionally required configuring complex router port forwarding, setting up dynamic DNS records, and exposing home IP addresses directly to public network scanners. Cloudflare Tunnels, powered by the open-source cloudflared daemon, revolutionise this paradigm by establishing outbound-only, encrypted connections between your Linux host and the global Cloudflare edge network.

By routing inbound traffic through authenticated outbound tunnels, you can publish internal HTTP web services, reverse proxies, and administrative consoles without opening a single inbound port on your firewall or router. This comprehensive guide walks you through installing cloudflared on Linux, authenticating your host, configuring persistent named tunnels, routing custom DNS subdomains, and running the daemon as a resilient background systemd service.


Prerequisites and Environment Verification

Before installing and configuring cloudflared, verify that your environment satisfies the following operational requirements:

  • Supported Linux Distribution: Ubuntu 22.04/24.04 LTS, Debian 11/12, Fedora 39/40, RHEL/Rocky Linux 9, or Arch Linux running on x86_64 or arm64 hardware.
  • Cloudflare Account and Active Domain: A free or paid Cloudflare account managing an active domain whose nameservers point to Cloudflare DNS.
  • Administrative Privileges: Root or sudo access to install system binaries and manage systemd system services.
  • Local Service to Expose: An active local service listening on localhost (such as Nginx on port 80, a Docker container on port 8080, or a Node.js development server on port 3000).

Step 1: Installing Cloudflared on Linux

Cloudflare publishes official precompiled binaries and package repositories across all primary Linux distributions. Select the appropriate installation method for your system.

Method A: On Ubuntu and Debian Systems

Add Cloudflare’s official GPG key and APT repository to ensure automated security updates via standard package management:

# Create the keyrings directory
sudo mkdir -p --mode=0755 /etc/apt/keyrings

# Download and import the Cloudflare GPG key
curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg | sudo tee /etc/apt/keyrings/cloudflare-main.gpg > /dev/null

# Add the official cloudflared repository to your APT sources
echo 'deb [signed-by=/etc/apt/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared jammy main' | sudo tee /etc/apt/sources.list.d/cloudflared.list

# Update package lists and install cloudflared
sudo apt update
sudo apt install -y cloudflared

Method B: On Fedora, RHEL, and CentOS Stream

Download and install the official RPM package directly from Cloudflare’s package mirror:

# Install cloudflared via DNF/RPM
sudo dnf install -y https://pkg.cloudflare.com/cloudflared-ascii.repo
sudo dnf install -y cloudflared

Method C: Standalone Binary (Universal)

If you prefer a direct standalone binary or run an alternative distribution such as Alpine or Arch Linux:

# Download the latest 64-bit Linux binary
curl -L --output cloudflared https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64

# Grant execution permissions and move to system path
chmod +x cloudflared
sudo mv cloudflared /usr/local/bin/cloudflared

Confirm successful installation by checking the installed version string:

cloudflared --version

Step 2: Authenticating Cloudflared with Your Cloudflare Account

To authorize cloudflared to generate tunnels and update DNS records across your domain, authenticate the client against your Cloudflare account:

cloudflared tunnel login

Executing this command produces an interactive authentication URL in your terminal:

Please open the following URL and log in with your Cloudflare account:

https://dash.cloudflare.com/argotunnel?callback=https%3A%2F%2Flogin.cloudflareaccess.org%2F...

Leave cloudflared running to download the cert flag.
  1. Copy the displayed link and paste it into any web browser.
  2. Log in to your Cloudflare dashboard and select the authoritative domain you wish to associate with your tunnels.
  3. Click Authorise to grant the certificate permissions.

Once authenticated in your browser, cloudflared automatically downloads an origin certificate and saves it to ~/.cloudflared/cert.pem. Verify that the file exists:

ls -l ~/.cloudflared/cert.pem

Step 3: Creating a Named Persistent Tunnel

Ephemeral, ad-hoc tunnels (such as cloudflared tunnel --url localhost:8080) generate temporary random URLs. For reliable, production-ready hosting, create a persistent named tunnel:

cloudflared tunnel create web-production

The command output displays your unique Tunnel UUID and saves an associated tunnel credentials JSON file:

Tunnel credentials written to /home/user/.cloudflared/a1b2c3d4-e5f6-7890-abcd-1234567890ab.json.
Created tunnel web-production with id a1b2c3d4-e5f6-7890-abcd-1234567890ab

Record your Tunnel ID (UUID), as you will reference it in your configuration and routing rules. You can inspect all registered tunnels at any time:

cloudflared tunnel list

Step 4: Configuring Ingress Routing Rules

Cloudflared uses a structured YAML configuration file to map incoming public hostnames to internal network services. Create the configuration file at ~/.cloudflared/config.yml:

nano ~/.cloudflared/config.yml

Populate the file with your Tunnel ID, credentials path, and ingress definitions:

tunnel: a1b2c3d4-e5f6-7890-abcd-1234567890ab
credentials-file: /home/user/.cloudflared/a1b2c3d4-e5f6-7890-abcd-1234567890ab.json

ingress:
  # Map subdomains to specific internal services
  - hostname: app.yourdomain.com
    service: http://localhost:8080
    originRequest:
      connectTimeout: 30s
      noTLSVerify: false

  # Optional admin dashboard on another local port
  - hostname: monitor.yourdomain.com
    service: http://localhost:9090

  # Mandatory catch-all rule for unmatched requests
  - service: http_status:404

Save and close the file. Note that Cloudflare ingress rules evaluate sequentially; the final catch-all rule (service: http_status:404) is strictly required to handle unrouted traffic gracefully.


Step 5: Routing DNS Traffic to Your Tunnel

Now configure Cloudflare DNS to point your designated public subdomain (e.g., app.yourdomain.com) to the named tunnel using the CLI:

cloudflared tunnel route dns web-production app.yourdomain.com

This command automatically injects a CNAME record into your Cloudflare DNS zone pointing app.yourdomain.com to a1b2c3d4-e5f6-7890-abcd-1234567890ab.cfargotunnel.com with Cloudflare proxying enabled.

Validate your configuration file syntax before launching the tunnel:

cloudflared tunnel ingress validate

Test the tunnel directly in foreground mode to verify end-to-end traffic flow:

cloudflared tunnel run web-production

Open a web browser and visit https://app.yourdomain.com. Your internal service should respond with a valid Cloudflare SSL certificate. Press Ctrl + C in your terminal to stop the foreground test.


Step 6: Running Cloudflared as a Systemd Service

To guarantee that your tunnel starts automatically upon system reboot and restarts in the event of transient failures, install cloudflared as a system-wide background service.

  1. Move the tunnel configuration and credentials to the global system directory /etc/cloudflared/:
    sudo mkdir -p /etc/cloudflared
    sudo cp ~/.cloudflared/config.yml /etc/cloudflared/config.yml
    sudo cp ~/.cloudflared/*.json /etc/cloudflared/
  2. Update the credentials-file path inside /etc/cloudflared/config.yml to reflect the new location:
    credentials-file: /etc/cloudflared/a1b2c3d4-e5f6-7890-abcd-1234567890ab.json
  3. Register the system service using Cloudflared’s built-in installer:
    sudo cloudflared service install
  4. Enable and start the cloudflared systemd service:
    sudo systemctl enable cloudflared
    sudo systemctl start cloudflared
  5. Verify the runtime status of the daemon:
    sudo systemctl status cloudflared

Essential Operational and Monitoring Commands

The following table outlines standard management commands for maintaining your Cloudflare Tunnels:

Command Operational Purpose
cloudflared tunnel list Displays all active, inactive, and deleted tunnels in your account.
cloudflared tunnel info <name> Shows tunnel connection state, active connectors, and IP metrics.
sudo journalctl -u cloudflared -f Streams real-time connection and routing logs from systemd.
cloudflared tunnel route ip show Lists private subnet IP routes configured through the tunnel.
sudo systemctl restart cloudflared Reloads the configuration file after updating ingress rules.
cloudflared tunnel delete <name> Deletes a tunnel and invalidates its remote credentials.

Troubleshooting Common Cloudflared Issues

1. “Origin Certificate Missing or Expired”

If you encounter authentication errors when creating tunnels, ensure ~/.cloudflared/cert.pem exists and possesses valid read permissions. Run cloudflared tunnel login again to refresh credentials.

2. “502 Bad Gateway” on Public URL

A 502 error returned by Cloudflare indicates that cloudflared is connected to Cloudflare’s edge, but cannot establish a connection to your internal service. Verify that your target application is actively listening on the exact port specified in config.yml:

curl -I http://localhost:8080
sudo ss -tulpn | grep 8080

3. “TLS Verification Failed for Local HTTPS Backend”

If your local backend utilizes a self-signed SSL/TLS certificate (such as an internal Proxmox or router web GUI), add noTLSVerify: true under the originRequest block in /etc/cloudflared/config.yml:

ingress:
  - hostname: pve.yourdomain.com
    service: https://localhost:8006
    originRequest:
      noTLSVerify: true
  - service: http_status:404

Save the file and run sudo systemctl restart cloudflared to apply the change.

Get the best tech tips delivered straight to your inbox.

Join thousands of readers mastering Apple, Google, Microsoft, and Linux.