Hosting / updated 28 Sep 2026
Hosting at home: Cloudflare Tunnel vs VPS vs port-forward
Cloudflare Tunnel vs VPS vs port-forward
Short answer: For a home lab, run a Cloudflare Tunnel with an Access policy in front of every admin page. Use a VPS for anything that must stay up when your house loses power, or that you don't want tied to your home IP. Don't port-forward unless you enjoy reading logs.
The four options
| Port-forward from home | Cloudflare Tunnel at home | Tailscale / WireGuard only | Cheap VPS | |
|---|---|---|---|---|
| Open inbound ports on your router | Yes | None | None | n/a (VPS ports are public) |
| Your home IP visible | Yes | Hidden behind Cloudflare | Hidden | Hidden (VPS IP instead) |
| Who can reach the app | Whole internet | Whole internet, unless you add Access | Only your devices | Whole internet |
| Login wall before the app | Only what the app has | Access policy (SSO / email code) if you set one | Tailnet membership | Only what you set up |
| If the app is owned | Attacker is on your home LAN | Attacker is on your home LAN | Attacker is on your home LAN | Attacker is on a box you can wipe |
| Uptime | Your power and ISP | Your power and ISP | Your power and ISP | Datacenter |
| Main way it goes wrong | Scanners find it within hours | Tunnel published with no Access policy | Shared too widely / Funnel turned on | Unpatched box, SSH password auth |
What actually gets small setups owned
-
Admin panels published with no login wall. Proxmox, Portainer, Grafana, Open WebUI, an Ollama port. The tunnel is not the problem; the missing Access policy is.
-
A port-forward left open after moving to a tunnel. The tunnel hides the origin only if nothing else points at it.
-
Leaked secrets. A tunnel token or API key committed to a public repo or pasted in a forum post.
- Blast radius. Something at home that gets owned sits on the same LAN as your NAS, backups, and every IoT device. A VPS that gets owned does not.
Recommended setup by use
| You want to host | Do this |
|---|---|
| Admin UIs (Proxmox, Portainer, Grafana, Home Assistant admin) | Tailscale/WireGuard only. If you must use a tunnel, put an Access policy on it. |
| Your own apps for you and family (Immich, Nextcloud, Vaultwarden) | Tunnel + Access policy, or Tailscale. |
| Local LLM front end (Open WebUI) | Tunnel + Access policy. Never expose the raw Ollama / vLLM / LiteLLM port. |
| Public website or blog | Static host (Cloudflare Pages) first. VPS or tunnel only if it needs a backend. |
| Anything that must be up 24/7 | VPS, or a managed platform. |
| Game servers, raw TCP/UDP | VPS, or a port-forward on a separate VLAN. Tunnels mostly carry HTTP. |
Tunnel checklist
- [ ] Every public hostname has a Cloudflare Access application and an Allow policy.
- [ ] Open each hostname in a private window. You should see the Access login, not the app.
- [ ] Router has no port-forwards to the machine running the service.
- [ ] Tunnel token lives in a secrets file or env, not in a committed compose file.
- [ ] Services bind to
127.0.0.1or the Docker network, not0.0.0.0.
VPS checklist
- [ ] SSH keys only, password auth off.
- [ ] Automatic security updates on.
- [ ] Only 80/443 open to the world. Everything else over Tailscale/WireGuard.
- [ ] Docker-published ports checked: Docker writes its own firewall rules and can bypass UFW.
Sources
- Cloudflare Tunnel docs: https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/
- Cloudflare Access policies: https://developers.cloudflare.com/cloudflare-one/access-controls/policies/
- Publishing a self-hosted app behind Access: https://developers.cloudflare.com/cloudflare-one/access-controls/applications/http-apps/self-hosted-public-app/
- Cloudflare service terms (content limits on proxied traffic): https://www.cloudflare.com/service-specific-terms-application-services/
- Tailscale overview: https://tailscale.com/docs/concepts/what-is-tailscale
- Tailscale Funnel (public exposure, off by default): https://tailscale.com/docs/features/tailscale-funnel
- Docker and host firewalls: https://docs.docker.com/engine/network/packet-filtering-firewalls/