Comparte tu terminal usando tu propio servidor de tmate

  • Guías
  • Descentralización
  • tmate es una herramienta que permite compartir nuestra terminal con otros usuarios de forma segura y a través de redes con múltiples configuraciones.

    Motivación #

    ¿Has tenido alguna vez la necesidad de compartir en tiempo real lo que estás haciendo en tu terminal con otras personas que están en otros lugares? Podría ser útil, por ejemplo, para ayudarte con la gestión de máquinas remotas. O incluso, con las herramientas adecuadas, hacer desarrollo de software de forma grupal.

    Pero, ¿para qué me querría complicar con esto, si puedo establecer una simple sesión ssh con una máquina remota?

    En una sesión normal de ssh, un usuario se conecta a través de una terminal a otra máquina (conectada a través de una red local o de internet) de modo que puede introducir comandos y gestionarla de forma remota. Pero no puede compartir lo que está haciendo con otros usuarios, a no ser que estén físicamente juntos. Con tmate todos ellos verán el mismo contenido en todo momento, lo cual es útil para realizar pair programming o programación en pareja. Aunque en este caso sería más acertado hablar de mob programming, ya que el efecto sería el mismo que si varios usuarios compartieran un solo ordenador con una sola pantalla, pero cada uno con su teclado.

    El proyecto de software libre tmate surge de esta necesidad. Está construído sobre el código base de tmux, que es un multiplexador de terminal, es decir, permite la ejecución de múltiples shells (y por tanto, múltples aplicaciones en primer plano) que pueden ser organizadas dividiendo la terminal tanto en ventanas como en paneles. Por tanto, tmate hereda estas caracterísiticas de tmux, y añade las suyas propias.

    Además de todo esto, tmate es útil en la medida en la que puede viajar a través de NATs y tolerar posibles cambios de IP del cliente que comparte la sesión, ya que todo pasa a través del servidor externo, ya sea el oficial de tmate.io o el nuestro propio, actuando como proxy. Por ejemplo, podríamos conectarnos desde el exterior a un ordenador en nuestro domicilio, que normalmente estará detrás de una NAT, sin necesidad de abrir puertos en el router, simplemente ejecutando el cliente de tmate, creando una sesión y guardándonosla para conectarnos desde el exterior.

    Para mantener la coherencia a lo largo del artículo, vamos a identificar tres tipos de actores diferentes:

    • Servidor: ejecutará la parte servidor de tmate. Es el que mantiene las sesiones, y actúa simplemente como proxy, es decir, como máquina por la que transcurre el tráfico, pero nada más.
    • Cliente: ejecutará la parte cliente de tmate. Esta es la máquina cuyo acceso se compartirá con los demás usuarios a través del servidor.
    • Usuarios: son los que se conectarán a la máquina cliente a través del servidor. No necesitan tener instalado tmate, solamente necesitarán conectarse mediante ssh a la sesión que mantiene el servidor, utilizando un comando que generará el cliente y que éste deberá comunicarles.

    Configuración del cliente con el servidor por defecto de los creadores de tmate #

    Para empezar, vamos a ver cómo funciona el cliente de tmate con la configuración básica por defecto. Descargamos e instalamos el cliente desde el repositorio de paquetes de nuestra distribución de Linux, en este caso Ubuntu o cualquier otra basada en Debian:

    sudo apt install tmate
    

    También está disponible en los repositorios de otras distribuciones, como Fedora, openSUSE, Gentoo o Arch. Incluso podemos descargar el ejecutable estático precompilado.

    Una vez instalado, lo ejecutamos sin más:

    tmate
    

    Con la configuración por defecto, nos abrirá una conexión con un servidor remoto que mantienen los creadores de tmate, en la máquina ssh.tmate.io. Si todo va bien, lo que veremos en la pantalla del terminal serán dos comandos ssh, similares a este:

    ssh 9BzGRYrfvy5Zp9j3YwJ22Xg66@lon1.tmate.io
    

    Uno será para solo lectura (solo podrá teclear el que comparte la sesión), y otro para lectura y escritura. Estos comandos son lo que permitirá a los usuarios conectarse a la sesión generada por el cliente. Puede que adicionalmente, y dependiendo de la configuración del servidor, veamos dos direcciones http, con las cuales podremos también acceder al terminal compartido, pero a través del navegador, lo cual puede ser útil si alguno de los usuarios no tuviera la posibilidad de acceder a una terminal.

    Es decir, los usuarios no necesitan instalar el cliente de tmate, ni crear ni establecer claves ssh ni llevar a cabo ninguna configuración adicional. Únicamente será necesario tener un cliente ssh, algo que actualmente es ubicuo. Ni siquiera eso si optan por conectarse a través de la web.

    En todo momento podemos recuperar el comando de conexión ejecutando tmate show-messages para pasárselo a un nuevo usuario.

    Configuración de nuestro propio servidor #

    Hay que tener en cuenta que tmate es un proyecto de software libre, y el servidor principal es un servicio gratuito y desinteresado. Veremos además que, por diseño, no es posible sacar ningún tipo de información ni de rédito por mantenerlo. Por tanto, la gente que lo mantiene no tiene ninguna obligación de hacerlo. En un momento dado, el servidor puede fallar o dejar de estar disponible. Existen otros servidores a los cuales podríamos conectarnos (especificándolo en el archivo ~/.tmate.conf, como veremos más adelante), pero si somos usuarios habituales, lo ideal es tener nuestro propio servidor.

    Tener nuestro propio servidor ayuda a no sobrecargar los servidores de los creadores, y nos da mayor seguridad y control si lo configuramos correctamente. Este será el objetivo de esta sección.

    Requisitos previos para instalar el servidor #

    Partimos de un VPS, con una Debian 10 (Buster) recién instalada. Tendremos también instalado Docker (20.10.5). En este caso, y dado que no necesitamos ninguna característica especial, es muy probable que todo funcione correctamente con versiones bastante más antiguas (y más nuevas) de ambos, así como con otras muchas distribuciones de Linux. El dominio ficticio que apunta a nuestro VPS, para fines ilustrativos, será mi.servidor.com.

    La versión de cliente de tmate que usaremos será la v2.4.0, y la de servidor será la v2.3.0, que son las más recientes en el momento de escribir este artículo. Con lo que sí hay que tener cuidado es con no usar versiones demasiado alejadas de cliente y servidor, ya que puede haber incompatibilidades entre ellas.

    Generación de claves #

    Necesitamos generar dos claves asimétricas, una de tipo RSA y otra de tipo ed25519.

    Primero generamos la clave RSA y su fingerprint:

    ssh-keygen -t rsa -f ~/.ssh/tmate/ssh_host_rsa_key -N ''
    ssh-keygen -l -E sha256 -f ~/.ssh/tmate/ssh_host_rsa_key.pub
    

    Lo mismo con la clave ed25519:

    ssh-keygen -t ed25519 -f ~/.ssh/tmate/ssh_host_ed25519_key -N ''
    ssh-keygen -l -E sha256 -f ~/.ssh/tmate/ssh_host_ed25519_key.pub
    

    Necesitaremos la ruta donde hemos almacenado estas claves para configurar el servidor, y los fingerprints para configurar el cliente.

    Levantar el servidor #

    Aquí podemos optar por dos aproximaciones. La primera de ellas será descargar el repositorio, compilar la aplicación servidor y ejecutarlo directamente. La otra consiste en usar una imagen de Docker. Esto último es lo más recomendable, ya que así nos dará igual cuál sea el sistema de la máquina host, y además la mantendremos más limpia.

    Opción 1: compilar y ejecutar el servidor #

    Necesitaremos, antes de nada, instalar algunos paquetes:

    sudo apt install git-core automake build-essential pkg-config libtool \
      libmsgpack-dev libevent-dev libncurses-dev libssh-dev
    

    Clonamos el repositorio:

    git clone https://github.com/tmate-io/tmate-ssh-server.git
    cd tmate-ssh-server
    

    Compliamos el servidor:

    ./autogen.sh && ./configure && make
    

    Ya estamos listos. Ahora arrancamos el servidor, especificando un puerto, nuestro hostname y el directorio donde tenemos las claves que generamos anteriormente:

    sudo ./tmate-ssh-server -p 2200 -h mi.servidor.com -k ~/.ssh/tmate
    

    Es necesario arrancar este servidor como root, así como evitar el puerto 22, ya que normalmente será por el que estaremos accediendo a la máquina para su gestión.

    Opción 2: usar un contenedor de Docker #

    Podemos encontrar en Dockerhub una imagen ya creada con el servidor de tmate y sus dependencias, basada en Alpine. También podemos generarla nosotros mismos mediante el Dockerfile que viene en el repositorio de tmate.

    docker pull tmate/tmate-ssh-server
    
    docker run \
      --cap-add SYS_ADMIN \
      --name tmate-server \
      -e SSH_KEYS_PATH='/keys' \
      -e SSH_HOSTNAME='mi.servidor.com' \
      -p 2200:2200 \
      -v ~/.ssh/tmate:/keys \
      -d \
      tmate/tmate-ssh-server
    

    Nótese que el contenedor necesita ser ejecutado con un permiso especial.

    Podemos hacer exactamente lo mismo con docker-compose. En primer lugar creamos un fichero docker-compose.yml y añadimos el código que aparece a continuación.

    services:
      tmate:
        image: tmate/tmate-ssh-server
        restart: always
        cap_add:
          - SYS_ADMIN
        ports:
          - 2200:2200
        volumes:
          - ~/.ssh/tmate:/keys
        environment:
          - SSH_KEYS_PATH=/keys
          - SSH_HOSTNAME=mi.servidor.com
    

    Para levantar el servicio, usamos el siguiente comando en el mismo directorio donde hayamos creado el fichero anterior.

    docker-compose up -d
    

    Ver sesiones abiertas #

    Para ver cuántas instancias de tmate tenemos abiertas en el servidor, ejecutamos en el servidor:

    top
    

    Si estamos usando un contenedor de Docker, tendremos que ejecutar el comando dentro del mismo:

    docker exec -it tmate-server top
    

    Veremos algo similar a esto:

    PID PPID USER    STAT VSZ   %VSZ CPU %CPU COMMAND
      1    0 root    S    5216    0%   0   0% tmate-ssh-server -p 2200 -q 2200 -k /keys -h mi.servidor.com
     23    1 nobody  SN   5708    0%   0   0% tmate-ssh-server [EXAT...] (daemon) 21.123.234.123
     16    1 nobody  SN   5708    0%   0   0% tmate-ssh-server [Xb6H...] (daemon) 12.213.243.231
    

    En este caso, veríamos el proceso princial (con el PID 1) y los otros dos serían dos conexiones abiertas por dos clientes diferentes, que podemos identificar tanto por la IP como por los primeros caracteres del comando de conexión.

    Configuración del cliente con nuestro propio servidor #

    Ahora vamos a configurar nuestro cliente, desde el cual nos conectaremos al servidor de tmate. La máquina cliente que lo ejecute será la que genere un enlace, el cual podremos pasar a otros usuarios para que se conecten y poder así compartir la sesión.

    Como ya tenemos instalado el cliente de tmate, abrimos o creamos un archivo ~/.tmate.conf en nuestro directorio personal y agregamos algunos parámetros de configuración, como el hostname y el puerto donde dejamos ejecutando el servidor, y los fingerprints que generamos al principio:

    set -g tmate-server-host mi.servidor.com
    set -g tmate-server-port 2200
    set -g tmate-server-rsa-fingerprint SHA256:aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTvVw
    set -g tmate-server-ed25519-fingerprint SHA256:wWxXyYzZ+AaBbCcDdEeFfGgHhIiJjKkLlMnOoPpQqRr
    

    Ya solo nos queda ejecutar tmate. Al hacerlo, nos aparecerá una pantalla con un par de comandos ssh. Uno de ellos será de solo lectura, y otro de lectura y escritura. Serán similares a esto:

    ssh -p 2200 bjUSAWzjq6JdghNAuTwpqPFrm@mi.servidor.com
    

    Esto se lo pasamos al usuario que queramos que entre a nuestra máquina, con el que compartiremos la sesión. Hemos de ser cuidadosos y no publicar esto en cualquier parte, ya que si alguien se hiciera con este comando y la sesión estuviera abierta, podría acceder a nuestra máquina con todos los privilegios que tenga la sesión abierta en ese momento.

    Al finalizar el trabajo, y si no queremos que nadie más pueda conectarse a nuestra máquina, es necesario cerrar la sesión de tmate usando el comando exit. De lo contrario, y si nos limitamos a cerrar la ventana que contiene el terminal, dejaremos activa la sesión en segundo plano, de modo que si nuestra máquina se queda encendida y alguien conserva el comando, puede volver a acceder en cualquier momento, en el estado en el que estuviera la sesión.

    Personalizar el cliente #

    Como tmate está basado en tmux, podremos personalizar nuestro tmate igual que lo haríamos con tmux. Ambos comparten la misma sintaxis, e incluso podemos hacer que compartan la misma configuración. El archivo de configuración de tmux es ~/.tmux.conf, con lo que podemos añadir lo siguiente en nuestro ~/.tmate.conf:

    source-file ~/.tmux.conf
    

    Y así tmate heredará la configuración de tmux.

    La forma más raṕida de interactuar con tmate/tmux es mediante atajos de teclado. Los atajos de teclado por defecto se pueden consultar en esta cheatsheet. Deben ir precedidos de un prefijo, que por defecto será ctrl+b, o, en la jerga de tmux, C-b.

    Pero estos comandos los podemos cambiar, y podemos hacer este cambio permanente. Para eso necesitamos reasignar o bindear los atajos a diversos comandos en el archivo de configuración. Podemos ver varios ejemplos de esto en la guía de tmux.

    También podemos configurar la barra inferior a nuestro gusto, tanto a nivel visual como de funcionalidad. Tenemos una serie de variables disponibles para mostrar cosas como el hostname, o los diferentes indicadores de panel o ventana, aunque también podemos mostrar el resultado de la ejecución de cualquier comando de sistema (por ejemplo, podríamos mostrar la fecha y la hora del sistema, o nuestra dirección IP, o cualquier otra cosa que se nos ocurra). Hay muchos desarrolladores que publican sus archivos .tmux.conf como parte de sus dotfiles. Si hacemos una búsqueda podremos encontrar muchos de ellos. Incluso existen plugins, y un gestor de plugins llamado tpm para tmux.