---
title: "Cloudflare Tunnel on a VPS: publish apps without opening ports | StreetHosting"
description: "Install cloudflared on a VPS, create the tunnel in the dashboard or CLI, publish apps over HTTPS, close ports 80 and 443 and put panels and SSH behind Access."
url: "https://streethosting.com.br/en/guides/vps/cloudflare-tunnel-vps"
type: "page"
language: "en-US"
---

VPS · 8 min · Intermediate

Published on Sep 28, 2026 · Updated on Sep 28, 2026

# Cloudflare Tunnel on a VPS: how to publish apps and close the web ports

With Cloudflare Tunnel, the VPS opens an outbound connection to Cloudflare and visitors come in through it, with no port 80 or 443 open and no IP in DNS. Here is the install, the two ways to create the tunnel, and what it does not solve.

By [Equipe StreetHosting](https://streethosting.com.br/en/autores#equipe-streethosting) · StreetHosting infrastructure and support team

[Linux administration](https://streethosting.com.br/en/guides/topics/linux) [DDoS protection](https://streethosting.com.br/en/guides/topics/ddos-protection) [Network, DNS and domains](https://streethosting.com.br/en/guides/topics/networking)

Summarize with:

[](https://chat.openai.com/?q=Summarize%20the%20key%20points%20of%20this%20StreetHosting%20guide%3A%20https%3A%2F%2Fstreethosting.com.br%2Fen%2Fguides%2Fvps%2Fcloudflare-tunnel-vps.%20Highlight%20the%20step-by-step%20instructions%2C%20the%20prerequisites%20and%20the%20most%20common%20mistakes. "ChatGPT") [](https://claude.ai/new?q=Summarize%20the%20key%20points%20of%20this%20StreetHosting%20guide%3A%20https%3A%2F%2Fstreethosting.com.br%2Fen%2Fguides%2Fvps%2Fcloudflare-tunnel-vps.%20Highlight%20the%20step-by-step%20instructions%2C%20the%20prerequisites%20and%20the%20most%20common%20mistakes. "Claude") [](https://www.google.com/search?udm=50&aep=11&q=Summarize%20the%20key%20points%20of%20this%20StreetHosting%20guide%3A%20https%3A%2F%2Fstreethosting.com.br%2Fen%2Fguides%2Fvps%2Fcloudflare-tunnel-vps.%20Highlight%20the%20step-by-step%20instructions%2C%20the%20prerequisites%20and%20the%20most%20common%20mistakes. "Google AI Mode") [](https://x.com/i/grok?text=Summarize%20the%20key%20points%20of%20this%20StreetHosting%20guide%3A%20https%3A%2F%2Fstreethosting.com.br%2Fen%2Fguides%2Fvps%2Fcloudflare-tunnel-vps.%20Highlight%20the%20step-by-step%20instructions%2C%20the%20prerequisites%20and%20the%20most%20common%20mistakes. "Grok") [](https://www.perplexity.ai/search/new?q=Summarize%20the%20key%20points%20of%20this%20StreetHosting%20guide%3A%20https%3A%2F%2Fstreethosting.com.br%2Fen%2Fguides%2Fvps%2Fcloudflare-tunnel-vps.%20Highlight%20the%20step-by-step%20instructions%2C%20the%20prerequisites%20and%20the%20most%20common%20mistakes. "Perplexity")

Share:

[](https://x.com/intent/tweet?text=Cloudflare%20Tunnel%20on%20a%20VPS%3A%20publish%20apps%20without%20opening%20ports&url=https%3A%2F%2Fstreethosting.com.br%2Fen%2Fguides%2Fvps%2Fcloudflare-tunnel-vps "Share on X") [](https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fstreethosting.com.br%2Fen%2Fguides%2Fvps%2Fcloudflare-tunnel-vps "Share on Facebook") [](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fstreethosting.com.br%2Fen%2Fguides%2Fvps%2Fcloudflare-tunnel-vps "Share on LinkedIn") [](https://wa.me/?text=Cloudflare%20Tunnel%20on%20a%20VPS%3A%20publish%20apps%20without%20opening%20ports%20https%3A%2F%2Fstreethosting.com.br%2Fen%2Fguides%2Fvps%2Fcloudflare-tunnel-vps "Share on WhatsApp")

For agents: Copy as Markdown [.md](https://streethosting.com.br/en/guides/vps/cloudflare-tunnel-vps.md)

In this guide 8 sections

* [How the tunnel works](https://streethosting.com.br/en/guides/vps/cloudflare-tunnel-vps#como-funciona)
* [Installing cloudflared](https://streethosting.com.br/en/guides/vps/cloudflare-tunnel-vps#instalar-cloudflared)
* [Option 1: tunnel from the dashboard with a token](https://streethosting.com.br/en/guides/vps/cloudflare-tunnel-vps#criar-pelo-painel)
* [Option 2: tunnel from the CLI with config.yml](https://streethosting.com.br/en/guides/vps/cloudflare-tunnel-vps#criar-pela-cli)
* [Closing ports 80 and 443](https://streethosting.com.br/en/guides/vps/cloudflare-tunnel-vps#fechar-portas)
* [Access for panels and SSH](https://streethosting.com.br/en/guides/vps/cloudflare-tunnel-vps#access-painel-ssh)
* [What the tunnel does not solve](https://streethosting.com.br/en/guides/vps/cloudflare-tunnel-vps#limites)
* [Which VPS to use with the tunnel](https://streethosting.com.br/en/guides/vps/cloudflare-tunnel-vps#qual-vps)

Quick answer

**Cloudflare Tunnel on a VPS**works like this: cloudflared opens an outbound connection to Cloudflare, and visitors to your domain come in through it. You install cloudflared, create the tunnel from the dashboard with a token or from the CLI with a config.yml, point each subdomain at a local service and, after testing, close ports 80 and 443 in the firewall. Panels and SSH get a login through Cloudflare Access. The tunnel is for HTTP and HTTPS; a public game server on UDP still depends on the provider's Anti-DDoS.

## How the tunnel works[](https://streethosting.com.br/en/guides/vps/cloudflare-tunnel-vps#como-funciona)

On a regular VPS, the domain's A record points to the machine's IP, and Nginx listens on ports 80 and 443 waiting for visitors. With the tunnel, the path is reversed. cloudflared runs on the VPS and keeps outbound connections to Cloudflare's network on port 7844. The subdomain's DNS becomes a CNAME to the tunnel's address, with the proxy enabled, and whoever visits the site talks to Cloudflare, which delivers the request through the tunnel to the local service.

Since the connection starts from the VPS, no inbound port needs to stay open. For the same reason the tunnel works on machines without a public IP, such as a home server behind [CGNAT](https://streethosting.com.br/en/guides/infrastructure/what-is-cgnat). On a VPS the gain is different: taking the IP out of DNS and reducing what stays exposed.

| Aspect                   | Nginx exposed directly   | Cloudflare Tunnel                          |
| ------------------------ | ------------------------ | ------------------------------------------ |
| Open inbound ports       | 80 and 443               | None for the web                           |
| VPS IP in DNS            | Yes, in the A record     | No, CNAME to the tunnel                    |
| Public certificate       | Let's Encrypt on the VPS | At Cloudflare's edge                       |
| Protocols for the public | Any                      | HTTP and HTTPS                             |
| External dependency      | None                     | Cloudflare account and cloudflared running |
| DNS requirement          | Any provider             | Domain with Cloudflare nameservers         |

## Installing cloudflared[](https://streethosting.com.br/en/guides/vps/cloudflare-tunnel-vps#instalar-cloudflared)

The requirement is having the domain added to a Cloudflare account, with the nameservers pointing to it. On a VPS running Ubuntu 24.04 or 22.04, install cloudflared from the official repository, which keeps the package updated along with the rest of the system:

`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 any main" \ | sudo tee /etc/apt/sources.list.d/cloudflared.list sudo apt-get update && sudo apt-get install cloudflared cloudflared --version`

Before creating the tunnel, confirm the application responds locally. If it runs on port 3000, `curl -I http://localhost:3000` must return an HTTP header. A tunnel pointing at a stopped service results in a 502 error at the edge, and the problem looks like Cloudflare's when it is not.

## Option 1: tunnel from the dashboard with a token[](https://streethosting.com.br/en/guides/vps/cloudflare-tunnel-vps#criar-pelo-painel)

This is the fastest path. The menu has moved a few times: today tunnels live under Networking, Tunnels in the Cloudflare dashboard, and in earlier versions they appeared inside Zero Trust, under Networks.

1. Create a tunnel of the Cloudflared type and give it a name, such as `minha-vps`.
2. Choose Debian as the system. The dashboard shows an install command with a long token that starts with eyJ.
3. Since cloudflared is already installed, run only the final part on the VPS: `sudo cloudflared service install SEU_TOKEN`. The systemd service is created and started.
4. In the dashboard, add a published application route, called Public Hostname in older versions: subdomain app, domain `seu-dominio.com.br`, type HTTP and URL localhost:3000.
5. The dashboard creates the DNS CNAME on its own. Open the address in the browser and check.

The token is the tunnel's credential: anyone who has it can run your tunnel on another machine and receive your traffic. Do not paste it in a repository or a chat. If it leaks, generate a new token in the dashboard and reinstall the service with it.

## Option 2: tunnel from the CLI with config.yml[](https://streethosting.com.br/en/guides/vps/cloudflare-tunnel-vps#criar-pela-cli)

From the command line, the routes live in a file on the VPS itself. It is the best option when you want to version the configuration or rebuild the server from scratch with the same result.

`cloudflared tunnel login # prints a URL; open it in your browser and pick the domain cloudflared tunnel create minha-vps # generates the UUID and the credentials file in ~/.cloudflared cloudflared tunnel list cloudflared tunnel route dns minha-vps app.seu-dominio.com.br cloudflared tunnel route dns minha-vps painel.seu-dominio.com.br cloudflared tunnel route dns minha-vps ssh.seu-dominio.com.br`

If an A record with the same name already exists, route dns fails saying the record exists. Delete the old record in the DNS dashboard and run it again. Then put the credentials and configuration in `/etc/cloudflared`, which is where the service looks:

`sudo mkdir -p /etc/cloudflared sudo cp ~/.cloudflared/UUID_DO_TUNEL.json /etc/cloudflared/ sudo nano /etc/cloudflared/config.yml`

`tunnel: UUID_DO_TUNEL credentials-file: /etc/cloudflared/UUID_DO_TUNEL.json ingress: - hostname: app.seu-dominio.com.br service: http://localhost:3000 - hostname: painel.seu-dominio.com.br service: http://localhost:9000 - hostname: ssh.seu-dominio.com.br service: ssh://localhost:22 - service: http_status:404`

Rules are read top to bottom and the last one, without a hostname, is mandatory: it answers 404 for any name that did not match the previous ones. Validate, test in the foreground and only then install the service:

`sudo cloudflared tunnel --config /etc/cloudflared/config.yml ingress validate sudo cloudflared tunnel --config /etc/cloudflared/config.yml ingress rule https://app.seu-dominio.com.br sudo cloudflared tunnel --config /etc/cloudflared/config.yml run # Ctrl+C to stop sudo cloudflared --config /etc/cloudflared/config.yml service install sudo systemctl start cloudflared sudo systemctl status cloudflared`

From here on, the file that counts is the one in /etc/cloudflared. After any edit, run `sudo systemctl restart cloudflared` and follow along with `journalctl -u cloudflared -f`.

## Closing ports 80 and 443[](https://streethosting.com.br/en/guides/vps/cloudflare-tunnel-vps#fechar-portas)

The tunnel only delivers its full benefit when the VPS stops accepting direct web traffic. Otherwise, whoever discovers the IP can keep reaching the site without going through Cloudflare. Do this in order, with the site already working through the tunnel.

### Services listening only on localhost[](https://streethosting.com.br/en/guides/vps/cloudflare-tunnel-vps#escutar-localhost)

Each application must listen on 127.0.0.1, not on 0.0.0.0. In Docker, publish the port bound to localhost, because ports published by Docker bypass the UFW rules. Check the result with ss:

`# docker compose: ports with localhost in front ports: - "127.0.0.1:3000:3000" # what is listening and on which address sudo ss -tlnp`

If you keep Nginx between the tunnel and the applications, as in the [Nginx as a reverse proxy](https://streethosting.com.br/en/guides/vps/nginx-reverse-proxy-vps) guide, two adjustments save you a headache. First, remove the HTTP to HTTPS redirect from the server block the tunnel uses: the visitor is already on HTTPS at the edge, and the redirect produces the too many redirects error. Second, recover the visitor's real IP, which arrives in the `CF-Connecting-IP` header, otherwise every access shows up in the log as 127.0.0.1:

`# inside the Nginx http or server block set_real_ip_from 127.0.0.1; real_ip_header CF-Connecting-IP;`

### Removing the UFW rules[](https://streethosting.com.br/en/guides/vps/cloudflare-tunnel-vps#regras-ufw)

`sudo ufw status numbered sudo ufw delete 3 # use the number of the 80, 443 or Nginx Full rule sudo ufw status numbered # check again, the numbers shift after each delete`

cloudflared needs no new rule, because UFW allows outbound traffic by default. The default deny logic is explained in the [UFW firewall on a VPS](https://streethosting.com.br/en/guides/vps/ufw-firewall-ubuntu-vps) guide.

Closing the port does not erase the past. If the IP sat in an A record for months, it may be in DNS history databases. Also review the MX and forgotten subdomains that still point straight at the VPS.

## Access for panels and SSH[](https://streethosting.com.br/en/guides/vps/cloudflare-tunnel-vps#access-painel-ssh)

The tunnel publishes the panel, but it does not decide who gets in. That is what Cloudflare Access is for: it puts a Cloudflare login screen in front of the subdomain before any request reaches the VPS. In Zero Trust, under Access, create a self-hosted application for `painel.seu-dominio.com.br`and an Allow policy with the authorized emails. The default login sends a code by email, and you can connect Google or GitHub as the identity provider. The free plan covers small teams; check the user limit on Cloudflare's plans page.

For SSH, the ssh://localhost:22 route in config.yml is already in place. On your computer, install cloudflared and add this to `~/.ssh/config`:

`Host ssh.seu-dominio.com.br ProxyCommand cloudflared access ssh --hostname %h # then connect as usual ssh usuario@ssh.seu-dominio.com.br`

On Windows, replace cloudflared with the full path to cloudflared.exe. With an Access application for `ssh.seu-dominio.com.br`, the browser asks for a login on the first connection.

Only close port 22 in UFW after logging in through the tunnel in a second session, and with the VPS panel console tested. If cloudflared stops, SSH through the tunnel stops with it. A safe middle ground is keeping 22 open only for the office's static IP, or using a [WireGuard VPN](https://streethosting.com.br/en/guides/vps/wireguard-vpn-vps) as an alternate path.

## What the tunnel does not solve[](https://streethosting.com.br/en/guides/vps/cloudflare-tunnel-vps#limites)

The tunnel is excellent for the web and poor for almost everything else when the audience is the public. SSH, RDP and generic TCP work, but only with cloudflared running on the connecting computer, which serves your team and not visitors.

| Use case                           | Works through the tunnel?           | Note                                                                    |
| ---------------------------------- | ----------------------------------- | ----------------------------------------------------------------------- |
| Website, API, web panel, WebSocket | Yes                                 | Main use case                                                           |
| Team SSH and RDP                   | Yes, with cloudflared on the client | Protect with Access                                                     |
| Remote database                    | Yes, with cloudflared access tcp    | For internal use; ideally do not expose it                              |
| Public game server on UDP          | No                                  | Players do not install cloudflared; depends on the provider's Anti-DDoS |
| Inbound email on port 25           | No                                  | Outside mail servers connect straight to the IP                         |
| Very large uploads                 | With a limit                        | The request body follows the limit of your Cloudflare plan              |

The upload limit deserves attention: on the free plan, each request currently accepts up to 100 MB, so systems that receive large files need chunked uploads or another path. And the tunnel does not replace system updates, strong passwords and a secure application: it hides the port, it does not fix the vulnerability of whatever sits behind it. Cloudflare's limits for games are detailed in [Cloudflare and game server protection](https://streethosting.com.br/en/guides/infrastructure/cloudflare-game-server-protection).

## Which VPS to use with the tunnel[](https://streethosting.com.br/en/guides/vps/cloudflare-tunnel-vps#qual-vps)

cloudflared is lightweight: it usually takes a few dozen MB of memory and almost no CPU. Sizing the VPS is still about the applications that sit behind it. And the tunnel does not remove the need for network protection on the server: everything that does not go through it, such as a game port, still arrives via the IP. On a [StreetHosting VPS](https://streethosting.com.br/en/vps) Anti-DDoS is included, with a datacenter in São Paulo, root access and activation within 60 seconds.

* **A small site or panel:** [Xeon VPS](https://streethosting.com.br/en/vps/xeon) at R$ 26.00 per month, with 2 vCPU, 2 GB of RAM and 20 GB NVMe.
* **Docker with a few applications and a database:** Xeon VPS at R$ 43.00, with 3 vCPU, 4 GB and 40 GB NVMe, or at R$ 77.00, with 6 vCPU, 8 GB and 80 GB.
* **Clock-sensitive application, such as server-side rendering:** Ryzen 9 9950X VPS with DDR5, at R$ 66.00 with 2 vCPU and 4 GB, or R$ 118.00 with 4 vCPU and 8 GB.
* Application responding on localhost before creating the tunnel
* Routes tested in the browser and with ingress rule
* Services listening on 127.0.0.1 and Docker ports bound to localhost
* Rules for 80 and 443 removed from UFW
* Old A records and forgotten subdomains reviewed
* Panel and SSH behind Access, with the VPS console tested

In this guide

* [How the tunnel works](https://streethosting.com.br/en/guides/vps/cloudflare-tunnel-vps#como-funciona)
* [Installing cloudflared](https://streethosting.com.br/en/guides/vps/cloudflare-tunnel-vps#instalar-cloudflared)
* [Option 1: tunnel from the dashboard with a token](https://streethosting.com.br/en/guides/vps/cloudflare-tunnel-vps#criar-pelo-painel)
* [Option 2: tunnel from the CLI with config.yml](https://streethosting.com.br/en/guides/vps/cloudflare-tunnel-vps#criar-pela-cli)
* [Closing ports 80 and 443](https://streethosting.com.br/en/guides/vps/cloudflare-tunnel-vps#fechar-portas)
* [Access for panels and SSH](https://streethosting.com.br/en/guides/vps/cloudflare-tunnel-vps#access-painel-ssh)
* [What the tunnel does not solve](https://streethosting.com.br/en/guides/vps/cloudflare-tunnel-vps#limites)
* [Which VPS to use with the tunnel](https://streethosting.com.br/en/guides/vps/cloudflare-tunnel-vps#qual-vps)

## Frequently asked questions

Does Cloudflare Tunnel hide my VPS IP?

It hides it for the web traffic that goes through the tunnel, because DNS points to Cloudflare and not to your IP. The address can still leak through old records, the email MX or other exposed services, so close the web ports in the firewall and review DNS after migrating.

Do I need to open any port on the VPS for the tunnel to work?

No inbound port needs to be opened. cloudflared makes outbound connections to Cloudflare on port 7844, over QUIC on UDP or HTTP/2 on TCP. Since UFW allows outbound traffic by default, nothing usually needs to change in the firewall.

Can I use Cloudflare Tunnel with a Minecraft server or another game?

Not for the public. The tunnel publishes HTTP and HTTPS to any visitor, but SSH, RDP and generic TCP only work with cloudflared installed on the connecting computer, and players will not do that. A public game server depends on the provider's Anti-DDoS protection.

Is it better to create the tunnel from the dashboard or from the command line?

The dashboard is faster: a token installs the service and the routes live in your Cloudflare account. From the command line, the routes live in a config.yml on the VPS, which you can version alongside the rest of the server configuration.

Do I still need Nginx and Let's Encrypt when using the tunnel?

Not necessarily. The public certificate sits at Cloudflare's edge and the leg to the VPS already travels encrypted inside the tunnel. Nginx is still useful when you want several sites, local caching or proxy rules, but from then on it only listens on localhost.

Next step

See VPS plans

Root VPS in Brazil with NVMe and Anti-DDoS.

[See VPS plans](https://streethosting.com.br/en/vps)

[See Xeon VPS Xeon VPS for steady workloads, automation and long-running projects.](https://streethosting.com.br/en/vps/xeon)

## Related guides

[Infrastructure Intermediate Cloudflare for game server protection: what works Cloudflare helps your website and DNS, but it does not replace the host's UDP protection. This guide spares your gaming community a false sense of security. 2 min Read guide](https://streethosting.com.br/en/guides/infrastructure/cloudflare-game-server-protection) [VPS Intermediate How to set up Nginx as a reverse proxy on a VPS Your app runs on an internal port and you want to serve it on a domain with HTTPS. Nginx as a reverse proxy solves that and also brings several apps together in one place. 3 min Read guide](https://streethosting.com.br/en/guides/vps/nginx-reverse-proxy-vps) [VPS Beginner UFW on Ubuntu VPS: firewall rules without losing SSH UFW makes the Ubuntu firewall simpler, but one rule in the wrong order locks you out of your VPS. Learn how to enable it without losing SSH, open only what you need, deal with Docker, and get back in through the console if something goes wrong. 10 min Read guide](https://streethosting.com.br/en/guides/vps/ufw-firewall-ubuntu-vps)

[← Back to the Guide Center](https://streethosting.com.br/en/guides)
