Zero-Trust Networking

    Deploy Cloudflare Tunnel on RamNode VPS

    Expose local services securely without opening firewall ports. Zero-trust access for web apps, APIs, SSH, and more.

    Ubuntu 22.04/24.04 LTS
    No Open Ports
    ⏱️ 15-20 minutes

    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
    1

    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 CaseRecommended PlanNotes
    Single web app or blog1 GB RAM VPSMore than sufficient for cloudflared plus a small app
    Multiple tunneled services2 GB RAM VPSRoom for several containers or services
    High-traffic API gateway4 GB+ RAM VPSExtra headroom for concurrent connections

    View Cloud VPS Plans →

    2

    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.
    3

    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.
    4

    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.

    5

    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

    OptionDescriptionExample
    tunnelYour tunnel UUIDa1b2c3d4-...
    credentials-filePath to tunnel credentials JSON/root/.cloudflared/<UUID>.json
    protocolConnection protocolauto, quic, http2
    logfilePath for log output/var/log/cloudflared.log
    metricsPrometheus metrics endpointlocalhost:2000
    no-tls-verifySkip TLS verification (dev only)true
    6

    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.

    7

    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.
    8

    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.
    9

    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.

    10

    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

    CommandDescription
    cloudflared tunnel loginAuthenticate with Cloudflare
    cloudflared tunnel create <name>Create a new tunnel
    cloudflared tunnel listList all tunnels
    cloudflared tunnel info <name>Show tunnel details
    cloudflared tunnel route dns <tunnel> <hostname>Create DNS route
    cloudflared tunnel runStart tunnel (foreground)
    cloudflared tunnel delete <name>Delete a tunnel
    sudo systemctl restart cloudflaredRestart the tunnel service
    sudo journalctl -u cloudflared -fTail tunnel logs

    Key File Locations

    PathDescription
    ~/.cloudflared/cert.pemAccount authentication certificate
    ~/.cloudflared/<UUID>.jsonTunnel credentials file
    /etc/cloudflared/config.ymlSystem-level tunnel configuration
    /var/log/cloudflared.logLog file (if configured)