What is Cloudflare Tunnel?

Cloudflare Tunnel (formerly Argo Tunnel) creates a secure, outbound-only connection between your RamNode VPS and the Cloudflare network. Instead of exposing your server's IP address or opening inbound firewall ports, the cloudflared daemon establishes encrypted tunnels that route traffic through Cloudflare's edge.

  • No Open Ports: Outbound-only connections
  • Free TLS: Automatic SSL certificates
  • Multi-Service: Route multiple subdomains through one tunnel
  • DDoS Protection: Cloudflare edge shields your origin
  • Zero Trust: Identity-aware access policies
  • Lightweight: Under 50 MB RAM usage

Prerequisites

What You Will Need

  • A RamNode VPS running Ubuntu 22.04 or 24.04 (Debian also works)
  • A domain name with DNS managed by Cloudflare (free plan is sufficient)
  • A Cloudflare account with at least one active zone
  • Root or sudo access on your VPS
  • One or more local services to expose (web server, API, SSH, etc.)

Recommended VPS Specifications

Use Case Recommended Plan Notes
Single web app or blog 1 GB RAM VPS More than sufficient for cloudflared plus a small app
Multiple tunneled services 2 GB RAM VPS Room for several containers or services
High-traffic API gateway 4 GB+ RAM VPS Extra headroom for concurrent connections

Install cloudflared

Install from the official APT repository for automatic updates.

Add Cloudflare GPG Key & Repository

sudo mkdir -p --mode=0755 /usr/share/keyrings

curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg \
  | sudo tee /usr/share/keyrings/cloudflare-main.gpg > /dev/null

echo "deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] \
  https://pkg.cloudflare.com/cloudflared $(lsb_release -cs) main" \
  | sudo tee /etc/apt/sources.list.d/cloudflared.list

Install the Package

sudo apt update
sudo apt install -y cloudflared

Verify Installation

cloudflared --version

📝 Note: If you prefer a manual installation, download the latest .deb package from the Cloudflare GitHub releases page and install with dpkg -i.

Authenticate with Cloudflare

Link your VPS to your Cloudflare account. This generates a certificate that authorizes tunnel and DNS management.

Login to Cloudflare

cloudflared tunnel login

This outputs a URL. Copy and paste it into your browser, select the domain you want to use, and authorize. After authorization, a certificate is saved to:

Certificate Location

~/.cloudflared/cert.pem

🔒 Security: Keep cert.pem secure. It grants full tunnel management permissions for the selected zone.

💡 Tip: On a headless VPS without a browser, copy the URL and open it on any device where you are logged into your Cloudflare dashboard.

Create a Tunnel

Create the Tunnel

cloudflared tunnel create my-ramnode-tunnel

Expected Output

Created tunnel my-ramnode-tunnel with id a1b2c3d4-e5f6-7890-abcd-ef1234567890

The tunnel credentials JSON file is stored at ~/.cloudflared/<UUID>.json. Make a note of the tunnel UUID — you'll reference it in the configuration file.

Configure the Tunnel

Create Config Directory

sudo mkdir -p /etc/cloudflared
sudo nano /etc/cloudflared/config.yml

Basic Configuration (Single Service)

config.yml — Single Service


tunnel: a1b2c3d4-e5f6-7890-abcd-ef1234567890
credentials-file: /root/.cloudflared/a1b2c3d4-e5f6-7890-abcd-ef1234567890.json

ingress:
  - hostname: app.example.com
    service: http://localhost:8080
  - service: http_status:404

⚠️ Important: The final catch-all rule (- service: http_status:404) is required. Cloudflare Tunnel will not start without it.

Multi-Service Configuration

Route multiple subdomains through a single tunnel:

config.yml — Multi-Service


tunnel: a1b2c3d4-e5f6-7890-abcd-ef1234567890
credentials-file: /root/.cloudflared/a1b2c3d4-e5f6-7890-abcd-ef1234567890.json

ingress:
  - hostname: app.example.com
    service: http://localhost:8080

- hostname: api.example.com
    service: http://localhost:3000

- hostname: grafana.example.com
    service: http://localhost:3001

- hostname: ssh.example.com
    service: ssh://localhost:22

- service: http_status:404

Configuration Options Reference

Option Description Example
tunnel Your tunnel UUID a1b2c3d4-...
credentials-file Path to tunnel credentials JSON /root/.cloudflared/.json
protocol Connection protocol auto, quic, http2
logfile Path for log output /var/log/cloudflared.log
metrics Prometheus metrics endpoint localhost:2000
no-tls-verify Skip TLS verification (dev only) true

Route DNS

Create DNS records that point your hostnames to the tunnel:

Create DNS Routes

cloudflared tunnel route dns my-ramnode-tunnel app.example.com
cloudflared tunnel route dns my-ramnode-tunnel api.example.com
cloudflared tunnel route dns my-ramnode-tunnel grafana.example.com

Each command creates a CNAME record pointing to your tunnel's unique hostname. Verify the records in your Cloudflare dashboard under DNS settings — each should show the orange proxy icon enabled.

Test the Tunnel

Run the tunnel manually before setting it up as a service:

Run Tunnel in Foreground

cloudflared tunnel --config /etc/cloudflared/config.yml run

You should see log output indicating connections to multiple Cloudflare edge locations. Open your configured hostname in a browser to confirm your service is accessible.

Troubleshooting Common Issues

502 Bad Gateway: Local service is not running. Start your application and verify it responds on the configured port.

Tunnel won't start: Missing catch-all ingress rule. Add - service: http_status:404 as the last entry.

DNS not resolving: CNAME record not created. Run cloudflared tunnel route dns for the hostname.

Connection refused: Wrong port in config. Verify your service listens on the port specified in config.yml.

Certificate error: Expired or missing cert.pem. Re-run cloudflared tunnel login.

Run as a systemd Service

For production, run cloudflared as a background service that starts on boot and restarts on failure.

Install the Service

sudo cloudflared service install

This creates a systemd unit file and copies your configuration to system directories.

Manage the Service

# Start the tunnel
sudo systemctl start cloudflared

# Enable on boot
sudo systemctl enable cloudflared

# Check status
sudo systemctl status cloudflared

# View logs
sudo journalctl -u cloudflared -f

💡 Tip: After installing the service, config changes should be made to /etc/cloudflared/config.yml followed by sudo systemctl restart cloudflared.

Security Hardening

Restrict Inbound Firewall Rules

Since all traffic flows through the tunnel, you can block inbound HTTP/HTTPS entirely:

Lock Down UFW

# Allow SSH (keep unless tunneling SSH too)
sudo ufw allow 22/tcp

# Deny all other inbound traffic
sudo ufw default deny incoming
sudo ufw default allow outgoing

# Enable the firewall
sudo ufw enable
sudo ufw status verbose

📝 Note: If you also tunnel SSH, you can remove the SSH allow rule for a fully locked-down server. Keep a backup access method (RamNode console) in case the tunnel goes down.

Enable Cloudflare Access (Zero Trust)

Put authentication in front of any tunneled service — especially admin panels and dashboards:

  1. Navigate to the Cloudflare Zero Trust dashboard at one.dash.cloudflare.com
  2. Go to Access → Applications and create a new self-hosted application
  3. Set the application domain to match your tunneled hostname
  4. Configure an Access policy (e.g., allow specific email addresses or IdP groups)
  5. Save and test in an incognito window

Keep cloudflared Updated

Update cloudflared

sudo apt update && sudo apt upgrade -y
sudo systemctl restart cloudflared

Monitor Tunnel Health

Enable Prometheus-compatible metrics by adding to your config:

Add to config.yml (top level)

metrics: localhost:2000

This exposes metrics at http://localhost:2000/metrics for integration with Grafana and Prometheus.

Advanced Configuration

Docker Integration

Point the tunnel at Docker container ports or use Docker's internal network:

Docker Ingress Example

ingress:
  - hostname: app.example.com
    service: http://172.17.0.2:8080        # Docker container IP

- hostname: db-admin.example.com
    service: http://host.docker.internal:8081  # Host-mapped port

- service: http_status:404

💡 Tip: For Docker Compose setups, run cloudflared as a container in the same network to reference services by name.

Load Balancing & Replicas

Run multiple instances of the same tunnel across different servers for high availability. Each replica uses the same UUID and credentials. Cloudflare distributes traffic automatically.

Run Replica on Each VPS

cloudflared tunnel --config /etc/cloudflared/config.yml run

Private Networking with WARP

For internal services that shouldn't be publicly accessible, use Cloudflare Tunnel with the WARP client. Team members connect through WARP and access internal IPs or hostnames directly, without public DNS exposure.

Quick Reference

Essential Commands

Command Description
cloudflared tunnel login Authenticate with Cloudflare
cloudflared tunnel create <name> Create a new tunnel
cloudflared tunnel list List all tunnels
cloudflared tunnel info <name> Show tunnel details
cloudflared tunnel route dns <tunnel> <hostname> Create DNS route
cloudflared tunnel run Start tunnel (foreground)
cloudflared tunnel delete <name> Delete a tunnel
sudo systemctl restart cloudflared Restart the tunnel service
sudo journalctl -u cloudflared -f Tail tunnel logs

Key File Locations

Path Description
~/.cloudflared/cert.pem Account authentication certificate
~/.cloudflared/<UUID>.json Tunnel credentials file
/etc/cloudflared/config.yml System-level tunnel configuration
/var/log/cloudflared.log Log file (if configured)