The screenshot shows that I'm a grizzled old systems programmer, having difficulty finding my inner hipster web-designer.
The chain is quite long.
The serial port on the Arduino is connected to the console serial on the boat's internet router. via an opto-isolated half duplex current loop interface.
The boat's router runs a little daemon which listens on a TCP port and copies data to/from the serial port. There's no protocol translation, so once the TCP connection is set up, the code to talk to this is identical to talking directly over the USB virtual serial line.
The tools I had to talk to the BMS over the serial line got extended to talk over TCP. This is mainly useful because I don't need to plug my laptop into the BMS USB port to get data whilst on the boat now.
It turns out that Three mobile internet still gives a real, routable, IP address, and the USB stick modem I use allows port forwarding. I use dynamic DNS to set a record in my DNS zone to the current IP address of the modem, and port-forward to the router behind it, so the BMS is now directly accessible from the global internet with the same TCP interface as before.
I have a virtual private server in the cloud running Linux which has a web server on it and I just made a trivial CGI program which runs the data-access tool to get the data, and reformats the data as brain-dead html.
So, the chain is webserver -> CGI -> BMStool -> internet -> boat router -> relay daemon -> serial line -> BMS
MP.