![]() |
|
Guide Fix Cloudflare Tunnel Profile Not Found in aaPanel - Printable Version +- AdminsForum (https://adminsforum.com) +-- Forum: Free & open-source control panels (https://adminsforum.com/Forum-free-open-source-control-panels) +--- Forum: aaPanel (https://adminsforum.com/Forum-aapanel) +---- Forum: aaPanel Guides & Tutorials (https://adminsforum.com/Forum-aapanel-guides-tutorials) +----- Forum: aaPanel Plugins & Integrations Guides (https://adminsforum.com/Forum-aapanel-plugins-integrations-guides) +----- Thread: Guide Fix Cloudflare Tunnel Profile Not Found in aaPanel (/Thread-guide-fix-cloudflare-tunnel-profile-not-found-in-aapanel) |
Fix Cloudflare Tunnel Profile Not Found in aaPanel - DEV - 10-11-2026 New to this plugin? Start with Install Cloudflare Tunnel Plugin in aaPanel Free Edition, then use this article if you encounter the profile error. A newly created Cloudflare Tunnel profile can return “Profile not found” before its first browser login. This article explains the confirmed cause and the local code fix, plus the other issues found during review. Reviewed build: Community plugin by fdciabdul, source commit ff0c7359f050fbca2b9efab11b61aa462d65b2d0; info.json version 1.3.0. This is a source-level review with isolated tests. Live plugin installation and Cloudflare end-to-end verification are pending. The fixes below do not make the whole plugin a certified or production-tested release. 1. Fix “Profile not found” on first login The UI allows adding a profile without an API token. However, DnsManager.find_profile() looks in _all_profiles(), which intentionally hides profiles that have neither token nor cert_path. That filter is useful for choosing working DNS credentials, but wrong for resolving the profile that is about to receive its first browser-login certificate. In dns_manager.py, change find_profile() to check the saved profiles first: Code: def find_profile(self, profile_id):
for p in self._read_profiles():
if isinstance(p, dict) and p.get("id") == profile_id:
return dict(p, virtual=False)
for p in self._all_profiles():
if p["id"] == profile_id:
return p
return None2. Fix unsafe UI string encoding Profile names are inserted into single-quoted JavaScript onclick arguments using an HTML-only encoder. An ordinary apostrophe can break an action; crafted text can introduce script in the authenticated panel UI. Encode for the JavaScript string context first, then the surrounding HTML attribute. The reviewed patch uses a separate jsesc helper for those action arguments, and escapes names/errors in HTML-rendered dialogs. HTML escaping alone is insufficient here. Do not test script injection on a live shared panel. Our six isolated JavaScript tests round-trip apostrophes, backslashes, quotes, newlines and markup without executing injected instructions. The entire UI script also parses successfully. We have not demonstrated unauthenticated panel compromise. 3. Protect installer staging and credentials The original binary installer downloads into one predictable file under /tmp. A privileged process should use a unique private temporary directory, invoke curl/install with argument arrays, restrict download redirects to HTTPS and check command results. The review patch implements that approach. Independent checksum verification and release pinning remain future work. Validate tunnel IDs as UUIDs before saving them or constructing credential paths. Apply mode 0600 to existing and newly relocated tunnel JSON credentials, and report relocation failures. Keep credentials out of public web directories, screenshots and support replies. 4. Fix configuration encoding and restart reporting In ingress_manager.py, use proper quoted YAML scalar encoding rather than only replacing quotation marks. JSON-quoted strings are valid YAML scalars and handle backslashes/control characters: Code: def _yaml_escape(s):
return json.dumps(str(s), ensure_ascii=True)Code: restarted = subprocess.run(
["systemctl", "restart", SERVICE_NAME],
capture_output=True, text=True, timeout=30,
)
if restarted.returncode != 0:
return public.returnMsg(
False,
"Config written, but service restart failed: "
+ (restarted.stderr or restarted.stdout),
)5. Avoid DNS data loss Before an automatic CNAME upsert, inspect every record returned for the hostname. Our patch refuses conflicting non-CNAME or multiple-record responses instead of replacing the first record. A user-selected zone must also match the hostname; stale/unavailable zone selections are rejected rather than silently redirected to another zone. For removal, refuse records that are not tunnel-target CNAMEs and check each Cloudflare deletion response. Do not delete A, AAAA, MX or TXT records simply because they share a hostname. Our tests verify these refusal paths and confirm API errors are returned. Remaining limitation: the patch recognizes tunnel CNAMEs by target suffix, not an ownership manifest for the particular tunnel. Full DNS/config/service rollback and concurrent-write locking are also still needed. 6. Validate before applying to a server Back up the installed plugin directory, runtime data and /etc/cloudflared first. Match the exact source version; do not paste partial changes into an unrelated older release. Check Python syntax and run the isolated tests. Our local review passed 13 backend tests and six UI string-encoding checks, plus script parsing and diff whitespace checks. Then use a disposable lab server to verify import, empty-profile login, account selection, credentials, origin response, generated ingress, DNS changes and actual service state. An API token accepted by the verification endpoint does not prove the zone permissions needed by this plugin. Browser login for tunnel CLI operations and the DNS API token serve different purposes. 7. What is not yet fixed or verified
Credits and references: Original plugin repository · Author's aaPanel thread · Cloudflare tunnel permissions |