Remote Pair Programming With Upterm

Owen Ou
4 min readJul 11, 2020

--

Upterm is an open-sourced solution for sharing terminal sessions instantly over the public internet via SSH tunnels. It is good for

  • Remote pair programming
  • Access remote computers behind NATs and firewalls
  • Remote debugging

Upterm is written in Go and is open-sourced at https://github.com/jingweno/upterm.

How it works

You run the upterm program by hosting a terminal session. Upterm starts an SSH server on your machine and connects to an Upterm server (a.k.a. uptermd) via reverse SSH tunnel. Your friends connect to your terminal session using ssh via the same Upterm server.

Here is a diagram on the technical details:

Demo

Quickstart

Install upterm by following this guide.

On your machine, host a terminal session by specifying a command:

$ upterm host -- bash

upterm will start the command and pop up an ssh connection string that one can connect. In case you miss the connection string, display it with:

$ upterm session current
=== IQKSFOICLSNNXQZTDKOJ
Command: bash
Force Command: n/a
Host: ssh://uptermd.upterm.dev:22
SSH Session: ssh IqKsfoiclsNnxqztDKoj:MTAuMC40OS4xNjY6MjI=@uptermd.upterm.dev

Open a new terminal and connect to the session:

$ ssh IqKsfoiclsNnxqztDKoj:MTAuMC40OS4xNjY6MjI=@uptermd.upterm.dev

You should see the input and output of both terminals are linked!

If you want only authorized clients to connect to your session, you can specify the clients’ authorized keys with:

$ upterm host --authorized-key PATH_TO_PUBLIC_KEY -- bash

If you are looking for a Tmate-like experience, create a Tmux session, and “force” clients to attach to the Tmux session:

$ upterm host --force-command 'tmux attach -t pair-programming' -- tmux new -t pair-programming

The above creates a Tmux session by running tmux new -t pair-programming. After a client connects, Upterm will attach the client's input and output to the input and output of the Tmux session "pair-programming".

If you are concerned with others accessing your root file system, wrap the terminal session in a Docker container:

$ upterm host -- docker run --rm -ti ubuntu bash

I will write another blog post in the future to share how I securely host a terminal session using containers.

How is Upterm compared to prior arts?

Upterm is an alternative to Tmate.

Tmate is a fork of an older version of Tmux. It adds terminal sharing capability on top of Tmux 2.x. Tmate doesn’t intend to catch up with the latest Tmux (at this time of the post, the latest Tmux is 3.x), so any Tmate & Tmux users must maintain two versions of the configuration. For example, you must bind the same keys twice with a condition.

Upterm is designed from the group up not to be a fork of anything. It builds around the concept of linking the input & output of any shell command between a host and its clients. As you see above, you can share any command besides tmux. This opens up a door for securely sharing a terminal session using containers (I will explain more in a future post).

Upterm is written in Go. It is more friendly hackable than Tmate that is written in C because Tmux is C. The Upterm CLI and server ( uptermd) are compiled into a single binary. You can quickly spawn up your pairing server in any cloud environment with zero dependencies.

Tips

Why doesn’t upterm show the current terminal session in Tmux?

upterm session current shows the connection info of the current terminal session. It needs the UPTERM_ADMIN_SOCKET environment variable to function. By default, Tmux doesn't carry over environment variables that are not in its default list to a Tmux session unless you tell it. So add the following line to your~/.tmux.conf:

set-option -ga update-environment " UPTERM_ADMIN_SOCKET"

How to make it obvious that I am in an upterm session?

It can be confusing whether your terminal session is an upterm session or not. As an example, I add an emoji to my prompt to identify an upterm session:

# in your ~/.bashrc or ~/.zshrc 
export PS1="$([[ ! -z "${UPTERM_ADMIN_SOCKET}" ]] && echo -e '\xF0\x9F\x86\x99 ')$PS1" # Add an emoji

This is what it looks like :-):

Deploy Uptermd

Upterm needs an Upterm server (a.k.a. uptermd) to expose terminal sessions securely. There is a community server running at uptermd.upterm.dev for your convenience (please put it into good use!). However, if you want to host your pairing server on Kubernetes or Heroku, follow this deployment guide. You are welcome to contribute one for your favorite cloud platforms. I am pleased to review it if you shoot me a PR :-).

To talk to a different uptermd server other than the community server, you specify with the --server flag:

# Use your Uptermd server via SSH on TCP
$ upterm host --server ssh://YOUR_SERVER -- YOUR_COMMAND

# Use your Uptermd server via SSH on WebSocket
$ upterm host --server wss://YOUR_SERVER -- YOUR_COMMAND

# Client connects to the host session via SSH on WebSocket
$ ssh -o ProxyCommand='upterm proxy wss://TOKEN@YOUR_SERVER' TOKEN@YOUR_SERVER:443

Conclusion

I am super excited about upterm, and I dogfood it daily to pair program with my coworkers (Disclaimer: I work remotely for Heroku). If you like what you see here, give upterm a shot. I am looking forward to your valuable feedback and contributions: https://github.com/jingweno/upterm/issues :-).

Originally published at https://owenou.com on July 11, 2020.

--

--