Using mosh passably on Windows
I am someone who loves to make my life difficult: I needed some always-connected resource away from web servers and mail servers to host some monitoring tooling and I can’t say no to a deal, even if the deal lends itself to frustration because it turns out that things are cheap for a reason. A dedicated server with an i7-7700K, 64GB of RAM and a load of storage attached for a mere ~£35/month is a deal. And no set-up fee! The planets truly aligned, until I realised that they only had availability in Singapore or Sydney - and only Sydney by the time I was ready to actually commit to a month of the rental.
Plenty of rationalisation later, I’d come to the conclusion that actually a 250-300ms ping time between London and Sydney was fine (after some napkin maths that had initially worked this out to be ~160ms that ignored, you know, that fibre isn’t laid in a straight line and landmasses, ocean topography and sharks changing sub-sea transit routes: I can bend reality to my will when I want to make a decision). Having tried to log into SSH for the first time on the new host, however, I was immediately reminded why I spend a lot of my time at work worrying how close people are to points of presence: it actually sucks to have to wait 0.2 seconds to see that a character I’ve typed is actually recognised on the remote host. Me being a person who will always type ahead, that is probably also going to lead to me issuing a typo command that I will regret for hours following.
Enter mosh: the mobile shell. mosh puts a wrapper around SSH that allows for roaming between networks, intermittent connectivity and (most importantly to me) local echo that will true itself up with what the host actually receives. It gives me a more responsive user experience typing into the shell while providing me an indicator of what has actually been received and processed by the host. That decreased gap between expression of intent through typing and seeing it on the screen is more than enough of a selling point to me.
The second problem here is that I am, for some very important tasks, confined to being logged into Windows and don’t really want to go and find another device or restart to be able to casually log into my new host. mosh doesn’t have a Windows-native port, but is distributed with Cygwin, the “Unix-like” environment and CLI for Windows. I will no doubt be met with cries of “why not use Windows Subsystem for Linux? Then it’d all just be normal tooling”: that’s significantly less fun to me and it’s cheating to just virtualise a whole other OS for the sake of one tool.
The only downside of this approach is that the terminal emulator distributed with Cygwin (MinTTY) is not what my muscle memory is accustomed to in Konsole, Kitty or Windows Terminal. Different mouse behaviour and different keyboard shortcuts is enough to absolutely kill my productivity and MinTTY certainly has that in spades. Fortunately, we can use Windows Terminal to enter the Cygwin environment as well. If we open Windows Terminal, press Ctrl+Shift+P and then enter Open Settings File (JSON). You’ll be presented with the JSON of your settings. You can add a new profile at the profiles key, inside the list object:
{
"commandline": "C:\\cygwin64\\bin\\bash.exe -i -l",
"guid": "{$GENERATED_GUID}",
"hidden": false,
"name": "Cygwin Bash"
}
To generate a GUID here we can use uuidgen from within the Cygwin environment from MinTTY. We start bash with the -i and -l flags as we need bash to be an interactive login shell in order for /etc/profile to be applied and for us to get a $PATH set that includes Cygwin’s bin directories. Otherwise, if we try to run ls, for example, we will see errors along the lines of command not found.
If you save the file, you should see the new Cygwin Bash entry appear in the list of Windows Terminal profiles.
For mosh to work, we need to install - from the Cygwin installer - both mosh and ssh. We have SSH natively on Windows these days, but if there is not an ssh binary in the Cygwin path, we’ll see errors like the below:
CreateProcessW failed error:2
posix_spawnp: No such file or directory
/usr/bin/mosh: Did not find remote IP address (is SSH ProxyCommand disabled?).
With our packages correctly installed, we can run either mosh $USER@$HOST if we’re doing password authentication or mosh --ssh="ssh -i $PATH_TO_SSH_PRIVATE_KEY" $USER@$HOST if we’re using key-based authentication. If your SSH key is somewhere else on the filesystem, you’ll need to give the path with Unix-style path separators prefixed by /cygdrive/$DRIVE_LETTER/.
If we have mosh installed on our server, we should see successful connections occur. We might also need to open UDP ports 60000-61000 on the server if we have an active firewall: we rely on those UDP ports for mosh to be able to establish its communication with the server.
Have I failed to realise that the performance of the web-based tools I’m intending to host in Sydney is also going to be impacted by the latency? Yes, but a good deal is always a good deal and waiting a little longer for a click is a world of difference experientially, for me at least, than waiting for the recognition of keyboard inputs.