Skip to content

net/cloudflared: new plugin for Cloudflare Tunnel integration#5429

Merged
fichtner merged 15 commits into
opnsense:masterfrom
insanityinside:net/cloudflared
Jun 10, 2026
Merged

net/cloudflared: new plugin for Cloudflare Tunnel integration#5429
fichtner merged 15 commits into
opnsense:masterfrom
insanityinside:net/cloudflared

Conversation

@insanityinside

@insanityinside insanityinside commented May 8, 2026

Copy link
Copy Markdown
Contributor

Important notices

Before you submit a pull request, we ask you kindly to acknowledge the following:

If AI was used, please disclose:

  • Model used: Claude Sonnet 4.6 (Anthropic)
  • Extent of AI involvement: Code generation and review assistance throughout development. All code has been manually reviewed and thoroughly tested.

Describe the problem

OPNsense has no native interface for managing Cloudflare Tunnel (cloudflared). Users behind CGNAT — where a publicly reachable WAN IP is not available — commonly use Cloudflare Tunnel as a supported, production-grade solution for exposing services without port forwarding. Managing it currently requires manual CLI setup with no OPNsense service integration.


Describe the proposed solution

Adds a new plugin net/cloudflared that integrates Cloudflare Tunnel into OPNsense as a first-class service. This is an extensive rework of #5406 (original authorship and credit: @AlanMartines), which this PR builds on and supersedes. It is revised to address the architectural feedback from that review, and integrates my real-world experience with the net/cloudflared port on native FreeBSD.

Key architectural change from #5406:
The original PR bundled a custom binary installer that downloaded cloudflared from a third-party GitHub fork. This plugin instead declares PLUGIN_DEPENDS= cloudflared, delegating binary management entirely to pkg via the FreeBSD ports tree. The plugin is a pure configuration wrapper, as requested in the review of the original PR. net/cloudflared would need adding to the OPNsense port builds as it is not currently present in the repo (I manually installed the pre-built FreeBSD binary package for testing). I'm assuming it's not an automatic process with that PLUGIN_DEPENDS line.

Functionality carried from the original PR:

  • Native MVC UI under Services > Cloudflare Tunnel > Settings
  • Token-based setup (Method 1 — managed tunnels via Cloudflare Zero Trust dashboard)
  • Secure token handling: passed via TUNNEL_TOKEN environment variable so it does not appear in ps aux; /etc/rc.conf.d/cloudflared set to 0600 permissions when configuration written
  • Post-quantum encryption option (--post-quantum)
  • Registered in System: Diagnostics: Services with start/stop/restart

Enhancements added in this rework:

  • Transport protocol selector: Auto (QUIC with HTTP/2 fallback, default), QUIC-only, or HTTP/2-only.
  • quic-disable-pmtu-discovery option: workaround for intermittent QUIC stream errors on networks where ICMP is filtered
  • Native log viewer functionality added
  • Crash recovery: cron action available to add automatic recovery if user requires
  • newwanip hook to restart on WAN IP change, if daemon exited with error
  • Boot-time startup via configure hook
  • Hardcoded no-autoupdate: true (pkg manages the binary; self-update is inappropriate)
  • Security notice in UI: tunnel traffic bypasses OPNsense firewall rules and access control must be enforced in Cloudflare Access

Translations:
Machine-assisted translations for 20 languages, including original pt-BR translations from #5406, are prepared and ready to be contributed to the OPNsense lang repo via POEditor as a follow-up to this PR. I'm assuming that's the correct way to handle the translated strings for the plugin, please correct me if not.

Testing:
Tested on OPNsense 26.1.7 / FreeBSD 14.x (amd64).

  • Enable/disable service via Apply
  • Token accepted and not visible in ps aux
  • Auto mode: tunnel connects, falls back to HTTP/2 if QUIC unavailable after around 2 minutes of retries as per cloudflared default behaviour
  • QUIC-only mode: UDP 7844 firewall rule present, tunnel connects
  • HTTP/2-only mode: TCP 7844 firewall rule present, tunnel connects
  • Post-quantum and PMTU options passed through to cloudflared
  • Log viewer loads, paginates, and refreshes correctly, follow mode works correctly without any visual artifacts
  • Tunnel health badge reflects live state
  • Service appears in System: Diagnostics: Services
  • Confirmed behaviour when booted without WAN or DNS available, automatic recovery functional
  • Tested tunnel functionality to internal network services

Related issue

Closes #5070

@insanityinside insanityinside marked this pull request as ready for review May 8, 2026 02:00
Copilot AI review requested due to automatic review settings May 8, 2026 02:00

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new net/cloudflared plugin to integrate Cloudflare Tunnel (cloudflared) into OPNsense as a managed service with a native MVC UI and backend/service wiring, relying on the FreeBSD cloudflared package for the binary.

Changes:

  • Introduces MVC pages + API endpoints to configure, control, and display tunnel/log status.
  • Adds configd actions, templates, and scripts to generate config, apply tunables, and expose tunnel health.
  • Adds firewall hook + watchdog (cron) for protocol-specific outbound rules and crash recovery.

Reviewed changes

Copilot reviewed 23 out of 23 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
README.md Adds the new plugin to the repository plugin list.
net/cloudflared/Makefile Declares the plugin and its dependency on cloudflared.
net/cloudflared/pkg-descr Describes the plugin’s purpose and major features.
net/cloudflared/LICENSE Adds plugin license file.
net/cloudflared/src/opnsense/service/templates/OPNsense/Cloudflared/+TARGETS Installs generated templates to rc.conf.d, config.yml, and sysctl.d.
net/cloudflared/src/opnsense/service/templates/OPNsense/Cloudflared/rc.conf.d Generates rc.conf.d service enablement + token env wiring.
net/cloudflared/src/opnsense/service/templates/OPNsense/Cloudflared/config.yml Generates cloudflared config (metrics, protocol, flags).
net/cloudflared/src/opnsense/service/templates/OPNsense/Cloudflared/tunables.conf Generates sysctl tunables for QUIC performance.
net/cloudflared/src/opnsense/service/conf/actions.d/actions_cloudflared.conf Defines configd actions (start/stop/restart/status/reconfigure/log/tunnel_status).
net/cloudflared/src/opnsense/scripts/OPNsense/Cloudflared/reconfigure.sh Reloads templates, applies sysctls, restarts service, reloads firewall.
net/cloudflared/src/opnsense/scripts/OPNsense/Cloudflared/tunnel_status.sh Computes tunnel health via metrics + log cross-check.
net/cloudflared/src/opnsense/scripts/OPNsense/Cloudflared/monitor.sh Watchdog script to restart the service when it dies unexpectedly.
net/cloudflared/src/opnsense/mvc/app/views/OPNsense/Cloudflared/index.volt Adds UI for settings, service controls, health badge, and log viewer.
net/cloudflared/src/opnsense/mvc/app/models/OPNsense/Cloudflared/Menu/Menu.xml Adds Services menu entry for the plugin UI.
net/cloudflared/src/opnsense/mvc/app/models/OPNsense/Cloudflared/ACL/ACL.xml Adds ACL for UI/API endpoints.
net/cloudflared/src/opnsense/mvc/app/models/OPNsense/Cloudflared/Cloudflared.xml Defines plugin configuration model (enabled/token/protocol/tunables).
net/cloudflared/src/opnsense/mvc/app/models/OPNsense/Cloudflared/Cloudflared.php Adds BaseModel class for the plugin model.
net/cloudflared/src/opnsense/mvc/app/controllers/OPNsense/Cloudflared/IndexController.php Serves the main UI page and general form.
net/cloudflared/src/opnsense/mvc/app/controllers/OPNsense/Cloudflared/forms/general.xml Defines UI fields (token, protocol, tunables, flags).
net/cloudflared/src/opnsense/mvc/app/controllers/OPNsense/Cloudflared/Api/SettingsController.php Exposes settings get/set API for the model.
net/cloudflared/src/opnsense/mvc/app/controllers/OPNsense/Cloudflared/Api/ServiceController.php Exposes service actions plus tunnel status/log APIs.
net/cloudflared/src/etc/inc/plugins.inc.d/cloudflared.inc Adds firewall hook, WAN-IP hook behavior, and service registration.
net/cloudflared/src/etc/cron.d/cloudflared Adds a per-minute cron job to run the watchdog script.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread net/cloudflared/src/opnsense/mvc/app/models/OPNsense/Cloudflared/Cloudflared.xml Outdated
Comment thread net/cloudflared/src/etc/inc/plugins.inc.d/cloudflared.inc Outdated
Comment thread net/cloudflared/src/etc/inc/plugins.inc.d/cloudflared.inc Outdated
Comment thread net/cloudflared/src/etc/cron.d/cloudflared Outdated
@insanityinside

insanityinside commented May 8, 2026

Copy link
Copy Markdown
Contributor Author

I did not intend to invoke Copilot to review that, automatic Github settings at work.

It did identify a couple of useful things (bad links) which I fixed in f99ed31 below that I hadn't caught in my code review, and one comment on the cronjob - followed convention I saw in other plugins, but happy to tidy up the header comments if appropriate.

Comment thread net/cloudflared/src/opnsense/mvc/app/models/OPNsense/Cloudflared/Cloudflared.xml Outdated
Comment thread net/cloudflared/src/opnsense/mvc/app/views/OPNsense/Cloudflared/index.volt Outdated
Comment thread net/cloudflared/src/opnsense/mvc/app/views/OPNsense/Cloudflared/index.volt Outdated
Comment thread net/cloudflared/src/opnsense/mvc/app/views/OPNsense/Cloudflared/index.volt Outdated
Comment thread net/cloudflared/src/etc/inc/plugins.inc.d/cloudflared.inc Outdated
@Monviech

Monviech commented May 8, 2026

Copy link
Copy Markdown
Member

I would suggest you remove as much cruft as possible and turn this into a minimum viable product first. I'm sure it could be 30-40% less code than this when using modern examples (e.g. the plugin I referenced).

I work with AI every day, and this output here looks too random and overdesigned at quite a few spots. I don't know why the AI made those decisions, but better prompting and better examples should improve the output by a lot.

Also keep in mind that you will be the owner of the end result and you will need to maintain this and give support for it.

Comment thread net/cloudflared/src/etc/inc/plugins.inc.d/cloudflared.inc Outdated
Comment thread net/cloudflared/src/etc/inc/plugins.inc.d/cloudflared.inc Outdated
@insanityinside

Copy link
Copy Markdown
Contributor Author

Understood. Leave it with me, I'll rebuild it clean by hand, and do my research properly. While it works, it can be a lot slimmer, and I'll take the comments on-board.

Worth closing this PR for now and I'll recreate with a much tidier version? I leant a bit too hard on Claude, and I'm still learning the ropes with LLM code generation vs just writing it myself.

Appreciate the feedback, I'm on it.

@Monviech

Monviech commented May 8, 2026

Copy link
Copy Markdown
Member

You can leave this open, it helps to track the review progress and the actual changes you implement to improve it. No rush with anything.

Comment thread net/cloudflared/src/etc/inc/plugins.inc.d/cloudflared.inc Outdated
@insanityinside insanityinside force-pushed the net/cloudflared branch 2 times, most recently from 42e2ba8 to 3a6cb1c Compare May 12, 2026 15:27
@insanityinside

insanityinside commented May 12, 2026

Copy link
Copy Markdown
Contributor Author

Reimplemented from scratch with the advice from the comments above, based on the existing plugin architecture and reusing whatever components I could. Still having some issues around testing MultiWAN, but I happy to make ongoing improvements once I've got my install into production and can do live testing in a real environment. I've prepped initial basic documentation here - https://github.com/insanityinside/opnsense-docs/blob/net/cloudflared/source/manual/how-tos/cloudflared.rst - ready to merge in if this plugin gets approved, and will sort translation submissions too.

Still used Claude to do the heavy lifting, but with a much tighter spec this time, and the code looks sane. Did manually set the process to "cloudflared" on the logs (as the logfile doesn't contain a process name in /var/log/cloudflared.log), but otherwise it's entirely using the vanilla logging setup now.

Comment thread net/cloudflared/src/opnsense/mvc/app/views/OPNsense/Cloudflared/index.volt Outdated
@insanityinside

Copy link
Copy Markdown
Contributor Author

@Monviech @fichtner Does this plugin need any further work before it gets merged, other than the net/cloudflared package being build on the opnsense repo? Seems to be running solidly on my live OPNsense server now, and has been stripped down to the absolute basics. Let me know if it needs any further changes, and I'll take care of them. I'm happy to maintain the plugin going forwards.

@Monviech

Monviech commented May 28, 2026

Copy link
Copy Markdown
Member

Sorry there is not much time lately but we will circle back eventually.

From what I can see the plugin looks reasonable, though we have to give this another look first (especially if the port builds without problems as well)

@insanityinside

Copy link
Copy Markdown
Contributor Author

Understood, just making sure I'd not missed anything required from me. Am happy if it's on the to-do list, completely understand resource constraints. I'll get the updated translations prepped and request access to the relevant translation projects to upload them.

Hopefully shouldn't be any issues with the upstream package/port, has minimal requirements for build (lang/go125), and ca_root_nss as a runtime dependency (already being built and deployed on pkg.opnsense.org).

@Monviech Monviech left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a few more comments. This looks quite clean already. Nice work so far.

function cloudflared_configure()
{
return [
'newwanip' => ['cloudflared_configure_newwanip'],

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still not sure why we would need that.

@insanityinside insanityinside Jun 9, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's the recovery mechanism if the daemon died on startup if it couldn't resolve DNS, should cleanly pick it back up, as mentioned in #5429 (comment)

Comment thread net/cloudflared/src/opnsense/mvc/app/models/OPNsense/Cloudflared/Cloudflared.xml Outdated
Comment thread net/cloudflared/src/opnsense/scripts/OPNsense/Cloudflared/reconfigure.sh Outdated
Comment thread net/cloudflared/src/opnsense/scripts/OPNsense/Cloudflared/recover.sh Outdated
@Monviech

Monviech commented Jun 9, 2026

Copy link
Copy Markdown
Member

Also you need a PR here to add the cloudflared binary to the build.

https://github.com/opnsense/tools/blob/master/config/26.1/ports.conf

insanityinside and others added 3 commits June 9, 2026 14:01
Wraps the net/cloudflared FreeBSD port to manage the cloudflared daemon
via the standard OPNsense service control interface.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Comment thread net/cloudflared/Makefile Outdated

@Monviech Monviech left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For me this looks okay now, thanks for following up during the review and your work.

Final call is @fichtner

Comment thread net/cloudflared/src/opnsense/service/conf/actions.d/actions_cloudflared.conf Outdated
Comment thread net/cloudflared/src/opnsense/service/conf/actions.d/actions_cloudflared.conf Outdated
@fichtner fichtner self-assigned this Jun 9, 2026
@insanityinside

insanityinside commented Jun 9, 2026

Copy link
Copy Markdown
Contributor Author

Completed the final changes. Let me do a full QA run against it on my router to make sure we've not broken anything and to ensure everything works as expected, then I can check my documentation and translations and make sure we're ready to go. Will update once I've completed testing.

@fichtner fichtner left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good now

one note is that if you need pre-start routines for chmod or anything you can do a cloudflared_setup=setup.sh trick with rc. You can see that in use in a lot of other plugins and core features.

@insanityinside

Copy link
Copy Markdown
Contributor Author

one note is that if you need pre-start routines for chmod or anything you can do a cloudflared_setup=setup.sh trick with rc. You can see that in use in a lot of other plugins and core features.

Only thought was to protect the token in the file - but if a user has access to shell on the box anyway, there's not a huge point to securing it further I don't think. Welcome any feedback on that one though.

@fichtner

fichtner commented Jun 9, 2026

Copy link
Copy Markdown
Member

as long as the service doesn't throw warnings it's ok. we don't recommend/allow giving shell access to anything but full administrators anyway.

Comment thread net/cloudflared/src/etc/inc/plugins.inc.d/cloudflared.inc Outdated
@insanityinside

insanityinside commented Jun 10, 2026

Copy link
Copy Markdown
Contributor Author

Only last thing I think I'll do is remove the restart cronjob completely - it's unnecessary, once it's running it's solid - will commit that, then we're good to merge.

@insanityinside

Copy link
Copy Markdown
Contributor Author

Happy with this now, testing passed, good to merge.

Docs look good to merge - https://github.com/insanityinside/opnsense-docs/blob/net/cloudflared/source/manual/how-tos/cloudflared.rst - PR at opnsense/docs#887 - let me know any feedback/improvements needed.

Will get set up for machine translations for the plugin.

Comment thread net/cloudflared/Makefile Outdated
@fichtner fichtner merged commit ed049cd into opnsense:master Jun 10, 2026
@fichtner

Copy link
Copy Markdown
Member

Merged, thanks!

@fichtner

Copy link
Copy Markdown
Member

Will get set up for machine translations for the plugin.

I'll approve your request now but it will take 2 months until the translations will be regenerated. This is a tedious process we only find the time to do 1-2 times a year.

@fichtner

Copy link
Copy Markdown
Member

PS: Oh, it would make more sense to pick a language or leave it for others to translate. This is an unusual request.

@insanityinside

Copy link
Copy Markdown
Contributor Author

PS: Oh, it would make more sense to pick a language or leave it for others to translate. This is an unusual request.

Ah, I was trying to be helpful - I'm used to generating appropriate translations and uploading them, and then having users tweak if they have a better version. I figured something was better than nothing. I looked at the build process on https://github.com/opnsense/lang, I can spin up a build box locally if it'd help, or I can leave it alone and let you do your usual processes 🙂

I've got the machine translation files if they're helpful for each language on poeditor.com, but I assume the strings would need gathering into en_US.pot first, by whatever means.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

Feature request: add CloudFlare tunnel

4 participants