I’ve been getting going with Balena Blocks and started putting together a node-exporter block to deliver device metrics to Prometheus. This runs in a container with it’s own webserver on port :9100 by default.
Now we can map that to port :80 easily enough with
docker-compose.yml to make it available via the Balena Public URL but then that container hogs the port.
If we want to do anything else with that public URL we can’t very easily.
What I wanted was a way to proxy requests into different containers based on different criteria, such as the path of the URL request received.
Enter Traefik which does this - and more - really rather well.
So I have created a block here which adds the Traefik container, with a simple example which routes public accesses on
https://my-device-id.balenadevices.com/metrics through to the internal
There’s more to do - mainly I want to add some more security via auth - but it seems to work quite nicely
This is fantastic, and very timely.
Pranav, one of the the team is currently working on removing the limitation of only having port 80 access to a device, and also enabling the option for TLS to be terminated at the device level, rather than in the cloud. As part of this work we would like the device public URL to be augmented such that you could make a request to
service.deviceUUID-balenadevices.com - but this would require something on the device to proxy those requests out to the relevant service. We had identified Traefik as one possible option, and initially to implement it as a block.
I’ll let @pranavpeshwe tell you more - but this is very exciting indeed!
Thank you for sharing your work, and thanks @phil-d-wilson for looping me in. As Phil mentioned, we have been thinking on similar lines about the problem you’ve identified and are working to resolve it.
As you’ve chosen to do, using URLs is the shortest path to multiplexing services on the single public device URL port. We are thinking of giving users the capability to resolve services using subdomains. We feel that it provides a much cleaner separation for microservices that users run on their devices (for e.g a HTTP(S) request to prometheus.my_device_uuid.balena-devices.com will result API calls being routed to the prometheus service on the device).
Subdomains do bring in their own complications/limitations most importantly wrt. TLS. The idea is to make users’ life easy by building a block that automates x509 certificate generation/maintenance for all of their services. Combined with the ability in balenaCloud backend to let devices terminate their own TLS connections, users will be able to have an end-to-end secure & private channel between device services and their consumers on the Internet.
Any suggestions are welcome. I’ve omitted some details in the interest of brevity, so feel free to probe with questions.
Thanks again for your efforts and for making your work available to everyone.
Glad you like it! Thanks for the kind words. Knowing how you are all always beavering away there at Balena I suspected you would be doing something like this!
As part of this work we would like the device public URL to be augmented such that you could make a request to
service.deviceUUID-balenadevices.com - but this would require something on the device to proxy those requests out to the relevant service
I like this very much! I did think about this a bit but I wasn’t sure I could do it. If I made a request to
service.deviceUUID-balenadevices.com today would that get passed through to the device? I would try but I don’t have anything online atm.
We had identified Traefik as one possible option, and initially to implement it as a block.
Interested to see what we could do to reconfigure in Traefik it for this!
Subdomains do bring in their own complications/limitations most importantly wrt. TLS
Yes absolutely. This had occurred to me too, and I can see pros and cons to moving the TLS support responsibility onto the device, but all in all I think I would like the option for this. I do think there’s a lot of value in Balena providing cert management as that is an absolute PITA and utterly necessary for embedded devices (in particular timely renewal, cert rolling, and repudiation).
Taking a step back I was trying to do something which should be simple and is really necessary but I couldn’t get auth going: i.e. Adding basic authentication to a web server service. I can get the auth dialogue to come up on Traefik but for some reason I can’t authenticate. Now this might be finger trouble on my part but I did wonder if the https:// proxy at the Balena end was stripping things out. I can test locally when I am in the office I guess.
I did wonder if the https:// proxy at the Balena end was stripping things out
I can help you debug in case you are not able to reproduce the issue locally (i.e things work locally but not with balenaCloud). Please share whatever logs you can. If feasible, do share any command/script/code-snippet I can use to reproduce the problem myself.
Thanks! Got sidetracked onto other things but will get back around to this and let you know what I find!