Skip to main contentSkip to navigation
[email protected]
Client AreaSupport
Hosting Mammoth
HostingMammothYour Data, Our Responsibility
Home
Solutions
Hosting Services
Store
Pricing
About
Blog
API
Contact

Stay Ahead of the Curve

Get the latest insights on cybersecurity, AI innovations, and enterprise data solutions delivered to your inbox.

Hosting Mammoth
HostingMammothEnterprise Solutions

Enterprise-grade data solutions. Hosting, recovery, cybersecurity, and AI-powered services for businesses worldwide.

[email protected]
Sun - Fri, 9:00am - 5:00pm

Services

  • Cloud Hosting
  • Data Recovery
  • Cybersecurity
  • Legal Support
  • MSP Services
  • Web Development
  • AI Services
  • Free Server Migration

Hosting

  • VPS Hosting (NVMe SSD)
  • VDS Hosting (NVMe)
  • Storage VPS (High SSD)
  • GPU Servers
  • Managed Services
  • Cloud Firewall
  • Load Balancer
  • One-Click Apps
  • n8n Hosting
  • Object Storage
  • FAQ

Company

  • Store
  • Pricing
  • About Us
  • Locations
  • Blog
  • Testimonials
  • Contact
  • Affiliate Program
  • White-Label
  • Terms of Service
  • Privacy Policy
  • Browser Cookies
  • SLA

Support

  • Client Area
  • Submit Ticket
  • Knowledge Base
  • Server Status
  • API Documentation

© 2026 Hosting Mammoth. All rights reserved.

Knowledge Base
Getting StartedAccount ManagementVPS HostingGPU ServersStorage VPSCloud FirewallLoad BalancerServer ManagementBilling & PaymentsSupport & TicketsAffiliate ProgramReseller ProgramMarketplace & Appsn8n HostingManaged ServicesServer MigrationAPI & DevelopersSecurityTroubleshootingGlossaryInstall Guides
  1. Home
  2. /
  3. Support
  4. /
  5. Install Guides
  6. /
  7. How To Install Cloudflared Tunnel Ubuntu
GUIDEInstall Guides

How to Set Up Cloudflare Tunnel on Ubuntu 24.04 VPS: Expose Services Without Port Forwarding

22 min read

How to Set Up Cloudflare Tunnel on Ubuntu 24.04 VPS: Expose Services Without Port Forwarding

Exposing a self-hosted service to the public internet traditionally means opening inbound ports on your firewall, configuring NAT rules on your router, dealing with dynamic IP addresses, and hoping your VPS provider does not rate-limit you when a bot starts probing port 22. Cloudflare Tunnel removes all of that. Instead of listening for incoming traffic, your server opens an outbound connection to Cloudflare's edge and receives requests through that persistent tunnel. This guide walks you through installing cloudflared on an Ubuntu 24.04 VPS, creating a tunnel, routing a hostname to it, hardening it with Zero Trust access policies, and running it as a reliable systemd service.

Looking for a lean, stable VPS to run cloudflared on? The CloudCore Starter plan has plenty of headroom for one or more tunnels plus the services behind them.

Table of Contents

  • What is Cloudflare Tunnel?
  • Why Use Cloudflare Tunnel Instead of Port Forwarding?
  • Prerequisites
  • Step 1: Update System Packages
  • Step 2: Install cloudflared from the Official Apt Repo
  • Step 3: Authenticate cloudflared with Your Cloudflare Account
  • Step 4: Create a Tunnel
  • Step 5: Configure Ingress Rules
  • Step 6: Route DNS to the Tunnel
  • Step 7: Install cloudflared as a systemd Service
  • Step 8: Protect the Tunnel with Cloudflare Access (Zero Trust)
  • Step 9: WebSocket and Long-Lived Connections
  • Back Up Your Tunnel Configuration
  • Cautions: Bandwidth, TOS, and Streaming Content
  • Troubleshooting
  • FAQ
  • Next Steps
  • What is Cloudflare Tunnel?

    Cloudflare Tunnel is a free service that lets you publish internal services to the internet without opening inbound ports or exposing your VPS IP. You install a small daemon called cloudflared on the origin server, it dials out to Cloudflare's edge, and that outbound connection becomes the transport for every request to your public hostname. From the outside, app.example.com resolves to Cloudflare; traffic reaches your server via the tunnel; no one on the public internet can connect to your origin directly.

    Cloudflare Tunnel is part of the broader Cloudflare One / Zero Trust platform. You can expose HTTP applications, raw TCP services (SSH, RDP, databases), and even entire private networks to remote devices running the WARP client. Common deployment patterns include publishing a self-hosted app like Nextcloud or Ghost, giving your team SSH access to a VPS without opening port 22, reaching a home lab that sits behind CGNAT, and building site-to-site networks without static IPs or IPsec tunnels.

    Under the hood, cloudflared multiplexes traffic over HTTP/2 or QUIC to the nearest Cloudflare data center. It establishes multiple redundant connections so that if one Cloudflare edge location has a hiccup, traffic fails over transparently. Because the TLS certificate is managed by Cloudflare at the edge, your origin never needs a public certificate — cloudflared can talk to your local service over plain HTTP on 127.0.0.1, and the TLS handshake with the end user happens entirely at the edge.

    Why Use Cloudflare Tunnel Instead of Port Forwarding?

    Compared to the traditional "open port 443, point DNS at your IP, install Let's Encrypt" workflow, Cloudflare Tunnel offers several concrete benefits:

    • No inbound ports — Your VPS firewall can deny every inbound connection on 80/443. Attackers cannot port-scan your origin because your origin is not advertising any listening socket to the public internet.
    • Works behind NAT and CGNAT — No public IPv4? No problem. The tunnel is established outbound, so as long as your server can reach the internet on port 443, it can publish services. This is the cleanest way to expose services on a home lab or a mobile hotspot.
    • Automatic DDoS protection — All traffic passes through Cloudflare's edge first. Volumetric attacks are absorbed by Cloudflare's anycast network before they ever reach your origin.
    • Free TLS at the edge — Cloudflare issues and renews certificates for you. You never run certbot again for tunneled hostnames.
    • IP rotation is harmless — If your VPS ever changes IP addresses, nothing breaks. The tunnel reconnects automatically and DNS records are not tied to the origin IP.
    • Generous free tier — Cloudflare Tunnel and Cloudflare Access (up to 50 users) are free for personal and small business use. There are no per-seat costs until you scale into Zero Trust Enterprise.
    • Single pane for access policies — Cloudflare Access lets you put authentication in front of any tunneled hostname without modifying the underlying app. Add Google SSO, Okta, email-OTP, or device posture checks from the dashboard.

    Cloudflare Tunnel vs. Alternatives

    FeaturePort Forward + CertbotReverse SSH TunnelTailscale FunnelCloudflare Tunnel
    Public inbound ports requiredYes (80/443)Yes (jump host)NoNo
    Works behind CGNATNoYesYesYes
    DDoS protectionDIYNoNoYes (built-in)
    TLS managementManual (certbot)ManualAutomaticAutomatic
    Zero Trust access policiesNo (build yourself)NoLimitedYes (free 50 users)
    Custom domainsYesYesLimitedYes
    Monthly cost (1 service)FreeFreeFree tierFree
    For most self-hosted applications on a VPS, Cloudflare Tunnel hits the sweet spot of zero cost, zero ports, and zero certificate wrangling.

    Prerequisites

    Before you begin, make sure you have:

    • A VPS running Ubuntu 24.04 LTS with root or sudo access
    • SSH access to your server
    • A Cloudflare account (free plan is fine) with a domain added and nameservers pointed at Cloudflare — if you have not done this yet, see developers.cloudflare.com/fundamentals/setup
    • A service running locally on the VPS that you want to expose — for this guide we assume something on http://localhost:8080, but the same steps work for any port and protocol
    Recommended Plan: CloudCore Starter
    >
    cloudflared itself is extremely lightweight (typically 40-80 MB RAM at idle). What matters is the service behind it. For a handful of self-hosted apps — Ghost, Nextcloud, Grafana, a static site — the CloudCore Starter plan gives you plenty of room:
    >
    - 2 vCPU cores
    - 4 GB RAM
    - 50 GB NVMe SSD
    - Unmetered bandwidth at 1 Gbps
    >
    Because all ingress goes through Cloudflare's edge, you can also lock the VPS firewall down to outbound-only, which is a huge security win regardless of the plan you choose.

    Connect to your server:

    bash
    ssh root@your-server-ip

    Step 1: Update System Packages

    Refresh your package index and apply any pending upgrades before installing new software:

    bash
    sudo apt update && sudo apt upgrade -y

    Expected output (abbreviated):

    text
    Hit:1 http://archive.ubuntu.com/ubuntu noble InRelease
    Hit:2 http://archive.ubuntu.com/ubuntu noble-updates InRelease
    Reading package lists... Done
    Building dependency tree... Done
    0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.

    If the kernel was updated, reboot before continuing:

    bash
    sudo reboot

    Step 2: Install cloudflared from the Official Apt Repo

    Cloudflare publishes cloudflared through its own apt repository, which means you get automatic updates via apt upgrade just like any other system package. This is the recommended install method — avoid the one-shot .deb download unless you have a specific reason, because it will not auto-update.

    Add Cloudflare's GPG key:

    bash
    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

    Add the repository. Ubuntu 24.04 is codename noble:

    bash
    echo "deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared noble main" | sudo tee /etc/apt/sources.list.d/cloudflared.list

    Update the package index and install:

    bash
    sudo apt update
    sudo apt install -y cloudflared

    Verify the install:

    bash
    cloudflared --version

    Expected output:

    text
    cloudflared version 2025.2.1 (built 2025-02-18-1045 UTC)

    The binary lives at /usr/local/bin/cloudflared (or /usr/bin/cloudflared depending on version). You can run it as any user at this point — no daemon is running yet.

    Step 3: Authenticate cloudflared with Your Cloudflare Account

    Before you can create a tunnel bound to your domain, cloudflared needs a certificate that proves it is authorized to manage DNS for your zone. You obtain this by logging in through a browser.

    Run the login command:

    bash
    cloudflared tunnel login

    Expected output:

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

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

    Leaving cloudflared running to download cert automatically.

    Copy the URL into your local browser (not the VPS's browser), log in to Cloudflare, and pick the zone (domain) you want this tunnel to serve. Cloudflare then writes a certificate file called cert.pem into ~/.cloudflared/ on the VPS.

    When it is done you will see:

    text
    You have successfully logged in.
    If you wish to copy your credentials to a server, they have been saved to:
    /root/.cloudflared/cert.pem

    This cert is what authorizes cloudflared to create DNS records and new tunnels in that zone. Treat it like an API key — anyone with this file can create tunnels on your account.

    Step 4: Create a Tunnel

    Each tunnel is a named logical connection between your origin and Cloudflare's edge. A single tunnel can serve many hostnames via ingress rules, so you usually want one tunnel per server rather than one per app.

    Create a tunnel named my-tunnel:

    bash
    cloudflared tunnel create my-tunnel

    Expected output:

    text
    Tunnel credentials written to /root/.cloudflared/6f2a8b91-c3d4-4e2f-9a1b-0c8d7e6f5a4b.json.
    cloudflared chose to use credentials file instead of token.
    Keep this file secret. To revoke these credentials, delete the tunnel.

    Created tunnel my-tunnel with id 6f2a8b91-c3d4-4e2f-9a1b-0c8d7e6f5a4b

    Two things just happened:

  • A new tunnel record was created on Cloudflare's side, visible in the Zero Trust dashboard under Networks → Tunnels.
  • A credentials file was written to ~/.cloudflared/<uuid>.json on your VPS. This file contains the tunnel secret — the runtime credential cloudflared uses to connect. It is separate from the cert.pem from Step 3.
  • List your tunnels to confirm:

    bash
    cloudflared tunnel list

    Expected output:

    text
    ID                                   NAME         CREATED              CONNECTIONS
    6f2a8b91-c3d4-4e2f-9a1b-0c8d7e6f5a4b  my-tunnel    2026-04-16T10:00:00Z

    Write the UUID down — you will reference it in the config file in the next step.

    Step 5: Configure Ingress Rules

    The config file at /etc/cloudflared/config.yml tells cloudflared which hostnames to accept and where to send the traffic locally. Create the directory and file:

    bash
    sudo mkdir -p /etc/cloudflared
    sudo tee /etc/cloudflared/config.yml > /dev/null <<'EOF'
    tunnel: 6f2a8b91-c3d4-4e2f-9a1b-0c8d7e6f5a4b
    credentials-file: /root/.cloudflared/6f2a8b91-c3d4-4e2f-9a1b-0c8d7e6f5a4b.json

    ingress: - hostname: app.example.com service: http://localhost:8080 - hostname: grafana.example.com service: http://localhost:3000 - hostname: ssh.example.com service: ssh://localhost:22 - service: http_status:404 EOF

    Replace the UUID, hostnames, and service URLs with your own. A few things to know:

    • tunnel — The UUID of the tunnel you created in Step 4.
    • credentials-file — Absolute path to the JSON file cloudflared tunnel create generated. When you move to running as a systemd service later, this path must be readable by the cloudflared system user.
    • Ingress rules are evaluated top-to-bottom. The first matching hostname wins. Requests for hosts not matched fall through to the catch-all at the bottom.
    • The last rule must be a catch-all with no hostname: key. Without it, cloudflared refuses to start. http_status:404 is the standard choice — return a 404 for unknown hostnames.
    • Service types include http://, https://, tcp://, ssh://, rdp://, unix:/path/to/socket, and hello_world (a built-in test endpoint).
    Validate the config before going further:

    bash
    cloudflared tunnel ingress validate

    Expected output:

    text
    Validating rules from /etc/cloudflared/config.yml
    OK

    Test a specific hostname against your rules:

    bash
    cloudflared tunnel ingress rule https://app.example.com/health

    Expected output:

    text
    Using rules from /etc/cloudflared/config.yml
    Matched rule #0
      hostname: app.example.com
      service: http://localhost:8080

    Step 6: Route DNS to the Tunnel

    A tunnel with no DNS record is invisible — nothing on the public internet knows to send app.example.com to Cloudflare's edge. The tunnel route dns command creates a proxied CNAME pointing at <tunnel-uuid>.cfargotunnel.com in one shot:

    bash
    cloudflared tunnel route dns my-tunnel app.example.com
    cloudflared tunnel route dns my-tunnel grafana.example.com
    cloudflared tunnel route dns my-tunnel ssh.example.com

    Expected output for each:

    text
    2026-04-16T10:10:00Z INF Added CNAME app.example.com which will route to this tunnel tunnelID=6f2a8b91-...

    Open the Cloudflare dashboard's DNS tab for your zone and you will see new orange-cloud CNAME records, one per hostname, all pointing at the same cfargotunnel.com target.

    If a DNS record for that hostname already exists (for example, an A record from a previous setup), the command refuses to overwrite it. Delete the old record in the dashboard first, then rerun the route command. This conflict is one of the most common beginner gotchas — watch for a record already exists error message.

    Step 7: Install cloudflared as a systemd Service

    Running cloudflared tunnel run my-tunnel in the foreground works for testing, but for production you want a systemd unit that auto-starts on boot and restarts on failure. cloudflared ships with a helper that sets this up:

    bash
    sudo cloudflared service install

    Expected output:

    text
    2026-04-16T10:15:00Z INF Using Systemd
    2026-04-16T10:15:00Z INF cloudflared service is installed

    Under the hood this:

  • Copies /etc/cloudflared/config.yml and the credentials JSON into /etc/cloudflared/ owned by a cloudflared system user.
  • Writes /etc/systemd/system/cloudflared.service.
  • Enables and starts the service.
  • Verify:

    bash
    sudo systemctl status cloudflared

    Expected output:

    text
    ● cloudflared.service - cloudflared
         Loaded: loaded (/etc/systemd/system/cloudflared.service; enabled; preset: enabled)
         Active: active (running) since Wed 2026-04-16 10:15:30 UTC; 10s ago
       Main PID: 2345 (cloudflared)
          Tasks: 9 (limit: 4552)
         Memory: 48.2M
         CGroup: /system.slice/cloudflared.service
                 └─2345 /usr/local/bin/cloudflared --no-autoupdate --config /etc/cloudflared/config.yml tunnel run

    Tail the logs while the tunnel connects:

    bash
    sudo journalctl -u cloudflared -f

    You are looking for four Registered tunnel connection lines, one per Cloudflare data center the tunnel has connected to:

    text
    INF Registered tunnel connection connIndex=0 location=FRA
    INF Registered tunnel connection connIndex=1 location=FRA
    INF Registered tunnel connection connIndex=2 location=AMS
    INF Registered tunnel connection connIndex=3 location=AMS

    Four connections means the tunnel is fully redundant. From another machine, browse to https://app.example.com and you should see the service that is running on localhost:8080 on your VPS, served through Cloudflare with a valid TLS certificate.

    At this point you can (and should) close inbound 80 and 443 on your firewall:

    bash
    sudo ufw default deny incoming
    sudo ufw allow OpenSSH   # keep SSH while you test, consider tunneling SSH too
    sudo ufw enable

    Step 8: Protect the Tunnel with Cloudflare Access (Zero Trust)

    Exposing a service via tunnel still makes it publicly reachable by default — anyone with the URL can hit it. Cloudflare Access sits in front of any tunneled hostname and enforces authentication before traffic even reaches your origin.

    From the Cloudflare Zero Trust dashboard, go to Access → Applications → Add an application → Self-hosted. Key fields:

    • Application name — any label, e.g. grafana.
    • Session duration — how long a successful login stays valid (24 hours is a common default).
    • Application domain — the exact hostname you want to protect, e.g. grafana.example.com.
    Click Next, then create an Access Policy. You choose an Action (Allow, Block, Bypass, or Service Auth) and a set of Include / Require / Exclude rules. Useful rule types:

    • Emails — Include a literal list of email addresses. Cloudflare sends a one-time PIN on login.
    • Emails ending in — e.g. @your-company.com for whole-team access.
    • Identity provider — Google, GitHub, Okta, Azure AD, Microsoft 365, SAML, or generic OIDC. Configure these under Settings → Authentication before using them here.
    • Country — geo-restrict (useful for admin panels).
    • Device posture — require WARP client, a specific OS version, disk encryption, or the presence of a managed certificate. Posture is the piece that turns Access into real Zero Trust.
    Finish the flow and, from a fresh browser session, load https://grafana.example.com. Instead of your Grafana login page you now see the Cloudflare Access authentication screen. After signing in, Cloudflare adds a CF-Access-Jwt-Assertion header and forwards the request through the tunnel to your origin. Your backend can trust this header because it is signed by Cloudflare and unspoofable — see developers.cloudflare.com/cloudflare-one/identity/authorization-cookie/validating-json for verification details.

    The Access free tier includes up to 50 users, which is enough for most homelabs and small teams.

    Step 9: WebSocket and Long-Lived Connections

    Out of the box, cloudflared supports WebSockets and long-lived HTTP connections — you do not need to toggle anything on the free plan. But there are two things to know:

    • Per-rule noTLSVerify and timeouts — If you have a service behind the tunnel that terminates its own TLS with a self-signed cert, add originRequest.noTLSVerify: true to that ingress rule. For long-poll endpoints, bump connectTimeout and tlsTimeout.
    • 100-second edge idle timeout — Cloudflare's edge closes idle connections after 100 seconds. For WebSockets this usually does not matter because the socket sends heartbeat frames. For raw TCP services that go quiet (some RDP workloads), you may see unexpected disconnects. Configure your app to send periodic keep-alives.
    Example config for a backend that needs long timeouts:

    yaml
    ingress:
      - hostname: app.example.com
        service: http://localhost:8080
        originRequest:
          connectTimeout: 30s
          tlsTimeout: 30s
          keepAliveTimeout: 90s
          noHappyEyeballs: false
      - service: http_status:404

    Full reference for originRequest options is at developers.cloudflare.com/cloudflare-one/connections/connect-networks/configure-tunnels/cloudflared-parameters/origin-parameters.

    Back Up Your Tunnel Configuration

    Three files together are the "state" of your tunnel. Losing them means you cannot manage or reconnect it without recreating from scratch:

    • /root/.cloudflared/cert.pem — zone management cert from Step 3
    • /root/.cloudflared/<uuid>.json — tunnel credentials from Step 4
    • /etc/cloudflared/config.yml — ingress rules from Step 5
    Back them up to an encrypted location (1Password, a GPG-encrypted archive in object storage, etc.):

    bash
    sudo tar czf cloudflared-backup-$(date +%Y%m%d).tar.gz \
      /root/.cloudflared/cert.pem \
      /root/.cloudflared/*.json \
      /etc/cloudflared/config.yml
    sudo chmod 600 cloudflared-backup-*.tar.gz

    Store the archive somewhere other than the VPS itself. When you restore on a new server, drop these three files back in place and cloudflared service install will pick them up.

    Cautions: Bandwidth, TOS, and Streaming Content

    Cloudflare Tunnel is free, but the free plan comes with one important restriction: Cloudflare's Terms of Service §2.8 prohibits using a Free, Pro, or Business plan to serve a disproportionate amount of non-HTML content — the classic example being a large video library or file-download service with heavy egress. Cloudflare occasionally enforces this by asking operators to move to an Enterprise plan or Cloudflare Stream.

    Rules of thumb:

    • Self-hosted dashboards, admin panels, APIs, blogs, SaaS apps — absolutely fine.
    • A personal Jellyfin / Plex instance with a handful of users — typically fine but you are in a grey zone.
    • Public video hosting, file sharing, or large media distribution — do not do this over a Free-plan tunnel. Use Cloudflare Stream, R2, or a proper CDN plan.
    • Tunneling Bittorrent or other P2P traffic — explicitly forbidden.
    None of this is a hard technical limit — cloudflared will happily push terabytes — but a sudden email from Cloudflare asking you to stop is not a fun surprise. Size your deployment against the TOS, not against what the tunnel technically allows.

    Troubleshooting

    ProblemCauseSolution
    Tunnel keeps disconnecting / reconnectingFirewall dropping outbound 7844 (QUIC) or unstable networkForce the HTTP/2 protocol: add protocol: http2 at the top of config.yml and restart. HTTP/2 goes over 443 which is almost always open.
    An A, AAAA, or CNAME record with that host already exists when running tunnel route dnsLeftover DNS record from a previous setupDelete the conflicting record in the Cloudflare dashboard DNS tab, then rerun the command.
    502 Bad Gateway in the browserOrigin service not listening on the address in config.yml, or bound to an IP cloudflared cannot reachVerify with curl http://localhost:8080 on the VPS. Check that the service binds to 127.0.0.1 or 0.0.0.0, not only a container-internal address.
    failed to request quick Tunnel: Post "https://api.trycloudflare.com/tunnel": ...Running cloudflared tunnel --url (quick tunnel) instead of a named tunnelUse the named-tunnel workflow from Step 4 onwards. Quick tunnels are for one-off testing only and cannot use Access.
    Cannot determine default origin certificate pathcert.pem missing or unreadable by the cloudflared userRe-run cloudflared tunnel login, or copy cert.pem to /etc/cloudflared/ and chown cloudflared:cloudflared.
    Access login page does not appear, app loads unprotectedAccess Application domain does not exactly match the tunneled hostnameIn the Access dashboard, confirm the Application domain matches the hostname in your ingress rule character-for-character (including subdomain).
    SSH through ssh.example.com hangsClient not using cloudflared access sshOn the client side, install cloudflared and use cloudflared access ssh --hostname ssh.example.com, or configure ProxyCommand in ~/.ssh/config.
    cloudflared using too much CPUQUIC fallback loop on unstable networkPin the protocol to http2 and check for packet loss to Cloudflare edge with mtr.
    View live logs whenever you are debugging:

    bash
    sudo journalctl -u cloudflared -f

    Get the last 100 lines:

    bash
    sudo journalctl -u cloudflared -n 100 --no-pager

    Increase log verbosity by editing config.yml:

    yaml
    loglevel: debug
    transport-loglevel: info

    Then sudo systemctl restart cloudflared.

    FAQ

    Does Cloudflare Tunnel expose my VPS IP address?

    No. All traffic reaches your server through the outbound tunnel, so the origin IP never appears in DNS or in response headers. This is a big upgrade over running Cloudflare as a standard reverse proxy (orange cloud on A/AAAA records), where a misconfigured app or a historical DNS lookup can leak the origin IP. With Tunnel, there is no A record pointing at your VPS to leak.

    Can I run multiple tunnels on the same VPS?

    Yes, but it is rarely necessary. One tunnel can serve unlimited hostnames through ingress rules. Multiple tunnels on one box are useful if you want to isolate blast radius (a credential leak on one tunnel does not compromise the others) or run separate tunnels for separate Cloudflare accounts. Each instance needs its own config.yml and its own systemd unit — run them as cloudflared@<name>.service style instanced units.

    How do I update cloudflared?

    Because you installed from the apt repo, updates come through sudo apt update && sudo apt upgrade. Restart the service after an upgrade to pick up the new binary: sudo systemctl restart cloudflared. You can also enable Cloudflare's built-in auto-update by removing --no-autoupdate from the generated systemd unit, but most production operators prefer to control the update window themselves.

    Can I use Cloudflare Tunnel for non-HTTP services like PostgreSQL or Redis?

    Yes, via tcp:// ingress rules on the origin side and the cloudflared access tcp command (plus a WARP client or Access-for-Infrastructure policy) on the client side. Keep in mind that the free plan's terms are written around HTTP workloads — bulk non-HTTP traffic may trigger the same §2.8 conversation as streaming video. For legitimate small-scale admin access (psql from a laptop to your prod DB behind Access), it works beautifully.

    Is there a Docker version of cloudflared?

    Yes — cloudflare/cloudflared:latest on Docker Hub. For a single service on a single VPS, the apt install is simpler and integrates with systemd cleanly. Use the Docker image when you want to ship cloudflared alongside an app in a Compose stack or Kubernetes pod. The same config.yml and credentials file format applies; mount them into the container at /etc/cloudflared/.

    How does Cloudflare Tunnel compare to Tailscale Funnel or ngrok?

    Tailscale Funnel is built on Tailscale's WireGuard mesh and is excellent for devices that are already in your tailnet. Funnel is simpler than Cloudflare Tunnel but has a more limited feature set (fewer custom-domain options on the free plan, no Zero Trust policies, no WAF). ngrok is optimized for developer workflows — quick tunnels for local dev, webhooks, mobile testing — and its persistent-tunnel pricing gets expensive compared to free Cloudflare Tunnel. Cloudflare Tunnel wins on custom domains, integrated WAF, built-in DDoS protection, and Access policies. Pick Tunnel when you are already on Cloudflare DNS and need production hosting; pick Tailscale when you want a mesh VPN first and public exposure as a bonus; pick ngrok for ephemeral dev workflows.

    Next Steps

    Now that your tunnel is live, here are sensible follow-ups:

    • Expose your apps cleanly through Nginx behind the tunnel — If you are hosting several apps on the same host, front them with a single Nginx reverse proxy and point the tunnel at Nginx instead of each service individually. See our Nginx install & reverse-proxy guide on Ubuntu 24.04 for the full Nginx setup.
    • Put Docker services behind the tunnel — Ship cloudflared in the same Compose file as your app so new deployments bring up an authenticated public URL automatically. Our Docker install guide for Ubuntu 24.04 walks through Compose and networking basics.
    • Harden SSH — Close inbound 22 entirely and access the VPS with cloudflared access ssh plus an Access Application requiring your identity provider. This is one of the highest-leverage security upgrades you can make on a public VPS.
    • Add a WAF ruleset — Cloudflare's free Managed Ruleset blocks common OWASP Top 10 attacks before traffic ever reaches your origin. Enable it per-zone under Security → WAF.
    • Monitor tunnel health — Cloudflare exposes tunnel metrics at http://localhost:20241/metrics in Prometheus format when you set metrics: localhost:20241 in config.yml. Scrape it from Prometheus or point an Uptime Kuma probe at your public hostname.

    Don't want to wrestle with DNS, certificates, and systemd?
    >
    The CloudCore Starter plan from vps-server.host gives you an Ubuntu 24.04 VPS that is ready for Cloudflare Tunnel out of the box:
    >
    - 2 vCPU, 4 GB RAM, 50 GB NVMe SSD
    - Unmetered bandwidth at 1 Gbps
    - Root access and full firewall control
    - 24/7 monitoring and snapshot backups
    >
    Launch your CloudCore Starter VPS and have your first tunnel live in the next 25 minutes.

    Was this article helpful?

    ← Back to Install GuidesBrowse all categories →

    Still have questions?

    Contact Support →Submit a Ticket