How I Connected a Netlify Function to My Home Server Using a Dynamic Cloudflare Tunnel
Description and use
A permanent DNS entry for a Cloudflare Tunnel, running as a systemd service, and a Netlify Function that uses an environment variable to reach the home API, eliminates 404 errors on tunnel restarts.
Problem
Netlify Functions needed to reach a home‑server API, but Cloudflare Tunnel URLs changed on restart, causing 404s and manual secret updates.
Outcome
A permanent DNS hostname for the Cloudflare tunnel, automated service startup, and environment‑variable‑based API calls eliminate manual updates and 404 errors, ensuring reliable communication between Netlify front‑end and home automation stack.
Workflow
- Create a named Cloudflare tunnel and route a permanent DNS name to it.
- Configure cloudflared with a config.yml pointing to local service and hostname.
- Enable and start cloudflared as a systemd service.
- Store the stable hostname in a Netlify environment variable and fetch it in the function.
- Set up a health‑check Netlify Function that polls Cloudflare metrics and restarts the service via SSH if inactive.
Evidence
When I moved the front‑end to Netlify, my Netlify Functions needed to hit that internal API. A Cloudflare Tunnel (formerly Argo Tunnel) solved the NAT issue, but every time the tunnel restarted its public URL changed.
Create a named tunnel (only once) cloudflared tunnel create home‑api
cloudflared tunnel route dns home‑api home.api.mybiz.com
/etc/cloudflared/config.yml url: http://localhost:3000 hostname: home.api.mybiz.com
sudo systemctl enable cloudflared@home‑api sudo systemctl start cloudflared@home‑api
exports.handler = async () => { const base = process.env.HOME_API_URL || "https://home.api.mybiz.com"; const res = await fetch(${base}/status); const data = await res.json(); return { statusCode: 200, body: JSON.stringify(data) }; };
curl -s https://api.cloudflare.com/client/v4/accounts/<ACCOUNT_ID>/tunnels | jq '.result[] | select(.name=="home‑api") | .status'
- Record date: 2026-10-18T13:41:16.528Z