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/ |
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:
- Navigate to the Cloudflare Zero Trust dashboard at
one.dash.cloudflare.com - Go to Access → Applications and create a new self-hosted application
- Set the application domain to match your tunneled hostname
- Configure an Access policy (e.g., allow specific email addresses or IdP groups)
- 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) |