- Published on
Cloudflared Tunnel Guide
- Authors
- Name
- goodhulk
🧭 Motivation & Use Cases
Self-hosted tools like dashboards, file servers, or development UIs are great—until you need to access them from outside your local network. Opening firewall ports feels risky, dynamic IPs are annoying, and VPN setups can get complex. Reverse tunnels are a practical middle ground.
This guide covers one such tunnel solution, using cloudflared
, to make a local service securely accessible via a subdomain, without requiring root privileges or port forwarding.
✨ Requirements
- A domain managed via Cloudflare (e.g.
yourdomain.com
) - A subdomain already created in DNS (e.g.
home.yourdomain.com
) - A running local service (e.g.
localhost:9000
for Portainer, Homer, etc.) - Basic CLI usage
Optional:
- Dynamic DNS (if you want fallback SSH or VPN access)
- API token if you'd rather use automation over browser login
♻️ Step 1: Clean Up Old Versions (Optional)
sudo rm -rf /usr/local/bin/cloudflared
sudo rm -rf /etc/cloudflared
sudo rm -rf ~/.cloudflared
cloudflared
(User-level)
🛠️ Step 2: Install mkdir -p ~/bin
cd ~/bin
curl -L https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64 -o cloudflared
chmod +x cloudflared
Add to your PATH if needed:
echo 'export PATH=$HOME/bin:$PATH' >> ~/.bashrc
source ~/.bashrc
Test:
cloudflared --version
🔐 Step 3: Login with Cloudflare
cloudflared tunnel login
This opens a browser window to link your domain account.
Alternatively, use an API token:
export CLOUDFLARE_API_TOKEN="your-token-here"
cloudflared tunnel login
Token scopes required:
- Zone.DNS
- Zone:Read
- Account.Tunnel:Edit
⚡ Step 4: Create the Tunnel
cloudflared tunnel create dashboard-tunnel
This generates a .json
credential file in ~/.cloudflared
.
🌐 Step 5: Link Tunnel to Subdomain
cloudflared tunnel route dns dashboard-tunnel home.yourdomain.com
Make sure no existing A/AAAA/CNAME record is already defined for the subdomain.
🧾 Step 6: Create Tunnel Config
nano ~/.cloudflared/config.yml
Example config:
tunnel: dashboard-tunnel
credentials-file: /home/youruser/.cloudflared/xxxxxxxxx.json
ingress:
- hostname: yoursubdomain.yourdomain.com
service: http://localhost:9000
- service: http_status:404
🚀 Step 7: Start the Tunnel
cloudflared tunnel --config ~/.cloudflared/config.yml run
Access via:
https://yoursubdomain.yourdomain.com
🔄 Optional: Autostart via systemd (User Scope)
mkdir -p ~/.config/systemd/user
sudo loginctl enable-linger $USER
Then create:
nano ~/.config/systemd/user/cloudflared.service
Contents:
[Unit]
Description=Cloudflare Tunnel
After=network.target
[Service]
ExecStart=%h/bin/cloudflared --config %h/.cloudflared/config.yml tunnel run
Restart=on-failure
[Install]
WantedBy=default.target
Enable the service:
systemctl --user daemon-reexec
systemctl --user daemon-reload
systemctl --user enable cloudflared
systemctl --user start cloudflared
🧪 Debug & Test
Check running process:
ps aux | grep cloudflared
Test internal service:
curl http://localhost:9000
🌐 Optional: Dynamic DNS
While tunnels don’t require a static IP, other services (like SSH or VPN) might. I configured DDNS using the Cloudflare DNS API to keep fallback access possible. Since my domain is already on Cloudflare, that choice kept things simple.
✅ Summary
- A local service (e.g. dashboard) is securely accessible via HTTPS
- No port forwarding or root access required
- Can survive reboots using systemd user services
- Optional fallback via Dynamic DNS
This solution isn’t the only one – but if you already manage your DNS through Cloudflare, it’s relatively low-friction and secure.