Skip to content 99% OFF 🎉 Anniversary Sale 99% OFF Shared Hosting Use Code HURRYUP Claim Offer 99% OFF Hosting
99% OFF Hosting — Code HURRYUP
Products
AI Website Builder New VPS Hosting Cloud Servers Web Hosting cPanel Hosting Dedicated Servers Domains
Company
About Documentation Support Center Contact Get Started Call +91 75795 45488
Login
Hosting Panel — cPanel & Billing Console Panel — VPS Management
ALL SYSTEMS OPERATIONAL
VPS

Cloudflare Tunnel on a VPS: Expose Apps Without Open Ports

Getwebup 6 min read

You've got n8n, Grafana, or some internal admin panel running on a VPS, and you need to reach it from outside — but you don't want to punch a hole in the firewall for it. Opening a port and pointing a subdomain at your server's IP works, but now that IP is sitting in the open, getting hit by scanners within hours. Cloudflare Tunnel skips the open port entirely. Here's how to set it up properly, and where it beats (and doesn't beat) a normal reverse proxy.

Symptom: you don't want to expose your VPS's IP just to reach one app

This usually shows up in one of a few ways:

  • You've set up an internal tool (n8n, Grafana, MinIO console, a staging site) and the only way to reach it right now is http://your-server-ip:3000
  • Your firewall rules are getting messy — every new service means another ufw allow line
  • You're behind CGNAT, a dynamic IP, or a network where inbound ports simply don't work
  • You want SSL on an internal app without buying a cert or fighting Let's Encrypt for a subdomain nobody else needs to see

The instinct is to open the port, add an Nginx reverse proxy, and slap a Let's Encrypt certificate on it. That works — we've covered that path before. But it means your VPS's public IP is now directly reachable on that port, which is exactly what automated scanners are built to find.

Cause: the traditional setup requires an inbound-facing port

A standard reverse-proxy setup needs traffic to reach your server directly:

Internet → your-server-ip:443 → Nginx → localhost:3000 (your app)

For that to work, port 443 (or whatever you're using) has to be open on your firewall and reachable from the public internet. That's fine for a real public website — it's the whole point. But for an internal dashboard or a tool only your team touches, it's more exposure than the use case needs. Every open port is one more thing bots will probe, and one more thing you have to patch and monitor.

Cloudflare Tunnel flips the connection around. Instead of the internet reaching in to your server, a lightweight daemon called cloudflared runs on your VPS and makes an outbound connection to Cloudflare's network. Cloudflare then routes traffic for your subdomain through that existing outbound connection. No inbound port ever has to open.

SetupInbound port neededSSL cert to manageGood for
Nginx reverse proxy + Let's EncryptYes (80/443)Yes, renews every 90 daysPublic-facing sites and APIs
Cloudflare TunnelNoNo — Cloudflare terminates itInternal tools, dashboards, staging, CGNAT/dynamic-IP servers

Fix: set up cloudflared and route a subdomain through it

This assumes you already have a domain on Cloudflare's DNS (orange-clouded proxy, not just nameservers pointed elsewhere) and an app running on the VPS on some local port — we'll use localhost:3000 as the example.

1. Install cloudflared on the VPS

On Ubuntu/Debian:

curl -L --output cloudflared.deb https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
sudo dpkg -i cloudflared.deb
cloudflared --version

On AlmaLinux/CentOS, grab the matching RPM from the same releases page instead and install with rpm -i.

2. Authenticate and create the tunnel

cloudflared tunnel login

This prints a URL — open it in a browser, log into Cloudflare, and pick the domain you want to tunnel through. It drops a certificate into ~/.cloudflared/cert.pem on the server. Then create the tunnel itself:

cloudflared tunnel create n8n-tunnel

This writes a credentials JSON file (usually in ~/.cloudflared/) and prints a tunnel ID — save that ID, you'll need it in the config file.

3. Write the config file

Create ~/.cloudflared/config.yml:

tunnel: <your-tunnel-id>
credentials-file: /root/.cloudflared/<your-tunnel-id>.json

ingress:
  - hostname: n8n.yourdomain.com
    service: http://localhost:3000
  - service: http_status:404

That last line matters — it's a catch-all that returns 404 for anything that doesn't match a defined hostname, instead of silently falling through.

4. Point DNS at the tunnel

cloudflared tunnel route dns n8n-tunnel n8n.yourdomain.com

This creates a CNAME record in Cloudflare pointing your subdomain at <tunnel-id>.cfargotunnel.com. You don't touch the zone editor manually — the command does it for you.

5. Run it as a service, not a foreground process

Test first with cloudflared tunnel run n8n-tunnel and confirm the subdomain loads. Once that works, install it as a proper systemd service so it survives reboots:

sudo cloudflared service install
sudo systemctl enable --now cloudflared
sudo systemctl status cloudflared

If status comes back active and your subdomain loads over HTTPS with a valid Cloudflare-issued certificate, you're done — and you never opened a single inbound port on the VPS for this app.

Multiple apps, one tunnel

You don't need a separate tunnel per service. Add more entries under ingress in the same config file:

ingress:
  - hostname: n8n.yourdomain.com
    service: http://localhost:3000
  - hostname: grafana.yourdomain.com
    service: http://localhost:3001
  - service: http_status:404

Then re-route DNS for each new hostname with the same tunnel route dns command, and restart the service.

Prevention: lock the tunnel down once it's live

  • Put Cloudflare Access in front of anything sensitive. A tunnel hides your server's IP, but the URL itself is still public unless you add an Access policy (Zero Trust → Access → Applications) requiring an email OTP or Google/GitHub login before the page loads.
  • Keep cloudflared updated. sudo apt update && sudo apt upgrade cloudflared — new releases patch real bugs, and the daemon has direct access to your internal network.
  • Rotate credentials if a laptop or CI runner that had access is ever compromised. cloudflared tunnel cleanup <tunnel-id> revokes old connector sessions.
  • Don't tunnel your primary public website through this. Tunnel is built for internal and admin-facing tools. Your main site should still run through normal DNS with Cloudflare's proxy, or a standard reverse proxy if you're not on Cloudflare at all.
  • Watch the tunnel in the dashboard. Zero Trust → Networks → Tunnels shows connector health and lets you catch a dropped connection before someone tells you the dashboard is down.

When to skip the tunnel and just open the port

Tunnel isn't a universal replacement for a reverse proxy. If you're running a public-facing production site or API that needs to handle real traffic volume and doesn't sit behind Cloudflare already, a standard Nginx reverse proxy with its own TLS cert is still the simpler, more predictable choice — Getwebup VPS plans have Nginx and Certbot available for exactly that. Reach for Cloudflare Tunnel specifically when the thing you're exposing is internal, low-traffic, or something you'd rather not have indexed by IP scanners at all.

Frequently asked questions

Does Cloudflare Tunnel replace my firewall?

No. Keep UFW or iptables running with sane rules for SSH and anything else you host. Tunnel just means the app it's routing doesn't need its own inbound port open — everything else on the server should still be locked down normally.

Is Cloudflare Tunnel free?

Yes, for the tunnel and DNS routing itself, on any Cloudflare plan including free. Cloudflare Access policies (login gates) are also free up to a generous number of users, which covers most small teams.

What happens if the VPS reboots or cloudflared crashes?

If you installed it with `cloudflared service install` and enabled it via systemd, it restarts automatically on reboot and respawns on crash. If you only ran `cloudflared tunnel run` in a terminal session, it dies the moment that session closes — always convert to a service for anything you rely on.

Can I use Cloudflare Tunnel if my domain isn't on Cloudflare's nameservers?

No — the tunnel needs to create a CNAME in a Cloudflare-managed DNS zone for your domain, so your domain's nameservers have to point to Cloudflare first. If you're using Getwebup's nameservers directly, either move DNS to Cloudflare or stick with a standard reverse proxy setup instead.

#cloudflare-tunnel #vps #cloudflared #firewall #reverse-proxy #self-hosted

Keep reading

Chat with Support