
Opening firewall ports to expose services from your VPS to the internet is the traditional approach — but it comes with significant risks. Every open port is a potential entry point for attackers. Cloudflare Tunnel solves this by creating an encrypted outbound tunnel from your VPS to Cloudflare's network, so you never need to open a single inbound port.
What Is Cloudflare Tunnel?
Cloudflare Tunnel (formerly Argo Tunnel) is a Zero Trust Network Access service that lets your VPS create an outbound connection to Cloudflare's network via a daemon called cloudflared. When users request your service, traffic flows through Cloudflare Edge and back through the tunnel to your VPS — never touching your public IP directly.
This means your VPS does not need any open inbound ports. Your firewall can block all incoming connections 100%, drastically reducing your attack surface.
Cloudflare Tunnel vs Direct Port Forwarding
- No inbound ports needed — Block all inbound traffic; only outbound tunnel is required
- Hide your VPS real IP — Attackers cannot directly target your server
- Built-in DDoS protection — Cloudflare filters traffic before it reaches your VPS
- Free SSL/TLS — Cloudflare manages certificates automatically
- Works with dynamic IP — No static IP requirement
- Access policies — Restrict access by email or IP using Cloudflare Access
Note: Cloudflare Tunnel is free on the Free plan. You need a domain with its nameservers pointing to Cloudflare to get started.
Prerequisites
- Ubuntu 20.04 / 22.04 VPS with root access
- Cloudflare account (free at cloudflare.com)
- Domain with nameservers pointing to Cloudflare
- A local service to expose (web app on port 80, 3000, etc.)
Step-by-Step Installation on Ubuntu VPS
Step 1: Install cloudflared
# Download cloudflared for Linux AMD64
curl -L --output cloudflared.deb \
https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
# Install package
sudo dpkg -i cloudflared.deb
# Verify version
cloudflared --version
Step 2: Authenticate with Cloudflare
# This outputs a URL to open in your browser for authorization
cloudflared tunnel login
Open the URL in your browser, select the domain you want to use, then Cloudflare creates a certificate at ~/.cloudflared/cert.pem automatically.
Step 3: Create the Tunnel
# Create a new tunnel (name it anything you like)
cloudflared tunnel create my-vps-tunnel
# List existing tunnels
cloudflared tunnel list
Step 4: Create Config File
nano ~/.cloudflared/config.yml
Add the following content (replace YOUR-TUNNEL-ID with the ID from step 3):
tunnel: YOUR-TUNNEL-ID
credentials-file: /root/.cloudflared/YOUR-TUNNEL-ID.json
ingress:
- hostname: app.yourdomain.com
service: http://localhost:3000
- hostname: web.yourdomain.com
service: http://localhost:80
- service: http_status:404
Step 5: Create DNS Records
# Create CNAME records pointing to your tunnel
cloudflared tunnel route dns my-vps-tunnel app.yourdomain.com
cloudflared tunnel route dns my-vps-tunnel web.yourdomain.com
Step 6: Run Tunnel as a System Service
# Install cloudflared as a systemd service
sudo cloudflared --config /root/.cloudflared/config.yml service install
# Enable and start
sudo systemctl enable cloudflared
sudo systemctl start cloudflared
# Check status
sudo systemctl status cloudflared
Cloudflare Tunnel (cloudflared) — Expose Your VPS Without Opening Ports
The heart of Cloudflare Tunnel is the cloudflared daemon running on your VPS, which keeps a persistent outbound connection open to Cloudflare's edge at all times. That connection is a mutual-TLS (mTLS) channel in both directions. When a request arrives at your domain, Cloudflare pushes it back down the existing connection into your VPS — so the VPS never needs a single inbound port open. This is a "reverse tunnel": instead of the internet reaching in to your server, your server reaches out to Cloudflare first. The result is that your inbound firewall can be sealed shut entirely.
Here is the full install-and-create flow again in a compact, copy-paste-ready form for a freshly provisioned AsiaGB Ubuntu VPS:
# 1) Install cloudflared (Ubuntu 20.04/22.04 AMD64)
curl -L --output cloudflared.deb \
https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
sudo dpkg -i cloudflared.deb
cloudflared --version
# 2) Authenticate and authorize your domain (open the printed URL in a browser)
cloudflared tunnel login
# 3) Create a new tunnel + list tunnels
cloudflared tunnel create my-vps-tunnel
cloudflared tunnel list
# 4) Note the Tunnel ID and the credentials (.json) file path for config.yml
After step 3, Cloudflare writes a credentials file at ~/.cloudflared/<TUNNEL-ID>.json — this is the secret key for your tunnel. Never push it to a public Git repo or share it: anyone who obtains this file can impersonate your tunnel.
Configure config.yml + Route DNS in Detail
The config.yml file defines which hostname maps to which internal service. The ingress block is read top to bottom like a routing table, and the final rule must always be the catch-all http_status:404 — otherwise cloudflared errors out on start:
# ~/.cloudflared/config.yml
tunnel: YOUR-TUNNEL-ID
credentials-file: /root/.cloudflared/YOUR-TUNNEL-ID.json
ingress:
# Node.js app on port 3000
- hostname: app.yourdomain.com
service: http://localhost:3000
# Main website on port 80
- hostname: web.yourdomain.com
service: http://localhost:80
# Example: an internal TLS service (skip internal cert check)
- hostname: secure.yourdomain.com
service: https://localhost:8443
originRequest:
noTLSVerify: true
# catch-all — required as the last rule
- service: http_status:404
Validate the syntax before running with cloudflared tunnel ingress validate to catch broken YAML, then bind each hostname's DNS record to the tunnel — Cloudflare automatically creates a special proxied CNAME:
# Validate config first
cloudflared tunnel ingress validate
# Route each hostname to the tunnel (creates CNAME automatically)
cloudflared tunnel route dns my-vps-tunnel app.yourdomain.com
cloudflared tunnel route dns my-vps-tunnel web.yourdomain.com
cloudflared tunnel route dns my-vps-tunnel secure.yourdomain.com
# Run in the foreground first to watch live logs before installing the service
cloudflared tunnel run my-vps-tunnel
If a page still doesn't load, check the terminal log for Registered tunnel connection and confirm your internal service (Node.js, Nginx, etc.) is actually listening on the configured port with ss -tlnp.
Run cloudflared as a Persistent systemd Service
Once the foreground test passes, make cloudflared run as a background service that auto-starts on every reboot using systemd — the standard approach on Ubuntu:
# Install as a systemd service (reads config from the given path)
sudo cloudflared --config /root/.cloudflared/config.yml service install
# Enable at boot + start now
sudo systemctl enable cloudflared
sudo systemctl start cloudflared
# Check status + tail live logs
sudo systemctl status cloudflared
sudo journalctl -u cloudflared -f
Whenever you edit config.yml later, remember to run sudo systemctl restart cloudflared for the new settings to take effect. For continuous 99% uptime, keep systemctl enable on so the service recovers itself after a reboot or kernel update, and add an external monitor to watch the service.
Tip: For high availability, run multiple cloudflared instances (even across multiple VPSes) using the same Tunnel ID. Cloudflare load-balances connections automatically, so if one instance goes down another picks up traffic instantly.
Security Benefits + Best Use Cases for Tunnel
The main reason teams migrate from direct port forwarding to Cloudflare Tunnel is the immediate security upgrade — with no extra hardware investment:
- Hide your VPS origin IP — attackers only see Cloudflare's IP, never your real server, so they cannot launch DDoS or port scans directly at you
- Zero open inbound ports — your inbound attack surface drops to nothing; bots scanning the internet for ports 22/80/443 find nothing to hit
- Traffic filtered at the edge — Cloudflare's WAF, rate limiting, and DDoS protection run before traffic reaches your VPS, offloading CPU and bandwidth from the origin
- Add an authentication layer — pair with Cloudflare Access to require login (Google/GitHub/email OTP) before reaching internal services
- No static IP required — ideal for VPSes with changing IPs or backend servers behind NAT
Use cases where Cloudflare Tunnel shines on an AsiaGB Ubuntu VPS include:
- Internal admin panels / dashboards like Portainer, Grafana, or phpMyAdmin that should never be public
- WordPress / e-commerce sites that want to hide their real IP and get free Cloudflare DDoS protection
- Node.js / API backends on high ports (3000/8080) without exposing those ports to the internet
- Game servers / business apps that need secure remote access for a team
- Staging / demo sites you want to share temporarily with clients, gated by an Access policy
Lock Down UFW Firewall After Tunnel Setup
Once your tunnel is running, you can safely block all inbound ports and keep only SSH for management:
# Set default policies
sudo ufw default deny incoming
sudo ufw default allow outgoing
# Allow SSH only from your IP
sudo ufw allow from YOUR_IP to any port 22
# Enable UFW
sudo ufw enable
# Verify rules
sudo ufw status verbose
Security tip: Restrict SSH to only your IP address (ufw allow from 1.2.3.4 to any port 22) to prevent brute-force attacks on your management interface.
Using Cloudflare Access with Tunnel
Cloudflare Access adds an authentication layer in front of services exposed via Tunnel. You can require Google, GitHub, or email login before users can reach internal tools like admin panels, Portainer, or dashboards.
- Go to Cloudflare Dashboard → Zero Trust → Access → Applications
- Click "Add an application" → "Self-hosted"
- Specify the domain to protect and choose an identity provider
- Users must authenticate before accessing that URL
Frequently Asked Questions (FAQ)
Is Cloudflare Tunnel really free? Are there hidden costs?
Cloudflare Tunnel and the cloudflared daemon are free on Cloudflare's Free plan — enough to expose websites and personal or small-business services. All you need is a domain whose nameservers point to Cloudflare. Some advanced features (such as a large number of Access users) may require an upgrade, but everything in this guide works at no cost.
Do I still need to open ports 80/443 on my VPS when using Tunnel?
No. cloudflared opens the outbound connection to Cloudflare itself, so you can set UFW to deny incoming entirely and leave only port 22 (SSH) open for management. For maximum security you can even expose SSH through the tunnel and close port 22 externally, leaving zero inbound ports.
Will the tunnel come back automatically after a VPS reboot?
Yes, if you install cloudflared as a systemd service and run sudo systemctl enable cloudflared. systemd starts the service on every boot, so the tunnel recovers itself after a reboot or kernel update without you running any commands manually.
How is Cloudflare Tunnel different from a VPN or port forwarding?
Port forwarding opens an inbound port straight into your VPS, exposing the real IP and port to attacks. A traditional VPN requires installing a client and managing keys yourself. Cloudflare Tunnel is outbound-only: it hides your real IP, opens no inbound ports, and benefits from Cloudflare's WAF and DDoS protection at the edge — while end users simply visit your normal domain with no client to install.
Get a Secure VPS Today
Linux VPS starting at 500 THB/month with Full Root Access, SSD storage, and Dedicated IP. Located in Thailand and Singapore.
View VPS Plans