Making Old Systems Accessible Via The Web
Aug. 14th, 2019 09:45 am I started out with a bunch of simh (well, and klh-10, and dps8...) processes running on a couple of Raspberry Pis; I had their consoles set up under GNU Screen, which let me attach and detach easily, and have everything more-or-less in one place.
For non-console access things were a hodgepodge of telnet-reachable ports; most of the systems had virtualized dz devices (dx busy-waits, which made it undesirable for packing a lot of guest systems onto a small number of hosts) listening on a host port, but some had full TCP/IP stacks and their own telnet daemons.
I got a little sick of remembering which port was which system, so I wanted to build a menu to manage that for me. Remember the early 90s, before consumer TCP/IP was really a thing, where you'd dialup into a terminal server (a text-mode thing then, not the fancy-pants remote desktops we have now), and type the name of the host you wanted to connect to? Like that.
I'm going to tell this story as if it all happened in a logical fashion and made sense, but the actual development was a lot more chaotic. You know how it is.
For writing the menu system I had a couple of design goals. First, since I plan for the list of systems accessible to change as I play with different things, it needed to be document-driven rather than keeping the menu in the code. Second, I wanted to write it in Go, because I haven't really gotten to use Go since changing to my current job back in 2016, and I miss it.
The basic design was very simple: show a menu, take an input selecting a menu item, and exec telnet with the proper parameters to connect the user session to the guest system. Once I'd blown the dust off my Go knowledge, it didn't take a lot of implementation. https://github.com/athornton/tmenu .
Well, that certainly helped; I just needed to run my menu and I didn't have to remember what host and port each system was accessible on. Next I figured I could make this network-accessible, and went to set it up as an inetd service. Well, really these days, it's a systemd service, but same idea: hook up a port to the process standard input and output.
Turned out I was going to have to implement telnet options in both the front and back end to do things like not-echoing-the-password when a user connected, and that didn't seem like fun, and so I decided, "hey, why don't I just put it inside a web-accessible terminal?"
I knew this was likely to work. I work on JupyterLab in my day job, and it has an excellent terminal emulator in it, which is based on xterm.js. So now the problem collapsed to "is there already a websocket terminal application?"
A little Googling got me to "gotty". It seems to have been abandoned, and it didn't quite build with current Go versions, but a little bit of work got me to a version that works just fine. I submitted a pull request, in case it hasn't been abandoned. You can get a buildable version from https://github.com/yudai/gotty/pull/259 .
So now I could run gotty from systemd, and be listening on a particular port (I chose 6180) for HTTP connections, which would upgrade to websocket connections, and let me run my menu.
Well, that's nice and all, but still cleartext, and would require me to open a cleartext port back into my network to expose it. However...at this point, given a web server, which I have, it shouldn't be hard to build a reverse proxy. I use Apache 2.4, which is a little trickier than Nginx (which is what my project at work uses), but it wasn't too tough. The magic setting that took a while to figure out was ProxyPreserveHost On.
With that in place, I just gave the thing a name ("mvsevm.fsf.net"), added it to my Let's Encrypt names, acquired a certificate for it, and then I had a proxied TLS-encrypted web interface to a text-mode front end for a bunch of ancient systems.