Ultimately reading firewall logs to do port knocking is most secure way, because - as you said - there is virtually no attack surface.
I would argue that port knocking is extremely inconvenient and does not work in every scenario. So for me it's a tradeoff between "ultimate" security and convenience.
Instead of knocking on ports, send actual HTTP requests to different paths. Over TLS or just plain HTTP.
So where you’d port knock a sequence of ports here instead you send GET requests to some different, publicly known paths
GET /index.htm
GET /about_us.htm
GET /about_us.htm
GET /index.htm
GET /about_us.htm
GET /products.htm
You get the idea.
And now then the challenge is that if you’re on a network that does HTTP caching, it would interfere with this.
But we already have the well known cache-busting technique for that right, so
GET /css/main.css?ver=64729929
GET /js/bundle.js?ver=947367292
GET /js/bundle.js?ver=7483939
And so on. And version is for example current Unix time and is actually ignored in terms of “knocking”. Only the path matters.