My application listens on port 80, for the usual local services. I also want to use WiFi Connect. When the network is unavailable, port 80 needs to go to the WiFi Connect captive authentication portal.
Any suggestions on how to handle these situations?
I am also wondering if access to an applications admin UI over HTTP might be handy while WiFi Connect has the AP mode enabled, in some circumstances. So maybe I should change the port used by WiFi Connect…
I guess it isn’t a bug, dnsmasq is just answering all queries with the local IP, so whatever port the client system uses is what you’re going to get. So I’m not sure what real use PORTAL_LISTENING_PORT actually is.
What’s the solution, here? Can I have two containers trying to listen on the same port with one of them taking precedence? Ideas?
Wifi-connect has a script that launches it. If the wifi is already connected, it just goes into sleep. Instead of sleep, you could put your app there. Then if the device is not connected to wifi it will launch wifi connect on port 80 with a captive portal, and if it is connected it will launch your app on port 80 and never the two at the same time. Would likely add in a check in the script to loop through and see if the connection state has changed.
This however depends on not wanting to have your app running at the same time as wifi connect, I.e. forcing users to connect to a wifi hotspot rather than use your app offline.
I have on my to do list to find a solution for this although do need both online and offline access to my app which is why I’m interested in this thread. May have to explore whether I can make my own captive portal in the app.
Best I can tell, if you have WiFi connect running (not on port 80), a user connected, and something else running on port 80 that redirects certain urls to a page of your choice then the captive portal will open and load that page. https://github.com/balena-io/wifi-connect/issues/207#issuecomment-380039522
Surprisingly it’s tricky to find a comprehensive list of URLs to forward but this was helpful:
Hi there, the change to PORTAL_LISTENING_PORT would need to be coupled with an iptables rule to forward packets from port 80 (default) to appropriate non-default port where the portal is listening. This can be done in a privileged container with host networking.
That makes a lot of sense! And could easily be made optional via an environment variable. Should we do this in the wifi-connect block or in the wifi-connect app?
You should start with https://github.com/balenablocks/wifi-connect. There are a few ways of doing this, but if you take the wifi-connect Dockerfile.template and in start.sh insert a line to add the iptables rule before the wifi-connect starts, that should be enough. You should check if the rule is there first, before adding it and also probably a good idea to remove it on container exit using traditional trap signal handling function in scripts.
One of my colleagues did a couple tests running a container on a balenaOS device (his was a NUC, but this procedure should work regardless of hardware):
balena-engine run -it --privileged ubuntu /bin/bash
balena-engine run -it --privileged --network host ubuntu /bin/bash
He observed that iptables lists an empty table with the former, and a populated table with the latter. Therefore, we presume the container is running without specifying network_mode: host in the docker-compose.yml file. It would be strange, though, because the sample docker-compose.yml file of the balenablock has network_mode: host, and we presume you used https://github.com/balenablocks/wifi-connect
The commands launch a simple Ubuntu container in privileged mode, which means they have access to hostOS stuff. The first example uses the “Docker” network addressing (usually 172.x.x.x.). The second uses your device’s host networking (something like 192.x.x.x). One thing you might try is adding network_mode: host to your frontend: stanza.
But I can’t/shouldn’t be using those commands myself, on my macOS workstation.
The frontend has nothing to do with the wifi-connect container, it’s a placeholder for the UI that needs to run on port 80 once the device has connectivity. I’m testing the iptables commands from within the wifi-connect container.