This article contains affiliate links. If you purchase through our links, we may earn a commission at no extra cost to you. We only recommend products we’ve thoroughly researched and verified.

Cloudflare Tunnel is the cleanest way to access your mini PC home server from outside your home. No port forwarding. No dynamic DNS. No home IP exposure. The cloudflared daemon on your server creates an outbound connection to Cloudflare’s edge — your services appear at a public HTTPS URL, and your router never needs touching.
What you need:
- A Cloudflare account free
- A domain name with DNS managed by Cloudflare transfer is free; new.com domains ~$10/year
- A mini PC running Ubuntu Server 24.04 LTS with Docker installed
- One or more services running on the mini PC Home Assistant, Jellyfin, Nextcloud, etc.
How Cloudflare Tunnel Works
Standard remote access port forwarding:
Internet → Router (port 8123 open) → Mini PC → Home Assistant
^ Your home IP is exposed
Cloudflare Tunnel:
Internet → Cloudflare Edge → cloudflared daemon → Mini PC → Home Assistant
^ Your home IP is never in DNS
The cloudflared daemon on your server maintains a persistent outbound HTTPS connection to Cloudflare. Cloudflare routes public DNS requests for your domain to that connection and forwards the traffic — with automatic TLS termination and valid HTTPS certificates.
Step 1: Set Up Your Cloudflare Account
- Create a Cloudflare account at cloudflare.com
- Add your domain: Websites → Add Site → follow the DNS transfer wizard
- Update your domain’s nameservers at your registrar to point to Cloudflare’s NS records
- Wait for DNS propagation 5 minutes to 24 hours
If you don’t have a domain, register one. Cloudflare Registrar offers.com at cost price ~$9-10/year. This is the only cost for the entire setup.
Step 2: Install cloudflared
On Ubuntu system service, recommended for production:
# Add Cloudflare's repository
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 update && sudo apt install cloudflared
# Verify
cloudflared version
Authenticate with Cloudflare
cloudflared tunnel login
This opens a browser window or prints a URL to visit. Log in to your Cloudflare account and authorize cloudflared. A certificate is saved to ~/.cloudflared/cert.pem.
Step 3: Create a Tunnel
# Create a named tunnel
cloudflared tunnel create homelab
Output includes the tunnel UUID — note it. A credentials JSON file is created at ~/.cloudflared/<UUID>.json.
Step 4: Configure the Tunnel
Create the configuration file:
mkdir -p ~/.cloudflared
nano ~/.cloudflared/config.yml
# Tunnel UUID from "cloudflared tunnel create" output
tunnel: <YOUR-TUNNEL-UUID>
credentials-file: /home/ubuntu/.cloudflared/<YOUR-TUNNEL-UUID>.json
ingress:
# Home Assistant
- hostname: ha.yourdomain.com
service: http://localhost:8123
# Jellyfin
- hostname: jellyfin.yourdomain.com
service: http://localhost:8096
# Nextcloud
- hostname: cloud.yourdomain.com
service: http://localhost:8080
# Portainer
- hostname: portainer.yourdomain.com
service: https://localhost:9443
originRequest:
noTLSVerify: true # Self-signed cert on Portainer — skip verification
# Required catch-all — returns 404 for unmatched hostnames
- service: http_status:404
Step 5: Create DNS Records for Each Hostname
# Create CNAME records pointing each subdomain to the tunnel
cloudflared tunnel route dns homelab ha.yourdomain.com
cloudflared tunnel route dns homelab jellyfin.yourdomain.com
cloudflared tunnel route dns homelab cloud.yourdomain.com
cloudflared tunnel route dns homelab portainer.yourdomain.com
Each command creates a CNAME DNS record in Cloudflare pointing ha.yourdomain.com → <UUID>.cfargotunnel.com. Verify them in Cloudflare Dashboard → DNS.
Step 6: Run cloudflared
Test first:
cloudflared tunnel run homelab
Access https://ha.yourdomain.com — if Home Assistant loads, the tunnel is working. Press Ctrl+C to stop.
Run as a system service:
# Install as system service
sudo cloudflared --config ~/.cloudflared/config.yml service install
sudo systemctl enable cloudflared
sudo systemctl start cloudflared
# Check status
sudo systemctl status cloudflared
journalctl -u cloudflared -f
The cloudflared service now starts automatically on boot and reconnects if the connection drops.
Step 7: Run cloudflared in Docker Alternative
If you prefer managing cloudflared as a Docker container alongside your other services:
nano ~/cloudflared/docker-compose.yml
services:
cloudflared:
image: cloudflare/cloudflared:latest
container_name: cloudflared
command: tunnel --config /etc/cloudflared/config.yml run
volumes:
- ~/.cloudflared:/etc/cloudflared:ro
restart: unless-stopped
network_mode: host # Required to reach services on host ports
cd ~/cloudflared
docker compose up -d
Using network_mode: host allows cloudflared to reach services on localhost ports 8123, 8096, etc. directly.
Step 8: Secure with Cloudflare Access Zero Trust
Exposing Home Assistant publicly means anyone can attempt to log in. Cloudflare Access adds an authentication gate before your services — users must authenticate through Cloudflare before seeing the login screen.
In Cloudflare Dashboard → Zero Trust → Access → Applications:
- Add an Application → Self-hosted
- Application domain:
ha.yourdomain.com - Add Policy:
- Policy name: “Family”
- Action: Allow
- Rule: Emails →
youremail@gmail.com,partner@gmail.com
- Save
Now accessing https://ha.yourdomain.com shows a Cloudflare authentication page first. Only the specified email addresses can proceed.
Home Assistant config adjustment for reverse proxy
When behind a reverse proxy, Home Assistant needs to trust the proxy:
# configuration.yaml
http:
use_x_forwarded_for: true
trusted_proxies:
- 172.16.0.0/12 # Docker network range
- 127.0.0.1
Restart Home Assistant after this change.
Troubleshooting
“Bad Gateway” or “502 Error”
The tunnel can’t reach the backend service. Verify the service is actually running docker ps and check the port in config.yml matches. Check journalctl -u cloudflared -f for connection errors.
“No such tunnel” during setup
The credentials file path in config.yml doesn’t match the actual file. Run ls ~/.cloudflared/ to confirm the UUID file exists and matches the UUID in config.yml.
Cloudflare Access Loop endless authentication
Home Assistant or other services may not handle the authentication headers correctly. Add the cookie domain to Home Assistant’s trusted_proxies. For WebSocket services like Home Assistant, ensure “WebSocket” is enabled in the Zero Trust application configuration.
Service unreachable but tunnel is connected
Check if the service listens on 127.0.0.1 vs 0.0.0.0. Some Docker containers only bind to 0.0.0.0 inside the container — from the host, access via the port you mapped, not the container-internal address. Example: if Jellyfin’s Docker port is 8096:8096, use http://localhost:8096 in config.yml, not the container’s internal IP.
Security Best Practices
Enable Cloudflare Access on all publicly exposed services — especially Home Assistant and Portainer.
Restrict by IP for internal tools: In Cloudflare Access policies, you can require that requests come from your home IP range in addition to email authentication.
Disable direct login for sensitive services: If Home Assistant is behind Cloudflare Access, trusted users have already authenticated. You can use HA’s onboarding to only allow logins from trusted_networks for the initial local setup.
Monitor Cloudflare Access logs: Zero Trust → Logs → Access shows every authentication attempt — useful for spotting unexpected access attempts.
Who Should Skip This Comparison
Frequently Asked Questions
What is a Cloudflare Tunnel and how does it work?
A Cloudflare Tunnel creates an outbound-only connection from your mini PC to Cloudflare’s edge network. Your services become accessible at a public URL without opening any inbound ports on your router. The cloudflared daemon on your server initiates the connection, so your home IP is never exposed and CGNAT is not a problem.
Is Cloudflare Tunnel free?
Yes. Cloudflare Tunnel is free for personal use. You need a free Cloudflare account and a domain name with DNS managed by Cloudflare which is also free if you transfer your domain. There are no bandwidth limits for the free tier tunnel.
Is Cloudflare Tunnel safe to use for Home Assistant?
Yes, when combined with access policies. Enable Cloudflare Access Zero Trust on the tunnel — add an email or GitHub authentication requirement before users reach your Home Assistant login. This adds a second layer of authentication before the Home Assistant login screen appears, protecting against brute-force attacks on your HA credentials.
What is the difference between Cloudflare Tunnel and port forwarding?
Port forwarding opens a specific port on your router and maps it to an internal IP. It exposes your home IP address, requires a static IP or dynamic DNS, and fails with CGNAT. Cloudflare Tunnel uses an outbound connection from your server — no open ports, no IP exposure, works behind CGNAT, and Cloudflare provides automatic HTTPS with a valid certificate.
