Mosh with iTerm2’s Tmux Integration

I have found terminal/shell nirvana on my Mac with mosh + tmux + iTerm2 Tmux Integration, but it wasn’t easy.

My dream setup was these 3 running together:

1) mosh: Runs on client and on server. An ssh replacement that is secured with AES-128 and ssh. Virtually indestructible ssh-like sessions that remain “live” even after you change IP addresses (ie. physical locations), VPNs, or network interfaces. I can login to a server and never need to re-login for *months*. Whenever I open my macbook, my shell sessions are exactly where they were before and ready for the next command.  If your IP address changes while you commute (eg. train) or you are on VPN a lot, you really should use mosh instead of ssh. It’s not just for unreliable connections, I use mosh everywhere because it saves me time.

2) tmux: Runs on the server. Replacement for the old ‘screen’ utility. It allows you to keep active windows (and panes) in a session that remains alive even after you disconnect from the remote server.

3) iTerm2’s Tmux Integration: Runs on Mac. Very cool iTerm2 feature that renders your tmux windows as native iTerm2 tabs. Allows you to scroll back through your tmux window with Macbook touchpad gestures and iTerm hotkeys. Supports iTerm2’s very quick & capable Cmd-F (Find) instead of tmux’s Find.  Supports intuitive text selection and advanced text selection (discontiguous select & copy) built into iTerm. Switching between tabs with keyboard shortcuts. Basically everything you can do in iTerm2 regular tabs, you can probably do with your tmux session rendered by iTerm2’s Tmux Integration. It rocks.

 

The Problem

The problem is iTerm’s Tmux integration works fine when using ssh, but not when using mosh.

 

The Solution

With this howto, you can build a patched version of mosh (client and server) that is compatible with iTerm’s Tmux Integration.  Mosh is a small program, so the build is very quick.

Moreover, this howto allows you to try the patched mosh binaries without touching your existing mosh installation. This is done by specifying the ‘–client’ and ‘–server’ options when running mosh.

Once you are happy with how the patched mosh is working, you can move the patched mosh to a location in your path (need to do this on both client and server).

Note, if you are on wifi all the time, you can use Eternal Terminal instead of this howto. I use hard-wired ethernet at my desk and wifi when I leave my desk (eg. walking to a meeting). It so happens, this switching of network interfaces seems to break Eternal Terminal and close my session (in my testing).

In my setup I have a macbook (mosh client) connecting to an ubuntu 16.04 server (mosh server).

First, we’ll build mosh on the Macbook (mosh-client).

 

Build patched mosh-client on Macbook

Create a directory for the code:

dlee-mbp:~ donn$ mkdir -pv ~/workspace/git/github.com/rledisez/

dlee-mbp:~ donn$ cd ~/workspace/git/github.com/rledisez/

Grab the code:

dlee-mbp:rledisez donn$ git clone https://github.com/rledisez/mosh.git

dlee-mbp:rledisez donn$ cd mosh

Checkout the patched mosh branch called “localScrollback-1.3.2”:

dlee-mbp:mosh donn$ git checkout -b localScrollback-1.3.2 origin/localScrollback-1.3.2

 

Use Homebrew to install dependencies:

dlee-mbp:mosh donn$ brew install protobuf automake pkg-config

 

Build patched mosh binaries:

dlee-mbp:mosh donn$ ./autogen.sh

configure.ac:21: installing ‘./ar-lib’

configure.ac:13: installing ‘./compile’

configure.ac:6: installing ‘./install-sh’

configure.ac:6: installing ‘./missing’

src/crypto/Makefile.am: installing ‘./depcomp’

parallel-tests: installing ‘./test-driver’

 

./configure

<See many lines of output>

 

make

<See many lines of output>

 

You don’t have to do ‘make install’ at this point. You can try the binary without installing it (see below).

 

But, we also need a patched mosh on the server, so next…

 

Build mosh on ubuntu server

Install debian package dependencies:

Note: Boost (libboost-dev) not needed for mosh 1.2+ so I didn’t install it.

sudo apt-get install automake libtool g++ protobuf-compiler libprotobuf-dev libutempter-dev libncurses5-dev zlib1g-dev libio-pty-perl libssl-dev pkg-config

Build mosh-client and mosh-server:

git clone https://github.com/rledisez/mosh.git

cd mosh

git checkout -b localScrollback-1.3.2 origin/localScrollback-1.3.2

./autogen.sh

./configure

make

 

Again, you don’t have to ‘make install’ if you just want to try things out.

 

Running the patched mosh

Locate the path to patched mosh-client on my Macbook:

/Users/donn/workspace/git/github.com/rledisez/mosh/src/frontend/mosh-client

Locate the path to patched mosh-server on my ubuntu server:

/home/donn/workspace/github.com/rledisez/mosh/src/frontend/mosh-server

 

With this info, I can try my first iTerm + tmux + mosh session:

The ‘mosh’ command is found in the ‘scripts’ subdirectory of the source code directory.

 

dlee-mbp:mosh donn$ scripts/mosh \
--client=/Users/donn/workspace/git/github.com/rledisez/mosh/src/frontend/mosh-client \
--server=/home/donn/workspace/github.com/rledisez/mosh/src/frontend/mosh-server 10.1.1.1

 

After logging in to 10.1.1.1, start tmux on remote host:

remote_host$ tmux -CC

[or ‘tmux -CC a’ if resuming an existing tmux session]

 

… and then see iTerm2 window with Tmux Integration enabled.  Cmd-T to open a new tab.

Enjoy!

 

Switching to patched mosh permanently

 

Mac: Just put mosh and mosh-client in your path.  To see your installed version of mosh:

$ which mosh

$ which mosh-client

 

To see your path:

$ echo $PATH

 

Maybe copy your originals as mosh.orig, mosh-client.orig

 

Ubuntu server: Same thing but with mosh-server.  Maybe save your original as mosh-server.orig

 

From this point forward, be aware that normal, standard mosh clients will not be compatible with patched mosh on the server.  If you want to support both, then use the ‘–server’ option when starting a mosh session to specify which version of mosh-server will be run on the server (eg. mosh-server or mosh-server.orig).

 

Fixing Problems

 

If your session dies abruptly with an error like the following, it means your mosh-client or your mosh-server is not running the patched version of mosh; it is probably running your normal, installed version of mosh.

 

Assertion failed: (*i == *my_it), function diff_from, file user.cc, line 69.

Abort trap: 6

 

Resources

 

iTerm2’s Tmux Integration:

https://gitlab.com/gnachman/iterm2/wikis/TmuxIntegration

 

Build instructions for mosh:

https://github.com/mobile-shell/mosh/wiki/Build-Instructions

 

Patched mosh that supports tmux control-mode (tmux -CC). Original patch by github user 4ast. Rebased on mosh 1.3.2 by rledisez:

https://github.com/rledisez/mosh/tree/localScrollback-1.3.2

At the time of this article, v1.3.2 was the latest stable version for download at mosh.org

 

Original patched mosh:

https://github.com/4ast/mosh

Note: Commit d5bd1d31d86d4003705e69f87466aa7e10f9c5b9 “add support for resize events” is already part of mosh mainline.

 

“tmux integration hangs when logged in with mosh (ok w/ ssh)”

https://gitlab.com/gnachman/iterm2/issues/5924

 

Homebrew package manager for Mac:

https://brew.sh/

Bounty ($$$) for adding tmux control-mode support to mosh:

https://www.bountysource.com/issues/2052677-mosh-prevents-the-use-of-scrollback