VPS Tutorials
Hide Your VPS Origin IP with Cloudflare Tunnel (2026): Zero Trust, No Open Ports, and Internal Network Penetration Deployment Guide
Cloudflare Tunnel lets web services on a VPS avoid exposing public ports directly: cloudflared actively connects out to Cloudflare, and Cloudflare then reaches back to your local service. This article explains which scenarios it suits, how to deploy it, how to bind a domain, how to protect the admin backend with Access, and how to troubleshoot common issues such as Inactive status, 502 errors, and the origin still being directly reachable.

Many VPS websites, after connecting to Cloudflare, only switch their DNS records to the orange-cloud proxy. This hides part of the access path, but if the origin IP has already leaked, attackers can still bypass Cloudflare and hit your VPS directly.
Cloudflare Tunnel solves a different problem: it removes the need for the origin to open public ports 80/443. A cloudflared daemon runs on the VPS and actively establishes an outbound-only encrypted connection to Cloudflare; when external users visit your domain, requests first enter Cloudflare and are then forwarded through this tunnel to the local service on the VPS.
This article follows real VPS user scenarios: when to use Tunnel, how to create a tunnel, how to publish a self-hosted service, how to protect the admin backend, and how to troubleshoot common failures.
Cloudflare Tunnel is best suited to these needs:
| Scenario | Suitable? | Notes |
|---|---|---|
| Exposing a blog, tool site, or small SaaS | Suitable | No need to open origin 80/443; hides the origin IP |
| Exposing n8n, Gitea, or Grafana admin backends | Very suitable | Can be combined with Cloudflare Access for login protection |
| Services behind home broadband/NAT | Suitable | No public IP or port forwarding needed |
| High-concurrency download sites, large-file businesses | Use with caution | Consider Cloudflare policies and bandwidth characteristics |
| Mail servers, game servers, arbitrary TCP services | Not necessarily | HTTP is simplest; non-HTTP depends on the protocol and approach |
In one sentence: if your service is essentially HTTP/HTTPS and you want to hide the origin IP, Tunnel is well worth using.
But it is not a silver bullet. Tunnel cannot fix application vulnerabilities for you, nor replace backups, logging, and access control. It solves the problems of "entry exposure surface" and "origin bypassing Cloudflare."
The traditional approach is:
用户 -> Cloudflare -> VPS 公网 IP:443 -> Nginx -> 应用
The Tunnel approach is:
用户 -> Cloudflare Edge -> cloudflared 隧道 -> 127.0.0.1:3000
The key difference is that cloudflared actively connects out from the VPS, so the VPS firewall can close inbound 80/443 and keep only SSH, or even be managed solely via console/VPN.
Cloudflare's official documentation also states clearly that Tunnel uses an outbound-only connection model: cloudflared actively connects from the origin to Cloudflare's global network, and traffic is then forwarded bidirectionally through this connection.
This is very valuable for VPS:
- The origin IP does not need to be exposed directly to users;
- Internal services without a public IP can also be published;
- The admin entry can be placed behind Cloudflare Access;
- Firewall policy is simpler: deny inbound by default and allow only necessary management ports.
You need:
- A domain already connected to Cloudflare;
- A VPS with outbound internet access;
- A locally running service, for example
127.0.0.1:3000; - Access to the Cloudflare Zero Trust dashboard.
First confirm the local service is reachable:
curl -I http://127.0.0.1:3000
If you cannot access it even locally, do not configure Tunnel yet. Tunnel is not an application repair tool; it only forwards traffic.
Go to Cloudflare Zero Trust:
Zero Trust -> Networks -> Connectors -> Cloudflare Tunnels -> Create a tunnel
Select Cloudflared and give the tunnel a name, for example:
vps-main-tunnel
Cloudflare will give you an installation command. On Debian/Ubuntu it looks roughly like this:
curl -L --output cloudflared.deb https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
sudo dpkg -i cloudflared.deb
sudo cloudflared service install <你的-token>
After installation, return to the dashboard. If the connector shows Healthy, the VPS has established a connection with Cloudflare.
In the Tunnel's Public Hostname or Published applications, add:
Subdomain: app
Domain: example.com
Type: HTTP
URL: http://localhost:3000
After saving, visit:
https://app.example.com
If the service is working, requests will reach port 3000 on the VPS through Cloudflare Tunnel.
At this point your application can listen only on localhost:
HOST=127.0.0.1 PORT=3000 npm start
Nginx also does not need to be the public entry point; it can just be a local reverse proxy layer:
server {
listen 127.0.0.1:8080;
server_name _;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
Then point Tunnel to:
http://localhost:8080
The Dashboard installation method usually registers a systemd service automatically. Check the status:
systemctl status cloudflared
journalctl -u cloudflared -n 100 --no-pager
Common commands:
systemctl restart cloudflared
systemctl enable cloudflared
If you reinstall the system later, remember to reinstall the connector. The Tunnel object lives in the Cloudflare dashboard; the cloudflared on the VPS is just the connector.
After using Tunnel, public inbound ports can be tightened significantly.
If your site is published entirely through Tunnel, you can do this:
ufw default deny incoming
ufw default allow outgoing
ufw allow OpenSSH
ufw enable
If you want to further protect SSH, you can allow only your own IP:
ufw allow from 你的固定IP to any port 22 proto tcp
But do not carelessly close SSH before you have prepared console/VNC/rescue mode. There are already related self-rescue articles:
Tunnel's strength is not only hiding the origin; it can also work with Cloudflare Access.
For example, if you have these backends:
n8n.example.comgitea.example.comgrafana.example.comadmin.example.com
You can create an Access Application in Zero Trust that requires visitors to pass one of the following before access:
- Email OTP;
- Google / GitHub login;
- Specified team email;
- Specified country/region or IP policy;
- Multi-factor authentication.
This way, even if the backend application's own login page is exposed, there is an extra layer of Cloudflare identity verification outside.
Recommended policies:
| Service | Access recommendation |
|---|---|
| Blog frontend | No Access needed |
| n8n / Grafana / Gitea backend | Strongly recommend adding Access |
| Webhook URL | Do not blindly add Access; it may affect third-party callbacks |
| Internal tools | Allow only specified emails or organization accounts |
First check the service:
systemctl status cloudflared
journalctl -u cloudflared -n 100 --no-pager
Then confirm the VPS can reach Cloudflare:
curl -I https://www.cloudflare.com
If the server is behind a strict firewall, confirm outbound connections are not blocked. Cloudflare documentation reminds that in restricted networks you should first run a connectivity pre-check, especially to confirm reachability to Cloudflare.
Common causes:
- Token copied incorrectly;
- systemd service not started;
- VPS outbound blocked by firewall;
- DNS or system time abnormal;
- cloudflared version too old.
Tunnel is already Healthy, but visiting the domain returns an error; usually the local service address is wrong.
Test on the VPS:
curl -I http://localhost:3000
curl -I http://127.0.0.1:3000
Note that localhost may resolve to IPv6 ::1, while your application only listens on IPv4. In this case, you can explicitly write in Public Hostname:
http://127.0.0.1:3000
If your application requires a Host header, you may also need to adjust the HTTP Host Header in the Tunnel's origin request settings.
Configuring Tunnel does not guarantee the origin is hidden. You also need to confirm:
- There is no grey-cloud A record in DNS exposing the real IP;
- The VPS firewall no longer opens 80/443;
- Historical DNS records, certificate transparency logs, and email headers do not leak the origin;
- The old Nginx entry is no longer listening publicly.
Test direct origin access:
curl -I http://你的VPS_IP
curl -kI https://你的VPS_IP
If the website is still reachable, the origin has not truly been closed off.
| Comparison | Ordinary orange-cloud proxy | Cloudflare Tunnel |
|---|---|---|
| Requires public inbound 80/443 | Yes | No |
| Hides origin IP | Partially | More thoroughly, but historical leaks still need cleanup |
| Suitable for NAT/home broadband | No | Yes |
| Supports Access | Yes | Yes, with a more complete experience |
| Troubleshooting complexity | Lower | Slightly higher |
Ordinary orange cloud already solves many CDN/WAF/cache problems; Tunnel is better suited to scenarios where you want to further reduce the VPS exposure surface or have no public inbound conditions.
Before publishing a service, check at least:
- Local service
curl http://127.0.0.1:端口is normal; - Cloudflare Tunnel connector shows Healthy;
- Public Hostname points to the correct local port;
- UFW has not locked out SSH;
- VPS public 80/443 is closed or no longer returns business pages;
- Admin domain has Cloudflare Access added;
- Webhook paths are not mistakenly blocked by Access;
-
journalctl -u cloudflaredhas no persistent errors; - Domain access, direct IP access, and mobile network have all been tested.
Be cautious in these cases:
- You need full control over Nginx TLS details and certificate chains;
- The business has many large-file downloads or special protocols;
- You do not want the entry to depend heavily on Cloudflare;
- Your network has unstable outbound connections to Cloudflare;
- You need non-HTTP protocols but do not want to introduce extra clients or Zero Trust configuration.
If it is just an ordinary website, admin backend, self-hosted tool, or internal panel, the benefits of Tunnel usually outweigh the complexity.
Cloudflare Tunnel is well suited to VPS users for three things: hiding the origin IP, reducing public inbound ports, and adding a layer of Zero Trust access control to backend services.
Its core is not "making the website faster" but "exposing the origin less." If you are already on Cloudflare and worry about the origin being directly accessed, the backend being scanned, or home broadband/NAT being unable to open ports, then Tunnel is a solution well worth mastering.
The truly secure approach is: publish services with Tunnel, close unnecessary inbound ports in the firewall, protect the backend with Access, and keep observing logs. That way the VPS is not left exposed alone on the public internet, but placed behind Cloudflare's edge network with controlled access.