Run NovaPanel behind a Cloudflare Tunnel
Homelab setup: expose the admin and customer panels through cloudflared without opening ports. Plus the honest list of what doesn't fit through an HTTP-only tunnel.
This guide is for homelabbers who want to expose NovaPanel without opening ports on their router. Cloudflare Tunnel (cloudflared) forwards traffic from Cloudflare's edge to a daemon running on your panel host, so nothing has to be publicly routable.
Cloudflare Tunnel only carries HTTP/HTTPS. Anything else NovaPanel serves (mail, FTP, authoritative DNS) needs a different solution. Read the table below before you commit to this setup.
What works, what doesn't
| Surface | Via Cloudflare Tunnel? | Notes |
|---|---|---|
| Admin panel (port 2087) | Yes | Point a tunnel hostname at http://localhost:2087 |
| Customer panel (port 2083) | Yes | Point a tunnel hostname at http://localhost:2083 |
| Customer websites (Caddy 80/443) | With caveats — see below | Caddy's automatic HTTPS depends on Let's Encrypt reaching port 80/443 |
| Mail — Postfix SMTP (25/465/587) | No | Not HTTP. Use a relay (SES, Mailgun, Postmark) or expose mail ports directly |
| Mail — Dovecot IMAP/POP (143/993/995) | No | Same — not HTTP |
| FTP / FTPS (21 + passive range) | No | Use SFTP over SSH instead, and tunnel SSH with cloudflared access ssh |
| Authoritative DNS (53) | No | Use Cloudflare DNS for your zones and point NS records at Cloudflare |
If your homelab use case is panel plus customer websites only, this setup works well. If you also need first-party mail or FTP, you'll need a public IP for those ports — Cloudflare Tunnel can't carry them.
Step 1 — Install cloudflared on the panel host
NovaPanel runs on Debian/Ubuntu. Install Cloudflare's official package:
sudo mkdir -p /usr/share/keyrings
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 $(lsb_release -cs) main" \
| sudo tee /etc/apt/sources.list.d/cloudflared.list
sudo apt-get update && sudo apt-get install -y cloudflared Authenticate against your Cloudflare account (this opens a browser):
sudo cloudflared tunnel login Create the tunnel and grab its UUID:
sudo cloudflared tunnel create novapanel
# → Created tunnel novapanel with id <UUID>
# → Tunnel credentials written to /root/.cloudflared/<UUID>.json Step 2 — Tunnel config (panel only)
Drop this at /etc/cloudflared/config.yml:
tunnel: <UUID>
credentials-file: /root/.cloudflared/<UUID>.json
ingress:
# Admin panel
- hostname: admin.example.com
service: http://localhost:2087
# Customer panel
- hostname: panel.example.com
service: http://localhost:2083
# Catch-all (required) — everything else gets a 404 from cloudflared
- service: http_status:404 Route the hostnames through the tunnel:
sudo cloudflared tunnel route dns novapanel admin.example.com
sudo cloudflared tunnel route dns novapanel panel.example.com Install and start the systemd unit:
sudo cloudflared service install
sudo systemctl enable --now cloudflared
sudo systemctl status cloudflared
The two hostnames now serve the panel over Cloudflare's edge TLS. NovaPanel doesn't need to bind to a public IP — localhost:2083 / localhost:2087 is enough.
Step 3 — Customer websites: choose one of two modes
NovaPanel's Caddy issues Let's Encrypt certificates for every customer domain using the HTTP-01 (port 80) or TLS-ALPN-01 (port 443) ACME challenges. When Cloudflare proxies a hostname (orange-cloud), the challenge requests never reach your origin — Caddy can't get a cert.
Two ways around it today:
Mode A — DNS proxy off (grey-cloud)
For domains served by NovaPanel's Caddy, set the Cloudflare DNS record to DNS only (the grey cloud icon, not the orange one). Cloudflare publishes the A/AAAA record but doesn't proxy the traffic — Let's Encrypt can hit port 80 on your origin directly, and Caddy issues a real public cert.
Trade-off: those hostnames lose Cloudflare's CDN, WAF, and DDoS protection. They still get DNS hosting. You still need ports 80 and 443 reachable on your origin for the grey-clouded domains, which usually means router port-forwarding for those two ports.
Mode B — Cloudflare Full (strict) with origin cert
Keep the orange cloud, but install a Cloudflare Origin CA cert on the origin and disable Caddy's ACME. Cloudflare's edge trusts the Origin CA but browsers don't — so it only works behind Cloudflare.
- In Cloudflare → SSL/TLS → Origin Server, create a 15-year Origin CA cert covering
*.example.comandexample.com. - Save the cert + private key on the panel host.
- Edit the customer site's Caddyfile to use the origin cert explicitly and disable automatic HTTPS:
example.com { tls /etc/caddy/origin/example.com.pem /etc/caddy/origin/example.com.key root * /srv/sites/<user>/public_html # ... rest of the site config NovaPanel generated } - Set SSL/TLS mode to Full (strict) in the Cloudflare dashboard.
- Add the hostnames to your
cloudflaredingress, pointing athttps://localhost:443withoriginServerNameset to the customer domain.
This keeps the orange cloud (CDN, WAF, DDoS) and avoids opening 80/443 on your router, at the cost of editing per-site Caddy configs.
Heads-up: NovaPanel doesn't natively manage Origin CA certs yet. If you re-save the site in the panel, automatic Caddy regeneration will overwrite your tls override. Native support for ACME DNS-01 (Cloudflare DNS) and Origin CA certs is on the roadmap.
Verification checklist
After setup, walk through these to confirm everything is wired up:
sudo systemctl status cloudflared→ active (running)https://admin.example.comopens the admin loginhttps://panel.example.comopens the customer login- A test customer site loads over HTTPS without a cert warning
- Cloudflare → Network → "Free WAF rules" don't flag the panel's WebSocket endpoints (
/api/customer/sites/*/terminal,/api/customer/notifications/stream) — if they do, add a bypass rule for those paths
Common gotchas
- WebSockets idle out after 100s. Cloudflare's default WebSocket idle timeout is 100 seconds; the panel's terminal and notification streams will reconnect, but for long terminal sessions consider Cloudflare Zero Trust which lets you raise the timeout.
- Large file uploads cap at 100 MB on Free plan. Cloudflare's body size limit applies to the File Manager and database imports. Pro bumps it to 200 MB, Business to 500 MB, Enterprise is configurable.
r.Hostincludes the tunnel hostname. The panel's impersonation redirect usesr.Hostto construct the customer panel URL — make sure both hostnames are on the same root domain so the redirect works (e.g.admin.example.comandpanel.example.com, notadmin.org-a.comandpanel.org-b.com).