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

  1. 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.

  2. A port-forward left open after moving to a tunnel. The tunnel hides the origin only if nothing else points at it.

  3. Leaked secrets. A tunnel token or API key committed to a public repo or pasted in a forum post.

  4. 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.1 or the Docker network, not 0.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/