One place for hosting & domains

      aplicaciones

      Cómo acceder remotamente a aplicaciones GUI usando Docker y Caddy en Ubuntu 18.04


      El autor seleccionó la Free and Open Source Fund para recibir una donación como parte del programa Write for DOnations.

      Introducción

      Aún con la creciente popularidad de los servicios en la nube, la necesidad de ejecutar aplicaciones nativas sigue existiendo.

      Con noVNC y TigerVNC, puede ejecutar aplicaciones nativas dentro de un contenedor Docker y acceder a ellas remotamente usando un navegador web. Adicionalmente, puede ejecutar su aplicación en un servidor con más recursos del sistema de los que pueda tener disponibles localmente, lo que puede proporcionar mayor flexibilidad cuando se ejecutan grandes aplicaciones.

      En este tutorial, pondrá en un contendor Mozilla Thunderbird, un cliente de correo electrónico, usando Docker. Tras ello, lo protegerá y proporcionará acceso remoto usando el servidor web Caddy.

      Cuando haya terminado, podrá acceder a Thunderbird desde cualquier dispositivo usando únicamente un navegador web. Opcionalmente, podrá acceder localmente a los archivos usando WebDAV. También tendrá una imagen Docker completamente autocontenida que puede ejecutar en cualquier lugar.

      Requisitos previos

      Antes de iniciar esta guía, necesitará lo siguiente:

      Paso 1: Crear la configuración supervisord

      Ahora que su servidor está ejecutándose y Docker está instalado, está listo para comenzar a configurar el contenedor de su aplicación. Ya que su contenedor consta de varios componentes, deberá usar un administrador de procesos para iniciarlos y monitorizarlos. Aquí usará supervisord. supervisord es un gestor de procesos escrito en Python que se utiliza a menudo para organizar contenedores complejos.

      Primero, cree y entre en un directorio llamado thunderbird para su contenedor.

      • mkdir ~/thunderbird
      • cd ~/thunderbird

      Ahora cree y abra un archivo llamado supervisord.conf usando nano o su editor preferido:

      Ahora añada este primer bloque de código en supervisord.conf, lo que definirá las opciones globales para supervisord:

      ~/thunderbird/supervisord.conf

      [supervisord]
      nodaemon=true
      pidfile=/tmp/supervisord.pid
      logfile=/dev/fd/1
      logfile_maxbytes=0
      

      En este bloque, está configurando supervisord. Deberá establecer nodaemon a true porque se ejecutará dentro de un contenedor Docker como el punto de entrada. Por tanto, querrá que permanezca en ejecución en primer plano. También configura pidfile a una ruta accesible por un usuario non-root (más sobre esto más tarde), y logfile to stdout para que pueda ver los registros.

      A continuación, añada otro bloque de código pequeño a supervisord.conf. Este bloque inicia TigerVNC que es un servidor VNC/X11 combinado:

      ~/thunderbird/supervisord.conf

      ...
      [program:x11]
      priority=0
      command=/usr/bin/Xtigervnc -desktop "Thunderbird" -localhost -rfbport 5900 -SecurityTypes None -AlwaysShared -AcceptKeyEvents -AcceptPointerEvents -AcceptSetDesktopSize -SendCutText -AcceptCutText :0
      autorestart=true
      stdout_logfile=/dev/fd/1
      stdout_logfile_maxbytes=0
      redirect_stderr=true
      

      En este bloque, está configurando el servidor X11. X11 es un protocolo de servidor de visualización, que es lo que permite que se ejecuten las aplicaciones GUI. Tenga en cuenta que en el futuro se sustituirá con Wayland, pero el acceso remoto aún está en desarrollo.

      Para este contenedor, está usando TigerVNC y está integrado en el servidor VNC. Esto tiene varias ventajas sobre el uso de un servidor X11 y VNC:

      • Tiempo de respuesta más rápido, ya que el dibujo de la GUI se realiza directamente en el servidor VNC en vez de hacerse en un framebuffer intermedio (la memoria que almacena los contenidos de la pantalla).
      • Cambio de tamaño automático de la pantalla, que permite a la aplicación remota cambiar de tamaño automáticamente para que se ajuste al cliente (en este caso, la ventana de su navegador web).

      Si lo desea, puede cambiar el argumento para la opción -desktop desde Thunderbird a otra cosa que elija. El servidor mostrará su opción como el título de la página web usada para acceder a su aplicación.

      Ahora, vamos a añadir un tercer bloque de código a supervisord.conf para iniciar easy-novnc:

      ~/thunderbird/supervisord.conf

      ...
      [program:easy-novnc]
      priority=0
      command=/usr/local/bin/easy-novnc --addr :8080 --host localhost --port 5900 --no-url-password --novnc-params "resize=remote"
      autorestart=true
      stdout_logfile=/dev/fd/1
      stdout_logfile_maxbytes=0
      redirect_stderr=true
      

      En este bloque, está configurando easy-novnc, un servidor independiente que ofrece un envoltorio alrededor de noVNC. Este servidor realiza dos funciones. Primero, proporciona una página sencilla de conexión que le permite configurar opciones para la conexión, y le permite establecer las predeterminadas. Segundo, realiza proxy a VNC sobre WebSocket, lo que permite el acceso a través de un navegador web ordinario.

      Normalmente, el cambio de tamaño se realiza en el lado del cliente (es decir, escala de imagen), pero está usando la opción resize=remote para aprovechar los ajustes de resolución remota de TigerVNC. Esto también proporciona una menor latencia en dispositivos más lentos, como Chromebooks de gama baja:

      Nota: Este tutorial utiliza easy-novnc. Si lo desea, puede usar websockfy y un servidor web independiente. La ventaja de easy-novnc es que el uso de memoria y el tiempo de inicio es significativamente menor que si fuese auto-contenido. easy-novnc también proporciona una página conexión más limpia que la de noVNC predeterminado, y permite establecer opciones predeterminadas que son útiles para esta configuración (como resize=remote).

      Ahora añada el siguiente bloque a su configuración para iniciar OpenBox, el gestor de ventanas:

      ~/thunderbird/supervisord.conf

      ...
      [program:openbox]
      priority=1
      command=/usr/bin/openbox
      environment=DISPLAY=:0
      autorestart=true
      stdout_logfile=/dev/fd/1
      stdout_logfile_maxbytes=0
      redirect_stderr=true
      

      En este bloque, está configurando OpenBox, un gestor de ventanas X11 ligero. Podría omitir este paso, pero sin él no tendría las barras de título o podría cambiar el tamaño de las ventanas.

      Finalmente, vamos a añadir el último bloque a supervisord.conf, que iniciará la aplicación principal:

      ~/thunderbird/supervisord.conf

      ...
      [program:app]
      priority=1
      environment=DISPLAY=:0
      command=/usr/bin/thunderbird
      autorestart=true
      stdout_logfile=/dev/fd/1
      stdout_logfile_maxbytes=0
      redirect_stderr=true
      

      En este bloque final, está configurando priority a 1 para garantizar que Thunderbird se inicia tras TigerVNC, o encontrará una condición de carrera o fallaría aleatoriamente al inicio. También configuramos autorestart=true para que vuelva a abrir automáticamente la aplicación si se cierra por error. La variable de entorno DISPLAY indica a la aplicación que se muestre en el servidor VNC que configuró anteriormente.

      Este es el aspecto que tendrá su supervisord.conf completado:

      ~/thunderbird/supervisord.conf

      [supervisord]
      nodaemon=true
      pidfile=/tmp/supervisord.pid
      logfile=/dev/fd/1
      logfile_maxbytes=0
      
      [program:x11]
      priority=0
      command=/usr/bin/Xtigervnc -desktop "Thunderbird" -localhost -rfbport 5900 -SecurityTypes None -AlwaysShared -AcceptKeyEvents -AcceptPointerEvents -AcceptSetDesktopSize -SendCutText -AcceptCutText :0
      autorestart=true
      stdout_logfile=/dev/fd/1
      stdout_logfile_maxbytes=0
      redirect_stderr=true
      
      [program:easy-novnc]
      priority=0
      command=/usr/local/bin/easy-novnc --addr :8080 --host localhost --port 5900 --no-url-password --novnc-params "resize=remote"
      autorestart=true
      stdout_logfile=/dev/fd/1
      stdout_logfile_maxbytes=0
      redirect_stderr=true
      
      [program:openbox]
      priority=1
      command=/usr/bin/openbox
      environment=DISPLAY=:0
      autorestart=true
      stdout_logfile=/dev/fd/1
      stdout_logfile_maxbytes=0
      redirect_stderr=true
      
      [program:app]
      priority=1
      environment=DISPLAY=:0
      command=/usr/bin/thunderbird
      autorestart=true
      stdout_logfile=/dev/fd/1
      stdout_logfile_maxbytes=0
      redirect_stderr=true
      

      Si desea poner una aplicación diferente en contenedor, sustituya /usr/bin/thunderbird con la ruta al ejecutable de su aplicación. De lo contrario, estará listo para configurar el menú principal de su GUI.

      Paso 2: Configurar el menú de OpenBox

      Ahora que su gestor de procesos está configurado, vamos a configurar el menú de OpenBox. Este menú nos permite abrir aplicaciones dentro del contenedor. También incluiremos un monitor de terminal y procesos para depurar si es necesario.

      Dentro del directorio de la aplicación, utilice nano o su editor de texto favorito para crear y abrir un nuevo archivo llamado menu.xml:

      • nano ~/thunderbird/menu.xml

      Ahora añada el siguiente código a menu.xml:

      ~/thunderbird/menu.xml

      <?xml version="1.0" encoding="utf-8"?>
      <openbox_menu xmlns="http://openbox.org/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://openbox.org/ file:///usr/share/openbox/menu.xsd">
          <menu id="root-menu" label="Openbox 3">
              <item label="Thunderbird">
                  <action name="Execute">
                      <execute>/usr/bin/thunderbird</execute>
                  </action>
              </item>
              <item label="Terminal">
                  <action name="Execute">
                      <execute>/usr/bin/x-terminal-emulator</execute>
                  </action>
              </item>
              <item label="Htop">
                  <action name="Execute">
                      <execute>/usr/bin/x-terminal-emulator -e htop</execute>
                  </action>
              </item>
          </menu>
      </openbox_menu>
      

      Este archivo XML contiene los elementos del menú que aparecerán cuando haga clic con el botón derecho sobre el escritorio. Cada elemento consta de una etiqueta y una acción.

      Si desea añadir al contenedor una aplicación diferente, sustituya /usr/bin/thunderbird con la ruta al ejecutable de su aplicación y cambie la etiqueta del elemento.

      Paso 3: Crear el Dockerfile

      Ahora que OpenBox está configurado, creará el Dockerfile, que une todo.

      Crear un Dockerfile en el directorio de su contenedor:

      • nano ~/thunderbird/Dockerfile

      Para comenzar, vamos a añadir algún código para crear easy-novnc:

      ~/thunderbird/Dockerfile

      FROM golang:1.14-buster AS easy-novnc-build
      WORKDIR /src
      RUN go mod init build && 
          go get github.com/geek1011/easy-novnc@v1.1.0 && 
          go build -o /bin/easy-novnc github.com/geek1011/easy-novnc
      

      En la primera etapa, está creando easy-novnc. Esto se hace en una etapa independiente para mayor simplificada y para ahorrar espacio; no necesita toda la cadena de herramientas de go en su imagen final. Observe @v1.1.0 en el comando de compilación. Esto garantiza que el resultado sea determinista, lo cual es importante porque Docker captura el resultado de cada paso. Si no hubiese especificado una versión explícita, Docker haría referencia a la versión más reciente de easy-novnc en el momento en que se compiló la imagen por primera vez. Además, desea garantizar que descarga una versión específica de easy-novnc, en el caso de que se realicen cambios de ruptura en la interfaz CLI.“”“”

      Ahora vamos a crear la segunda etapa que será la imagen final. Aquí usará Debian 10 (buster) como imagen base. Observe que dado que se está ejecutando en un contenedor, funcionará independientemente de la distribución que esté ejecutando en su servidor.

      A continuación, añada el siguiente bloque a su Dockerfile:

      ~/thunderbird/Dockerfile

      ...
      FROM debian:buster
      RUN apt-get update -y && 
          apt-get install -y --no-install-recommends openbox tigervnc-standalone-server supervisor gosu && 
          rm -rf /var/lib/apt/lists && 
          mkdir -p /usr/share/desktop-directories
      

      En esta instrucción, está instalando Debian 10 como su imagen base y luego instalando el mínimo necesario para ejecutar aplicaciones GUI en su contenedor. Observe que ejecuta apt-get update como parte de la misma instrucción para evitar problemas de captura desde Docker. Para ahorrar espacio, también está eliminando las listas de paquetes descargadas posteriormente (los paquetes en caché en sí mismos se eliminan por defecto). Está creando /usr/share/desktop-directories porque algunas aplicaciones dependen de que exista el directorio.

      Vamos a añadir otro bloque de código pequeño:

      ~/thunderbird/Dockerfile

      ...
      RUN apt-get update -y && 
          apt-get install -y --no-install-recommends lxterminal nano wget openssh-client rsync ca-certificates xdg-utils htop tar xzip gzip bzip2 zip unzip && 
          rm -rf /var/lib/apt/lists
      

      En esta instrucción, está instalando algunas utilidades y paquetes útiles de uso general. Son interesantes xdg-utils (que proporciona los comandos base usados por las aplicaciones de escritorio en Linux) y ca-certificates (que instala los certificados raíz para permitirnos acceder a los sitios HTTPS).

      Ahora, podemos añadir las instrucciones para la aplicación principal:

      ~/thunderbird/Dockerfile

      ...
      RUN apt-get update -y && 
          apt-get install -y --no-install-recommends thunderbird && 
          rm -rf /var/lib/apt/lists
      

      Como antes, aquí estamos instalando la aplicación. Si añade una aplicación diferente al contenedor, puede sustituir estos comandos con los necesarios para instalar su aplicación específica. Algunas aplicaciones requerirán un poco más de trabajo para ejecutarse dentro de Docker. Por ejemplo, si está instalando una aplicación que utiliza Chrome, Chromium o QtWebEngine, deberá usar el argumento de línea de comando --no-sandbox porque no será compatible en Docker.

      A continuación, vamos a comenzar añadiendo las instrucciones para añadir las últimas líneas al contenedor:

      ~/thunderbird/Dockerfile

      ...
      COPY --from=easy-novnc-build /bin/easy-novnc /usr/local/bin/
      COPY menu.xml /etc/xdg/openbox/
      COPY supervisord.conf /etc/
      EXPOSE 8080
      

      Aquí está añadiendo los archivos de configuración que creó anteriormente a la imagen y copiando el binario easy-novnc de la primera etapa.

      Este siguiente bloque de código crea el directorio de datos y añade un usuario dedicado para su aplicación. Esto es importante porque algunas aplicaciones no se ejecutan como root. También es una buena práctica no ejecutar aplicaciones como root, incluso en un contenedor.

      ~/thunderbird/Dockerfile

      ...
      RUN groupadd --gid 1000 app && 
          useradd --home-dir /data --shell /bin/bash --uid 1000 --gid 1000 app && 
          mkdir -p /data
      VOLUME /data
      

      Para garantizar un UID/GID consistente para los archivos, está estableciendo explícitamente ambos a 1000. También está montando un volumen sobre el directorio de datos para garantizar que persiste entre los reinicios.

      Finalmente, vamos a añadir las instrucciones para iniciar todo:

      ~/thunderbird/Dockerfile

      ...
      CMD ["sh", "-c", "chown app:app /data /dev/stdout && exec gosu app supervisord"]
      

      Al establecer el comando predeterminado a supervisord, el administrador iniciará los procesos requeridos para ejecutar su aplicación. En este caso, está usando CMD en vez de ENTRYPOINT. En la mayoría de los casos, no supondría una diferencia, pero usar CMD es mejor para este fin por algunos motivos. Primero, supervisord no toma ningún argumento que sería relevante para nosotros, y si proporciona argumentos al contenedor, sustituye CMD y se anexan a ENTRYPOINT. Segundo, usar CMD nos permite proporcionar un comando completamente diferente (que se será ejecutado por /bin/sh -c) cuando se pasan argumentos al contenedor, lo que hace que la depuración sea más fácil.

      Y finalmente, deberá ejecutar chown como raíz antes de iniciar supervisord para evitar problemas de permisos sobre el volumen de datos y para permitir que se abran los procesos secundarios stdout. Esto también significa que deberá usar gosu en vez de la instrucción USER para cambiar al usuario.

      Este es el aspecto que tendrá su archivo Dockerfile completado:

      ~/thunderbird/Dockerfile

      FROM golang:1.14-buster AS easy-novnc-build
      WORKDIR /src
      RUN go mod init build && 
          go get github.com/geek1011/easy-novnc@v1.1.0 && 
          go build -o /bin/easy-novnc github.com/geek1011/easy-novnc
      
      FROM debian:buster
      
      RUN apt-get update -y && 
          apt-get install -y --no-install-recommends openbox tigervnc-standalone-server supervisor gosu && 
          rm -rf /var/lib/apt/lists && 
          mkdir -p /usr/share/desktop-directories
      
      RUN apt-get update -y && 
          apt-get install -y --no-install-recommends lxterminal nano wget openssh-client rsync ca-certificates xdg-utils htop tar xzip gzip bzip2 zip unzip && 
          rm -rf /var/lib/apt/lists
      
      RUN apt-get update -y && 
          apt-get install -y --no-install-recommends thunderbird && 
          rm -rf /var/lib/apt/lists
      
      COPY --from=easy-novnc-build /bin/easy-novnc /usr/local/bin/
      COPY menu.xml /etc/xdg/openbox/
      COPY supervisord.conf /etc/
      EXPOSE 8080
      
      RUN groupadd --gid 1000 app && 
          useradd --home-dir /data --shell /bin/bash --uid 1000 --gid 1000 app && 
          mkdir -p /data
      VOLUME /data
      
      CMD ["sh", "-c", "chown app:app /data /dev/stdout && exec gosu app supervisord"]
      

      Guarde y cierre su Dockerfile. Ahora estamos listos para crear y ejecutar nuestro contenedor, y luego acceder a Thunderbird – una aplicación GUI.

      Paso 4: Crear y ejecutar el contenedor

      El siguiente paso es crear su contenedor y configurarlo para que se ejecute al inicio. También configurará un volumen para conservar los datos de la aplicación entre reinicios y actualizaciones.

      Primero, cree su contenedor. Asegúrese de ejecutar estos comandos en el directorio ~/thunderbird:

      • docker build -t thunderbird .

      Ahora cree una nueva red que será compartida entre los contenedores de la aplicación:

      • docker network create thunderbird-net

      A continuación, cree un volumen para almacenar los datos de la aplicación:

      • docker volume create thunderbird-data

      Finalmente, ejecútelo para que se reinicie automáticamente:

      • docker run --detach --restart=always --volume=thunderbird-data:/data --net=thunderbird-net --name=thunderbird-app thunderbird

      Tenga en cuenta que si lo desea, puede sustituir thunderbird-app tras la opción --nombre con un nombre diferente. Sea cual sea su elección, su aplicación ahora está en contenedor y ejecutándose. Ahora vamos a usar el servidor web Caddy para protegerla y conectar remotamente a ella.

      Paso 5: Configurar Caddy

      En este paso, configurará el servidor web Caddy para proporcionar autenticación y, opcionalmente, acceso remoto a los archivos sobre WebDAV. Para mayor simplicidad, y para permitirle usarlo con su proxy inverso existente, lo ejecutará en otro contenedor.

      Cree un nuevo directorio y muévalo dentro:

      Ahora cree un nuevo Dockerfile usando nano o su editor preferido:

      Luego, añada las siguientes directivas:

      ~/caddy/Dockerfile

      FROM golang:1.14-buster AS caddy-build
      WORKDIR /src
      RUN echo 'module caddy' > go.mod && 
          echo 'require github.com/caddyserver/caddy/v2 v2.0.0' >> go.mod && 
          echo 'require github.com/mholt/caddy-webdav v0.0.0-20200523051447-bc5d19941ac3' >> go.mod
      RUN echo 'package main' > caddy.go && 
          echo 'import caddycmd "github.com/caddyserver/caddy/v2/cmd"' >> caddy.go && 
          echo 'import _ "github.com/caddyserver/caddy/v2/modules/standard"' >> caddy.go && 
          echo 'import _ "github.com/mholt/caddy-webdav"' >> caddy.go && 
          echo 'func main() { caddycmd.Main() }' >> caddy.go
      RUN go build -o /bin/caddy .
      
      FROM debian:buster
      
      RUN apt-get update -y && 
          apt-get install -y --no-install-recommends gosu && 
          rm -rf /var/lib/apt/lists
      
      COPY --from=caddy-build /bin/caddy /usr/local/bin/
      COPY Caddyfile /etc/
      EXPOSE 8080
      
      RUN groupadd --gid 1000 app && 
          useradd --home-dir /data --shell /bin/bash --uid 1000 --gid 1000 app && 
          mkdir -p /data
      VOLUME /data
      
      WORKDIR /data
      CMD ["sh", "-c", "chown app:app /data && exec gosu app /usr/local/bin/caddy run -adapter caddyfile -config /etc/Caddyfile"]
      

      Este Dockerfile crea Caddy con el complemento WebDAV habilitado, y luego lo abre en el puerto 8080 con Caddyfile en /etc/Caddyfile. Guarde y cierre el archivo.

      A continuación, configurará el servidor web Caddy. Cree un archivo llamado Caddyfile en el directorio que acaba de crear:

      Ahora añada el siguiente bloque de código a su Caddyfile:

      ~/caddy/Caddyfile

      {
          order webdav last
      }
      :8080 {
          log
          root * /data
          reverse_proxy thunderbird-app:8080
      
          handle /files/* {
              uri strip_prefix /files
              file_server browse
          }
          redir /files /files/
      
          handle /webdav/* {
              uri strip_prefix /webdav
              webdav
          }
          redir /webdav /webdav/
      
          basicauth /* {
              {env.APP_USERNAME} {env.APP_PASSWORD_HASH}
          }
      }
      

      Este Caddyfile realiza proxy el directorio raíz al contenedor thunderbird-app que creó en el Paso 4 (Docker lo resuelve a la IP correcta). También servirá como un navegador de archivo basado en web solo lectura en /files y para ejecutar el servidor WebDAV en /webdav que puede montar localmente para acceder a sus archivos. El nombre de usuario y la contraseña se leen desde las variables de entorno APP_USERNAME y APP_PASSWORD_HASH.

      Ahora cree el contenedor:

      • docker build -t thunderbird-caddy .

      Caddy v.2 requiere que haga hash a su contraseña deseada. Ejecute el siguiente comando y recuerde sustituir mypass con una contraseña fuerte que elija:

      • docker run --rm -it thunderbird-caddy caddy hash-password -plaintext 'mypass'

      Este comando dará como resultado una cadena de caracteres. Copie esto a su portapapeles para prepararse para ejecutar el siguiente comando.

      Ahora está listo para ejecutar el contenedor. Asegúrese de sustituir myuser con un nombre de usuario que elija, y sustituya mypass-hash con el resultado del comando que ejecutó en el paso anterior. Puede cambiar también el puerto (8080 aquí) para acceder a su servidor en un puerto diferente:

      • docker run --detach --restart=always --volume=thunderbird-data:/data --net=thunderbird-net --name=thunderbird-web --env=APP_USERNAME="myuser" --env=APP_PASSWORD_HASH="mypass-hash" --publish=8080:8080 thunderbird-caddy

      Ahora está listo para acceder y probar nuestra aplicación.

      Paso 6: Probar y administrar la aplicación

      Vamos a acceder a su aplicación y a asegurarnos de que está funcionando.

      Primero, abra http://your_server_ip:8080 en un navegador web, inicie sesión con las credenciales que seleccionó anteriormente y haga clic en Connect.

      Página de conexión de NoVNC

      Ahora debería poder interactuar con la aplicación, y debería cambiar de tamaño automáticamente para que se adapte a la ventana de su navegador.

      Menú principal de Thunderbird

      Si hace clic con el botón derecho en el escritorio en negro, debería ver un menú que le permite acceder a un terminal. Si hace clic en el centro, debería ver una lista de ventanas.

      Clic derecho en NoVNC

      Ahora abra http://your_server_ip:8080/files/ en un navegador web. Debería poder acceder a sus archivos.

      Archivo de acceso webdav a NoVNC

      Opcionalmente, puede intentar montar http://your_server_ip:8080/webdav/ en un cliente WebDAV. Debería poder acceder y modificar sus archivos directamente. Si utiliza la opción Asignar unidad de red en Windows Explorer, necesitará usar un proxy inverso para añadir HTTPS o establecer HKLMSYSTEMCurrentControlSetServicesWebClientParametersBasicAuthLevel​​​ a DWORD:2.

      En cualquier caso, su aplicación GUI nativa está ahora lista para su uso remoto.

      Conclusión

      Ahora ha configurado correctamente un contenedor Docker para Thunderbird y a continuación, usando Caddy, ha configurado el acceso a él a través de un navegador web. Si alguna vez necesita actualizar su aplicación, detenga los contenedores, ejecute docker rm thunderbird-app thunderbird-web, vuelva a crear las imágenes, y vuelva a ejecutar los comandos docker run de los pasos anteriores. Sus datos se conservarán, ya que se almacenan en un volumen.

      Si desea obtener más información sobre los comandos Docker básicos, puede leer este tutorial o esta hoja de trucos. Para un uso a más largo plazo, quizá desee considerar habilitar HTTPS (esto requiere un dominio) para mayor seguridad.

      Además, si está implementando más de una aplicación, es posible que desee usar Docker Compose o Kubernetes en vez de iniciar cada contenedor manualmente. Y recuerde, este tutorial puede servir como base para ejecutar cualquier otra aplicación Linux en su servidor, incluyendo:

      • Wine, una capa de compatibilidad para ejecutar aplicaciones Windows en Linux.
      • GIMP, un editor de imágenes de código abierto.
      • Cutter, una plataforma de ingeniería inversa de código abierto:

      Esta última opción demuestra el gran potencial de usar contendores y acceder remotamente a aplicaciones GUI. Con esta configuración, puede usar un servidor con una potencia de computación considerablemente mayor que si utilizase localmente herramientas que consumen muchos recursos como Cutter.



      Source link

      Cómo acceder remotamente a aplicaciones GUI usando Docker y Caddy en Ubuntu 20.04


      El autor seleccionó la Free and Open Source Fund para recibir una donación como parte del programa Write for DOnations.

      Introducción

      Aún con la creciente popularidad de los servicios en la nube, la necesidad de ejecutar aplicaciones nativas sigue existiendo.

      Con noVNC y TigerVNC, puede ejecutar aplicaciones nativas dentro de un contenedor Docker y acceder a ellas remotamente usando un navegador web. Adicionalmente, puede ejecutar su aplicación en un servidor con más recursos del sistema de los que pueda tener disponibles localmente, lo que puede proporcionar mayor flexibilidad cuando se ejecutan grandes aplicaciones.

      En este tutorial, pondrá en un contendor Mozilla Thunderbird, un cliente de correo electrónico, usando Docker. Tras ello, lo protegerá y proporcionará acceso remoto usando el servidor web Caddy.

      Cuando haya terminado, podrá acceder a Thunderbird desde cualquier dispositivo usando únicamente un navegador web. Opcionalmente, podrá acceder localmente a los archivos usando WebDAV. También tendrá una imagen Docker completamente auto-contenida que puede ejecutar en cualquier lugar.

      Requisitos previos

      Antes de iniciar esta guía, necesitará lo siguiente:

      Paso 1: Crear la configuración supervisord

      Ahora que su servidor está ejecutándose y Docker está instalado, está listo para comenzar a configurar el contenedor de su aplicación. Ya que su contenedor consta de varios componentes, deberá usar un administrador de procesos para iniciarlos y monitorizarlos. Aquí usará supervisord. supervisord es un gestor de procesos escrito en Python que se utiliza a menudo para organizar contenedores complejos.

      Primero, cree y entre en un directorio llamado thunderbird para su contenedor.

      • mkdir ~/thunderbird
      • cd ~/thunderbird

      Ahora cree y abra un archivo llamado supervisord.conf usando nano o su editor preferido:

      • nano ~/thunderbird/supervisord.conf

      Ahora añada este primer bloque de código en supervisord.conf, lo que definirá las opciones globales para supervisord:

      ~/thunderbird/supervisord.conf

      [supervisord]
      nodaemon=true
      pidfile=/tmp/supervisord.pid
      logfile=/dev/fd/1
      logfile_maxbytes=0
      

      En este bloque, está configurando supervisord. Deberá establecer nodaemon a true porque se ejecutará dentro de un contenedor Docker como el punto de entrada. Por tanto, querrá que permanezca en ejecución en primer plano. También configura pidfile a una ruta accesible por un usuario non-root (esto se describe más adelante), y logfile to stdout para que pueda ver los registros.

      A continuación, añada otro bloque de código pequeño a supervisord.conf. Este bloque inicia TigerVNC que es un servidor VNC/X11 combinado:

      ~/thunderbird/supervisord.conf

      ...
      [program:x11]
      priority=0
      command=/usr/bin/Xtigervnc -desktop "Thunderbird" -localhost -rfbport 5900 -SecurityTypes None -AlwaysShared -AcceptKeyEvents -AcceptPointerEvents -AcceptSetDesktopSize -SendCutText -AcceptCutText :0
      autorestart=true
      stdout_logfile=/dev/fd/1
      stdout_logfile_maxbytes=0
      redirect_stderr=true
      

      En este bloque, está configurando el servidor X11. X11 es un protocolo de servidor de visualización, que es lo que permite que se ejecuten las aplicaciones GUI. Tenga en cuenta que en el futuro se sustituirá con Wayland, pero el acceso remoto aún está en desarrollo.

      Para este contenedor, está usando TigerVNC y está integrado en el servidor VNC. Esto tiene varias ventajas sobre el uso de un servidor X11 y VNC:

      • Tiempo de respuesta más rápido, ya que el dibujo de la GUI se realiza directamente en el servidor VNC en vez de hacerse en un framebuffer intermedio (la memoria que almacena los contenidos de la pantalla).
      • Cambio de tamaño automático de la pantalla, que permite que la aplicación remota cambie de tamaño automáticamente para que se ajuste al cliente (en este caso, la ventana de su navegador web).

      Si lo desea, puede cambiar el argumento para la opción -desktop desde Thunderbird a otra cosa que elija. El servidor mostrará su opción como el título de la página web usada para acceder a su aplicación.

      Ahora, vamos a añadir un tercer bloque de código a supervisord.conf para iniciar easy-novnc:

      ~/thunderbird/supervisord.conf

      ...
      [program:easy-novnc]
      priority=0
      command=/usr/local/bin/easy-novnc --addr :8080 --host localhost --port 5900 --no-url-password --novnc-params "resize=remote"
      autorestart=true
      stdout_logfile=/dev/fd/1
      stdout_logfile_maxbytes=0
      redirect_stderr=true
      

      En este bloque, está configurando easy-novnc, un servidor independiente que ofrece un envoltorio alrededor de noVNC. Este servidor realiza dos funciones. Primero, proporciona una página sencilla de conexión que le permite configurar opciones para la conexión, y le permite establecer las predeterminadas. Segundo, realiza proxy a VNC sobre WebSocket, lo que permite el acceso a través de un navegador web ordinario.

      Normalmente, el cambio de tamaño se realiza en el lado del cliente (es decir, escala de imagen), pero está usando la opción resize=remote para aprovechar los ajustes de resolución remota de TigerVNC. Esto también proporciona una menor latencia en dispositivos más lentos, como Chromebooks de gama baja:

      Nota: Este tutorial utiliza easy-novnc. Si lo desea, puede usar websockfy y un servidor web independiente. La ventaja de easy-novnc es que el uso de memoria y el tiempo de inicio es significativamente menor que si fuese auto-contenido. easy-novnc también proporciona una página conexión más limpia que la de noVNC predeterminado, y permite establecer opciones predeterminadas que son útiles para esta configuración (como resize=remote).

      Ahora añada el siguiente bloque a su configuración para iniciar OpenBox, el gestor de ventanas:

      ~/thunderbird/supervisord.conf

      ...
      [program:openbox]
      priority=1
      command=/usr/bin/openbox
      environment=DISPLAY=:0
      autorestart=true
      stdout_logfile=/dev/fd/1
      stdout_logfile_maxbytes=0
      redirect_stderr=true
      

      En este bloque, está configurando OpenBox, un gestor de ventanas X11 ligero. Podría omitir este paso, pero sin él no tendría las barras de título o podría cambiar el tamaño de las ventanas.

      Finalmente, vamos a añadir el último bloque a supervisord.conf, que iniciará la aplicación principal:

      ~/thunderbird/supervisord.conf

      ...
      [program:app]
      priority=1
      environment=DISPLAY=:0
      command=/usr/bin/thunderbird
      autorestart=true
      stdout_logfile=/dev/fd/1
      stdout_logfile_maxbytes=0
      redirect_stderr=true
      

      En este bloque final, está configurando priority a 1 para garantizar que Thunderbird se inicia tras TigerVNC, o encontrará una condición de carrera o fallaría aleatoriamente al inicio. También configuramos autorestart=true para que vuelva a abrir automáticamente la aplicación si se cierra por error. La variable de entorno DISPLAY indica a la aplicación que se muestre en el servidor VNC que configuró anteriormente.

      Este es el aspecto que tendrá su supervisord.conf completado:

      ~/thunderbird/supervisord.conf

      [supervisord]
      nodaemon=true
      pidfile=/tmp/supervisord.pid
      logfile=/dev/fd/1
      logfile_maxbytes=0
      
      [program:x11]
      priority=0
      command=/usr/bin/Xtigervnc -desktop "Thunderbird" -localhost -rfbport 5900 -SecurityTypes None -AlwaysShared -AcceptKeyEvents -AcceptPointerEvents -AcceptSetDesktopSize -SendCutText -AcceptCutText :0
      autorestart=true
      stdout_logfile=/dev/fd/1
      stdout_logfile_maxbytes=0
      redirect_stderr=true
      
      [program:easy-novnc]
      priority=0
      command=/usr/local/bin/easy-novnc --addr :8080 --host localhost --port 5900 --no-url-password --novnc-params "resize=remote"
      autorestart=true
      stdout_logfile=/dev/fd/1
      stdout_logfile_maxbytes=0
      redirect_stderr=true
      
      [program:openbox]
      priority=1
      command=/usr/bin/openbox
      environment=DISPLAY=:0
      autorestart=true
      stdout_logfile=/dev/fd/1
      stdout_logfile_maxbytes=0
      redirect_stderr=true
      
      [program:app]
      priority=1
      environment=DISPLAY=:0
      command=/usr/bin/thunderbird
      autorestart=true
      stdout_logfile=/dev/fd/1
      stdout_logfile_maxbytes=0
      redirect_stderr=true
      

      Si desea poner una aplicación diferente en contenedor, sustituya /usr/bin/thunderbird con la ruta al ejecutable de su aplicación. De lo contrario, estará listo para configurar el menú principal de su GUI.

      Paso 2: Configurar el menú de OpenBox

      Ahora que su gestor de procesos está configurado, vamos a configurar el menú de OpenBox. Este menú nos permite abrir aplicaciones dentro del contenedor. También incluiremos un monitor de terminal y procesos para depurar si es necesario.

      Dentro del directorio de la aplicación, utilice nano o su editor de texto favorito para crear y abrir un nuevo archivo llamado menu.xml:

      • nano ~/thunderbird/menu.xml

      Ahora añada el siguiente código a menu.xml:

      ~/thunderbird/menu.xml

      <?xml version="1.0" encoding="utf-8"?>
      <openbox_menu xmlns="http://openbox.org/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://openbox.org/ file:///usr/share/openbox/menu.xsd">
          <menu id="root-menu" label="Openbox 3">
              <item label="Thunderbird">
                  <action name="Execute">
                      <execute>/usr/bin/thunderbird</execute>
                  </action>
              </item>
              <item label="Terminal">
                  <action name="Execute">
                      <execute>/usr/bin/x-terminal-emulator</execute>
                  </action>
              </item>
              <item label="Htop">
                  <action name="Execute">
                      <execute>/usr/bin/x-terminal-emulator -e htop</execute>
                  </action>
              </item>
          </menu>
      </openbox_menu>
      

      Este archivo XML contiene los elementos del menú que aparecerán cuando haga clic con el botón derecho sobre el escritorio. Cada elemento consta de una etiqueta y una acción.

      Si desea añadir al contenedor una aplicación diferente, sustituya /usr/bin/thunderbird con la ruta al ejecutable de su aplicación y cambie label del elemento.

      Paso 3: Crear el Dockerfile

      Ahora que OpenBox está configurado, creará el Dockerfile, que une todo.

      Crear un Dockerfile en el directorio de su contenedor:

      • nano ~/thunderbird/Dockerfile

      Para comenzar, vamos a añadir algún código para crear easy-novnc:

      ~/thunderbird/Dockerfile

      FROM golang:1.14-buster AS easy-novnc-build
      WORKDIR /src
      RUN go mod init build && 
          go get github.com/geek1011/easy-novnc@v1.1.0 && 
          go build -o /bin/easy-novnc github.com/geek1011/easy-novnc
      

      En la primera etapa, está creando easy-novnc. Esto se hace en una etapa independiente para mayor simplificada y para ahorrar espacio; no necesita toda la cadena de herramientas de Go en su imagen final. Observe @v1.1.0 en el comando de compilación. Esto garantiza que el resultado sea determinista, lo cual es importante porque Docker captura el resultado de cada paso. Si no hubiese especificado una versión explícita, Docker haría referencia a la versión más reciente de easy-novnc en el momento en que se compiló la imagen por primera vez. Además, desea garantizar que descarga una versión específica de easy-novnc, en el caso de que se realicen cambios de ruptura en la interfaz CLI.

      Ahora vamos a crear la segunda etapa que será la imagen final. Aquí usará Debian 10 (buster) como imagen base. Observe que, dado que se está ejecutando en un contenedor, funcionará independientemente de la distribución que esté ejecutando en su servidor.

      A continuación, añada el siguiente bloque a su Dockerfile:

      ~/thunderbird/Dockerfile

      ...
      FROM debian:buster
      RUN apt-get update -y && 
          apt-get install -y --no-install-recommends openbox tigervnc-standalone-server supervisor gosu && 
          rm -rf /var/lib/apt/lists && 
          mkdir -p /usr/share/desktop-directories
      

      En esta instrucción, está instalando Debian 10 como su imagen base y, luego, instalando el mínimo necesario para ejecutar aplicaciones GUI en su contenedor. Observe que ejecuta apt-get update como parte de la misma instrucción para evitar problemas de captura desde Docker. Para ahorrar espacio, también está eliminando las listas de paquetes descargadas posteriormente (los paquetes en caché en sí mismos se eliminan por defecto). Está creando /usr/share/desktop-directories porque algunas aplicaciones dependen de que exista el directorio.

      Vamos a añadir otro bloque de código pequeño:

      ~/thunderbird/Dockerfile

      ...
      RUN apt-get update -y && 
          apt-get install -y --no-install-recommends lxterminal nano wget openssh-client rsync ca-certificates xdg-utils htop tar xzip gzip bzip2 zip unzip && 
          rm -rf /var/lib/apt/lists
      

      En esta instrucción, está instalando algunas utilidades y paquetes útiles de uso general. Son interesantes xdg-utils (que proporciona los comandos base usados por las aplicaciones de escritorio en Linux) y ca-certificates (que instala los certificados raíz para permitirnos acceder a los sitios HTTPS).

      Ahora, podemos añadir las instrucciones para la aplicación principal:

      ~/thunderbird/Dockerfile

      ...
      RUN apt-get update -y && 
          apt-get install -y --no-install-recommends thunderbird && 
          rm -rf /var/lib/apt/lists
      

      Como antes, aquí estamos instalando la aplicación. Si añade una aplicación diferente al contenedor, puede sustituir estos comandos con los necesarios para instalar su aplicación específica. Algunas aplicaciones requerirán un poco más de trabajo para ejecutarse dentro de Docker. Por ejemplo, si está instalando una aplicación que utiliza Chrome, Chromium o QtWebEngine, deberá usar el argumento de línea de comando --no-sandbox porque no será compatible en Docker.

      A continuación, vamos a comenzar añadiendo las instrucciones para añadir las últimas líneas al contenedor:

      ~/thunderbird/Dockerfile

      ...
      COPY --from=easy-novnc-build /bin/easy-novnc /usr/local/bin/
      COPY menu.xml /etc/xdg/openbox/
      COPY supervisord.conf /etc/
      EXPOSE 8080
      

      Aquí está añadiendo los archivos de configuración que creó anteriormente a la imagen y copiando el binario easy-novnc de la primera etapa.

      Este siguiente bloque de código crea el directorio de datos y añade un usuario dedicado para su aplicación. Esto es importante porque algunas aplicaciones no se ejecutan como root. También es una buena práctica no ejecutar aplicaciones como root, incluso en un contenedor.

      ~/thunderbird/Dockerfile

      ...
      RUN groupadd --gid 1000 app && 
          useradd --home-dir /data --shell /bin/bash --uid 1000 --gid 1000 app && 
          mkdir -p /data
      VOLUME /data
      

      Para garantizar un UID/GID consistente para los archivos, está estableciendo explícitamente ambos a 1000. También está montando un volumen sobre el directorio de datos para garantizar que persiste entre los reinicios.

      Finalmente, vamos a añadir las instrucciones para iniciar todo:

      ~/thunderbird/Dockerfile

      ...
      CMD ["sh", "-c", "chown app:app /data /dev/stdout && exec gosu app supervisord"]
      

      Al establecer el comando predeterminado a supervisord, el administrador iniciará los procesos requeridos para ejecutar su aplicación. En este caso, está usando CMD en vez de ENTRYPOINT. En la mayoría de los casos, no supondría una diferencia, pero usar CMD es mejor para este fin por algunos motivos. Primero, supervisord no toma ningún argumento que sería relevante para nosotros, y, si proporciona argumentos al contenedor, sustituye CMD y se anexan a ENTRYPOINT. Segundo, usar CMD nos permite proporcionar un comando completamente diferente (que se será ejecutado por /bin/sh -c) cuando se pasan argumentos al contenedor, lo que hace que la depuración sea más fácil.

      Y, finalmente, deberá ejecutar chown como raíz antes de iniciar supervisord para evitar problemas de permisos sobre el volumen de datos y para permitir que se abran los procesos secundarios stdout. Esto también significa que deberá usar gosu en vez de la instrucción USER para cambiar al usuario.

      Este es el aspecto que tendrá su archivo Dockerfile completado:

      ~/thunderbird/Dockerfile

      FROM golang:1.14-buster AS easy-novnc-build
      WORKDIR /src
      RUN go mod init build && 
          go get github.com/geek1011/easy-novnc@v1.1.0 && 
          go build -o /bin/easy-novnc github.com/geek1011/easy-novnc
      
      FROM debian:buster
      
      RUN apt-get update -y && 
          apt-get install -y --no-install-recommends openbox tigervnc-standalone-server supervisor gosu && 
          rm -rf /var/lib/apt/lists && 
          mkdir -p /usr/share/desktop-directories
      
      RUN apt-get update -y && 
          apt-get install -y --no-install-recommends lxterminal nano wget openssh-client rsync ca-certificates xdg-utils htop tar xzip gzip bzip2 zip unzip && 
          rm -rf /var/lib/apt/lists
      
      RUN apt-get update -y && 
          apt-get install -y --no-install-recommends thunderbird && 
          rm -rf /var/lib/apt/lists
      
      COPY --from=easy-novnc-build /bin/easy-novnc /usr/local/bin/
      COPY menu.xml /etc/xdg/openbox/
      COPY supervisord.conf /etc/
      EXPOSE 8080
      
      RUN groupadd --gid 1000 app && 
          useradd --home-dir /data --shell /bin/bash --uid 1000 --gid 1000 app && 
          mkdir -p /data
      VOLUME /data
      
      CMD ["sh", "-c", "chown app:app /data /dev/stdout && exec gosu app supervisord"]
      

      Guarde y cierre su Dockerfile. Ahora estamos listos para crear y ejecutar nuestro contenedor, y, luego, acceder a Thunderbird – una aplicación GUI.

      Paso 4: Crear y ejecutar el contenedor

      El siguiente paso es crear su contenedor y configurarlo para que se ejecute al inicio. También configurará un volumen para conservar los datos de la aplicación entre los reinicios y las actualizaciones.

      Primero, cree su contenedor. Asegúrese de ejecutar estos comandos en el directorio ~/thunderbird:

      • docker build -t thunderbird .

      Ahora cree una nueva red que será compartida entre los contenedores de la aplicación:

      • docker network create thunderbird-net

      A continuación, cree un volumen para almacenar los datos de la aplicación:

      • docker volume create thunderbird-data

      Finalmente, ejecútelo para que se reinicie automáticamente:

      • docker run --detach --restart=always --volume=thunderbird-data:/data --net=thunderbird-net --name=thunderbird-app thunderbird

      Tenga en cuenta que si lo desea, puede sustituir thunderbird-app tras la opción --name diferente. Sea cual sea su elección, su aplicación ahora está en contenedor y ejecutándose. Ahora vamos a usar el servidor web Caddy para protegerla y conectar remotamente a ella.

      Paso 5: Configurar Caddy

      En este paso, configurará el servidor web Caddy para proporcionar autenticación y, opcionalmente, acceso remoto a los archivos sobre WebDAV. Para mayor simplicidad, y para permitirle usarlo con su proxy inverso existente, lo ejecutará en otro contenedor.

      Cree un nuevo directorio y muévalo dentro:

      Ahora cree un nuevo Dockerfile usando nano o su editor preferido:

      Luego, añada las siguientes directivas:

      ~/caddy/Dockerfile

      FROM golang:1.14-buster AS caddy-build
      WORKDIR /src
      RUN echo 'module caddy' > go.mod && 
          echo 'require github.com/caddyserver/caddy/v2 v2.0.0' >> go.mod && 
          echo 'require github.com/mholt/caddy-webdav v0.0.0-20200523051447-bc5d19941ac3' >> go.mod
      RUN echo 'package main' > caddy.go && 
          echo 'import caddycmd "github.com/caddyserver/caddy/v2/cmd"' >> caddy.go && 
          echo 'import _ "github.com/caddyserver/caddy/v2/modules/standard"' >> caddy.go && 
          echo 'import _ "github.com/mholt/caddy-webdav"' >> caddy.go && 
          echo 'func main() { caddycmd.Main() }' >> caddy.go
      RUN go build -o /bin/caddy .
      
      FROM debian:buster
      
      RUN apt-get update -y && 
          apt-get install -y --no-install-recommends gosu && 
          rm -rf /var/lib/apt/lists
      
      COPY --from=caddy-build /bin/caddy /usr/local/bin/
      COPY Caddyfile /etc/
      EXPOSE 8080
      
      RUN groupadd --gid 1000 app && 
          useradd --home-dir /data --shell /bin/bash --uid 1000 --gid 1000 app && 
          mkdir -p /data
      VOLUME /data
      
      WORKDIR /data
      CMD ["sh", "-c", "chown app:app /data && exec gosu app /usr/local/bin/caddy run -adapter caddyfile -config /etc/Caddyfile"]
      

      Este Dockerfile crea Caddy con el complemento WebDAV habilitado, y luego lo abre en el puerto 8080 con Caddyfile en /etc/Caddyfile. Guarde y cierre el archivo.

      A continuación, configurará el servidor web Caddy. Cree un archivo llamado Caddyfile en el directorio que acaba de crear:

      Ahora añada el siguiente bloque de código a su Caddyfile:

      ~/caddy/Caddyfile

      {
          order webdav last
      }
      :8080 {
          log
          root * /data
          reverse_proxy thunderbird-app:8080
      
          handle /files/* {
              uri strip_prefix /files
              file_server browse
          }
          redir /files /files/
      
          handle /webdav/* {
              uri strip_prefix /webdav
              webdav
          }
          redir /webdav /webdav/
      
          basicauth /* {
              {env.APP_USERNAME} {env.APP_PASSWORD_HASH}
          }
      }
      

      Este Caddyfile realiza proxy el directorio raíz al contenedor thunderbird-app que creó en el paso 4 (Docker lo resuelve a la IP correcta). También servirá como un navegador de archivo basado en web solo lectura en /files y para ejecutar el servidor WebDAV en /webdav que puede montar localmente para acceder a sus archivos. El nombre de usuario y la contraseña se leen desde las variables de entorno APP_USERNAME y APP_PASSWORD_HASH.

      Ahora cree el contenedor:

      • docker build -t thunderbird-caddy .

      Caddy v.2 requiere que haga hash a su contraseña deseada. Ejecute el siguiente comando y recuerde sustituir mypass con una contraseña segura que elija:

      • docker run --rm -it thunderbird-caddy caddy hash-password -plaintext 'mypass'

      Este comando dará como resultado una cadena de caracteres. Copie esto a su portapapeles para prepararse para ejecutar el siguiente comando.

      Ahora está listo para ejecutar el contenedor. Asegúrese de sustituir myuser con un nombre de usuario que elija, y sustituya mypass-hash con el resultado del comando que ejecutó en el paso anterior. Puede cambiar también el puerto (8080 aquí) para acceder a su servidor en un puerto diferente:

      • docker run --detach --restart=always --volume=thunderbird-data:/data --net=thunderbird-net --name=thunderbird-web --env=APP_USERNAME="myuser" --env=APP_PASSWORD_HASH="mypass-hash" --publish=8080:8080 thunderbird-caddy

      Ahora está listo para acceder y probar nuestra aplicación.

      Paso 6: Probar y administrar la aplicación

      Vamos a acceder a su aplicación y a asegurarnos de que está funcionando.

      Primero, abra http://your_server_ip:8080 en un navegador web, inicie sesión con las credenciales que seleccionó anteriormente, y haga clic en Connect.

      Página de conexión de NoVNC

      Ahora debería poder interactuar con la aplicación, y debería cambiar de tamaño automáticamente para que se adapte a la ventana de su navegador.

      Menú principal de Thunderbird

      Si hace clic con el botón derecho en el escritorio en negro, debería ver un menú que le permite acceder a un terminal. Si hace clic en el centro, debería ver una lista de ventanas.

      Clic derecho en NoVNC

      Ahora abra http://your_server_ip:8080/files/ en un navegador web. Debería poder acceder a sus archivos.

      Archivo de acceso webdav a NoVNC

      Opcionalmente, puede intentar montar http://your_server_ip:8080/webdav/ en un cliente WebDAV. Debería poder acceder y modificar sus archivos directamente. Si utiliza la opción Asignar unidad de red en Windows Explorer, necesitará usar un proxy inverso para añadir HTTPS o establecer HKLMSYSTEMCurrentControlSetServicesWebClientParametersBasicAuthLevel​​​ a DWORD:2.

      En cualquier caso, su aplicación GUI nativa está ahora lista para su uso remoto.

      Conclusión

      Ahora ha configurado correctamente un contenedor Docker para Thunderbird y a continuación, usando Caddy, ha configurado el acceso a él a través de un navegador web. Si alguna vez necesita actualizar su aplicación, detenga los contenedores, ejecute docker rm thunderbird-app thunderbird-web, vuelva a crear las imágenes, y vuelva a ejecutar los comandos docker run de los pasos anteriores. Sus datos se conservarán, ya que se almacenan en un volumen.

      Si desea obtener más información sobre los comandos Docker básicos, puede leer este tutorial o esta hoja de trucos. Para un uso a más largo plazo, quizá desee considerar habilitar HTTPS (esto requiere un dominio) para mayor seguridad.

      Además, si está implementando más de una aplicación, es posible que desee usar Docker Compose o Kubernetes en vez de iniciar cada contenedor manualmente. Y recuerde, este tutorial puede servir como base para ejecutar cualquier otra aplicación Linux en su servidor, incluyendo:

      • Wine, una capa de compatibilidad para ejecutar aplicaciones Windows en Linux.
      • GIMP, un editor de imágenes de código abierto.
      • Cutter, una plataforma de ingeniería inversa de código abierto.

      Esta última opción demuestra el gran potencial de usar contendores y acceder remotamente a aplicaciones GUI. Con esta configuración, puede usar un servidor con una potencia de computación considerablemente mayor que si utilizase localmente herramientas que consumen muchos recursos como Cutter.



      Source link

      Cómo presentar aplicaciones de Flask con Gunicorn y Nginx en Ubuntu 20.04


      Introducción

      A través de esta guía, creará una aplicación de Python utilizando el microframework de Flask en Ubuntu 20.04. En la mayor parte de este artículo se abordarán la configuración del servidor de la aplicación Gunicorn y la forma de iniciar la aplicación y configurar Nginx para que funcione como un proxy inverso de cliente.

      Requisitos previos

      Antes de comenzar con esta guía, deberá contar con lo siguiente:

      • Un servidor con Ubuntu 20.04 instalado y un usuario no root con privilegios sudo. Siga nuestra guía de configuración inicial para servidores a modo de orientación.
      • Nginx instalado conforme a los pasos 1 y 2 de Cómo instalar Nginx en Ubuntu 20.04.
      • Un nombre de dominio configurado para que apunte a su servidor. Puede adquirir uno en Namecheap u obtener uno de forma gratuita en Freenom. Puede aprender a apuntar dominios a DigitalOcean siguiendo la documentación sobre dominios y DNS pertinente. Asegúrese de crear los siguientes registros DNS:

        • Un registro A con your_domain orientado a la dirección IP pública de su servidor.
        • Un registro A con www.your_domain orientado a la dirección IP pública de su servidor.
      • Conocimientos sobre la especificación WSGI, que el servidor de Gunicorn usará para comunicarse con su aplicación Flask. En esta discusión se abarca WSGI de forma más deallada.

      Paso 1: Instalar los componentes desde los repositorios de Ubuntu

      Nuestro primer paso será instalar todo lo que necesitamos desde los repositorios de Ubuntu. Esto incluye pip, el administrador de paquetes de Python, que gestionará nuestros componentes de Python. También obtendremos los archivos de desarrollo de Python necesarios para crear algunos de los componentes de Gunicorn.

      Primero, actualizaremos el índice de paquetes locales e instalaremos los paquetes que nos permitirán crear nuestro entorno de Python. Entre ellos está phyton3-pip, junto con paquetes y herramientas de desarrollo adicionales que se necesitan para un entorno de programación sólido:

      • sudo apt update
      • sudo apt install python3-pip python3-dev build-essential libssl-dev libffi-dev python3-setuptools

      Una vez implementados estos paquetes, crearemos un entorno virtual para nuestro proyecto.

      Paso 2: Crear un entorno virtual de Python

      A continuación, configuraremos un entorno virtual para aislar nuestra aplicación de Flask de los otros archivos de Python del sistema.

      Comience instalando el paquete python3-venv, que instalará el módulo venv:

      • sudo apt install python3-venv

      Luego, crearemos un directorio principal para nuestro proyecto de Flask. Después de crearlo, posiciónese en él:

      • mkdir ~/myproject
      • cd ~/myproject

      Cree un entorno virtual para almacenar los requisitos de Python de su proyecto de Flask escribiendo lo siguiente:

      • python3 -m venv myprojectenv

      Con esto se instalará una copia local de Python y pip en un directorio llamado myprojectenv dentro del directorio de su proyecto.

      Antes de instalar aplicaciones dentro del entorno virtual, deberá activarlo. Hágalo escribiendo lo siguiente:

      • source myprojectenv/bin/activate

      Su mensaje cambiará para indicar que ahora realiza operaciones dentro del entorno virtual. Se parecerá a esto: (myprojectenv)user@host:~/myproject$.

      Paso 3: Configurar una aplicación de Flask

      Ahora que se encuentra en su entorno virtual, podrá instalar Flask y Gunicorn y comenzar a diseñar su aplicación.

      Primero, instalaremos wheel con la instancia local de pip para asegurarnos de que nuestros paquetes se instalen aunque falten archivos de wheel:

      Nota


      Independientemente de la versión de Phyton que use, cuando se active el entorno virtual deberá utilizar el comando pip (no pip3).

      A continuación, instalaremos Flask y Gunicorn:

      • pip install gunicorn flask

      Creación de una aplicación de ejemplo

      Ahora que dispone de Flask, puede crear una aplicación sencilla. Flask es un microframework. No cuenta con muchas de las herramientas que podrían incluirse en frameworks con más características y existe sobre todo como un módulo que puede importar a sus proyectos para que pueda inicializar una aplicación web.

      Aunque la complejidad podría ser mayor, crearemos nuestra app de Flask en un único archivo, llamado myproject.py:

      • nano ~/myproject/myproject.py

      El código de aplicación residirá en este archivo. Importará Flask y creará una instancia de un objeto de Flask. Puede utilizarlo para definir las funciones que deberían ejecutarse cuando se solicita una ruta específica:

      ~/myproject/myproject.py

      from flask import Flask
      app = Flask(__name__)
      
      @app.route("/")
      def hello():
          return "<h1 style="color:blue">Hello There!</h1>"
      
      if __name__ == "__main__":
          app.run(host="0.0.0.0")
      

      Esto define básicamente el contenido que se presentará al acceder al dominio root. Guarde y cierre el archivo cuando termine.

      Si siguió la guía de configuración inicial para servidores, debería tener activado un firewall UFW. Para probar la aplicación, debe permitir el acceso al puerto 5000:

      Ahora podrá probar su aplicación de Flask escribiendo lo siguiente:

      Verá un resultado como el siguiente, en el cual se incluirá una advertencia útil que le recordará no utilizar esta configuración de servidor en la producción:

      Output

      * Serving Flask app "myproject" (lazy loading) * Environment: production WARNING: Do not use the development server in a production environment. Use a production WSGI server instead. * Debug mode: off * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)

      Agregue :5000 al final de la dirección IP de su servidor en su navegador web y visítela:

      http://your_server_ip:5000
      

      Debería ver algo como esto:

      Aplicación de ejemplo de Flask

      Cuanto termine, pulse CTRL-C en la ventana de su terminal para detener el servidor de desarrollo Flask.

      Creación de un punto de entrada de WSGI

      A continuación, crearemos un archivo que servirá como punto de entrada para nuestra aplicación. Esto indicará a nuestro servidor de Gunicorn cómo interactuar con la aplicación.

      Llamemos al archivo wsgi.py:

      En él, importaremos la instancia de Flask desde nuestra aplicación y luego la ejecutaremos:

      ~/myproject/wsgi.py

      from myproject import app
      
      if __name__ == "__main__":
          app.run()
      

      Guarde y cierre el archivo cuando termine.

      Paso 4: Configurar Gunicorn

      Su aplicación quedará, así, escrita con un punto de entrada establecido. Ahora, podemos continuar con la configuración de Gunicorn.

      Antes de continuar, debe comprobar que Gunicorn pueda proveer correctamente la aplicación.

      Podemos hacerlo con solo pasarle el nombre de nuestro punto de entrada. Se construye como el nombre del módulo (menos la extensión .py) más el nombre del elemento invocable dentro de la aplicación. En nuestro caso, es wsgi:app.

      También especificaremos la interfaz y el puerto que se vinculará para que la aplicación se inicie en una interfaz disponible de forma pública:

      • cd ~/myproject
      • gunicorn --bind 0.0.0.0:5000 wsgi:app

      Debería ver un resultado como el siguiente:

      Output

      [2020-05-20 14:13:00 +0000] [46419] [INFO] Starting gunicorn 20.0.4 [2020-05-20 14:13:00 +0000] [46419] [INFO] Listening at: http://0.0.0.0:5000 (46419) [2020-05-20 14:13:00 +0000] [46419] [INFO] Using worker: sync [2020-05-20 14:13:00 +0000] [46421] [INFO] Booting worker with pid: 46421

      Visite de nuevo la dirección IP de su servidor con :5000 agregado al final en su navegador web:

      http://your_server_ip:5000
      

      Debería ver el resultado de su aplicación:

      Aplicación de ejemplo de Flask

      Cuando confirme que funciona correctamente, pulse CTRL-C en la ventana de su terminal.

      Ya completamos las tareas de nuestro entorno virtual, por lo que podemos desactivarlo:

      Ahora todos los comandos de Python usarán de nuevo el entorno de Phyton del sistema.

      A continuación, crearemos el archivo de unidad de servicio systemd. Crear un archivo de unidad systemd permitirá que el sistema init de Ubuntu inicie automáticamente Gunicorn y haga funcionar la aplicación de Flask cuando el servidor se cargue.

      Cree un archivo de unidad terminado en .service dentro del directorio /etc/systemd/system para empezar:

      • sudo nano /etc/systemd/system/myproject.service

      En su interior, empezaremos con la sección [Unit] que se usa para especificar metadatos y dependencias. Aquí agregaremos una descripción de nuestro servicio e indicaremos al sistema init que lo inicie solo tras haber alcanzado el objetivo de red:

      /etc/systemd/system/myproject.service

      [Unit]
      Description=Gunicorn instance to serve myproject
      After=network.target
      

      A continuación, abriremos la sección [Service]. Esto especificará el usuario y el grupo con los cuales deseamos que se ejecute el proceso. Otorgaremos la propiedad del proceso a nuestra cuenta de usuario normal, ya que tiene la propiedad de todos los archivos pertinentes. También otorgaremos la propiedad del grupo al grupo www-data para que Nginx pueda comunicarse fácilmente con los procesos de Gunicorn. No se olvide de sustituir el nombre de usuario por el suyo:

      /etc/systemd/system/myproject.service

      [Unit]
      Description=Gunicorn instance to serve myproject
      After=network.target
      
      [Service]
      User=sammy
      Group=www-data
      

      A continuación, planearemos los detalles del directorio de trabajo y estableceremos el entorno variable PATH para que el sistema init sepa que los ejecutables para el proceso están ubicados dentro de nuestro entorno virtual. También especificaremos el comando para iniciar el servicio. Este comando hará lo siguiente:

      • Iniciar 3 procesos de trabajadores (debería, no obstante, ajustar esto si es necesario)
      • Crear un archivo de socket de Unix, myproject.sock, dentro del directorio de nuestro proyecto y establecer un vínculo con él. Estableceremos un valor sin máscara de 007 para que se cree el archivo de socket, se proporcione acceso al propietario y, al mismo tiempo, se restrinjan otros accesos.
      • Especifique el nombre del archivo del punto de entrada de WSGI junto con el elemento invocable de Python dentro de ese archivo (wsgi:app).

      Systemd necesita que le proporcionemos la ruta completa al ejecutable de Gunicorn, que se instala dentro de nuestro entorno virtual.

      No se olvide de sustituir el nombre del usuario y las rutas del proyecto por su propia información:

      /etc/systemd/system/myproject.service

      [Unit]
      Description=Gunicorn instance to serve myproject
      After=network.target
      
      [Service]
      User=sammy
      Group=www-data
      WorkingDirectory=/home/sammy/myproject
      Environment="PATH=/home/sammy/myproject/myprojectenv/bin"
      ExecStart=/home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app
      

      Por último, vamos a añadiremos una sección [Install]. Esto indicará a systemd a qué deberá vincular este servicio si lo habilitamos para que se cargue en el inicio. Queremos que este servicio se inicie cuando el sistema multiusuario normal esté en funcionamiento:

      /etc/systemd/system/myproject.service

      [Unit]
      Description=Gunicorn instance to serve myproject
      After=network.target
      
      [Service]
      User=sammy
      Group=www-data
      WorkingDirectory=/home/sammy/myproject
      Environment="PATH=/home/sammy/myproject/myprojectenv/bin"
      ExecStart=/home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app
      
      [Install]
      WantedBy=multi-user.target
      

      Con eso, nuestro archivo de servicio de systemd quedará completo. Guárdelo y ciérrelo ahora.

      Ya podemos iniciar el servicio Gunicorn que creamos y activarlo para que se cargue en el inicio:

      • sudo systemctl start myproject
      • sudo systemctl enable myproject

      Comprobemos el estado:

      • sudo systemctl status myproject

      Debería ver el siguiente resultado:

      Output

      ● myproject.service - Gunicorn instance to serve myproject Loaded: loaded (/etc/systemd/system/myproject.service; enabled; vendor preset: enabled) Active: active (running) since Wed 2020-05-20 14:15:18 UTC; 1s ago Main PID: 46430 (gunicorn) Tasks: 4 (limit: 2344) Memory: 51.3M CGroup: /system.slice/myproject.service ├─46430 /home/sammy/myproject/myprojectenv/bin/python3 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app ├─46449 /home/sammy/myproject/myprojectenv/bin/python3 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app ├─46450 /home/sammy/myproject/myprojectenv/bin/python3 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app └─46451 /home/sammy/myproject/myprojectenv/bin/python3 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app

      Si detecta errores, asegúrese de resolverlos antes de continuar con el tutorial.

      Paso 5: Configurar Nginx para solicitudes de proxy

      Ahora, nuestro servidor de aplicación Gunicorn debería estar funcionando, esperando solicitudes en el archivo de socket del directorio del proyecto. Configuraremos Nginx para que transmita las solicitudes web al socket haciendo algunas pequeñas adiciones a su archivo de configuración.

      Comencemos creando un nuevo archivo de configuración de bloque de servidor en el directorio sites-available de Nginx. Lo llamaremos myproject para que se adecue al resto de esta guía:

      • sudo nano /etc/nginx/sites-available/myproject

      Abra un bloque de servidor e indique a Nginx que escuche en el puerto predeterminado 80. También le indicaremos que utilice este bloque para solicitudes para el nombre de dominio de nuestro servidor:

      /etc/nginx/sites-available/myproject

      server {
          listen 80;
          server_name your_domain www.your_domain;
      }
      

      A continuación, agregaremos un bloque de ubicación que coincida con cada solicitud. Dentro de este bloque, incluiremos el archivo proxy_params que especifica algunos parámetros de proxy generales que deben configurarse. Luego, pasaremos las solicitudes al socket que definimos usando la directiva proxy_pass:

      /etc/nginx/sites-available/myproject

      server {
          listen 80;
          server_name your_domain www.your_domain;
      
          location / {
              include proxy_params;
              proxy_pass http://unix:/home/sammy/myproject/myproject.sock;
          }
      }
      

      Guarde y cierre el archivo al finalizar.

      Para habilitar la configuración del bloque de servidor de Nginx que acaba de crear, vincule el archivo al directorio sites-enabled​​​:

      • sudo ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled

      Con el archivo en ese directorio, puede realizar una verificación en busca de errores de sintaxis:

      Si no se indican problemas, reinicie el proceso de Nginx para que lea la nueva configuración:

      • sudo systemctl restart nginx

      Por último, ajustaremos el firewall de nuevo. Ya no necesitamos acceso a través del puerto 5000, por lo que podemos eliminar esta regla. Luego, podemos permitir el acceso completo al servidor de Nginx:

      • sudo ufw delete allow 5000
      • sudo ufw allow 'Nginx Full'

      Ahora debería poder visitar el nombre de dominio de su servidor en su navegador web:

      http://your_domain
      

      Debería ver el resultado de su aplicación:

      Aplicación de ejemplo de Flask

      Si encuentra algún error, intente verificar lo siguiente:

      • sudo less /var/log/nginx/error.log: verifica los registros de error de Nginx.
      • sudo less /var/log/nginx/access.log: verifica los registros de acceso de Nginx.
      • sudo journalctl -u nginx: verifica los registros de proceso de Nginx.
      • sudo journalctl -u myproject: verifica los registros de Gunicorn de su app de Flask.

      Paso 6: Proteger la aplicación

      Para asegurarse de que el tráfico hacia su servidor siga siendo seguro, obtendremos un certificado SSL para su dominio. Existen varias formas de hacer esto, incluyendo obtener un certificado gratuito de Let´s Encrypt, generar un certificado auto firmado, o comprar uno de otro proveedor, y configurar Nginx para usarlo siguiendo los Pasos 2 al 6 de Cómo crear un certificado SSL auto firmado para Nginx en Ubuntu 20.04. Por motivos de conveniencia, elegiremos la primera opción.

      Instale el paquete de Nginx de Certbot con apt:

      • sudo apt install python3-certbot-nginx

      Certbot ofrece varias alternativas para obtener certificados SSL a través de complementos. El complemento de Nginx se encargará de reconfigurar Nginx y volver a cargar la configuración cuando sea necesario. Para utilizar este complemento, escriba lo siguiente:

      • sudo certbot --nginx -d your_domain -d www.your_domain

      Con esto, se ejecuta certbot con el complemento --nginx usando -d para especificar los nombres para los cuales deseamos que el certificado tenga validez.

      Si es la primera vez que ejecuta certbot, se le solicitará introducir una dirección de correo electrónico y aceptar las condiciones de servicio. A continuación, certbot se comunicará con el servidor de Let’s Encrypt y, luego, realizará una comprobación para verificar que usted controle el dominio para el que solicita un certificado.

      Si la comprobación se realiza correctamente, certbot le preguntará cómo desea configurar sus ajustes de HTTPS:

      Output

      Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access. ------------------------------------------------------------------------------- 1: No redirect - Make no further changes to the webserver configuration. 2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for new sites, or if you're confident your site works on HTTPS. You can undo this change by editing your web server's configuration. ------------------------------------------------------------------------------- Select the appropriate number [1-2] then [enter] (press 'c' to cancel):

      Seleccione su elección y luego ENTER. La configuración se actualizará y Nginx se volverá a cargar para aplicar los ajustes nuevos. certbot concluirá con un mensaje que le indicará que el proceso tuvo éxito e indicará la ubicación de almacenamiento de sus certificados:

      Output

      IMPORTANT NOTES: - Congratulations! Your certificate and chain have been saved at: /etc/letsencrypt/live/your_domain/fullchain.pem Your key file has been saved at: /etc/letsencrypt/live/your_domain/privkey.pem Your cert will expire on 2020-08-18. To obtain a new or tweaked version of this certificate in the future, simply run certbot again with the "certonly" option. To non-interactively renew *all* of your certificates, run "certbot renew" - Your account credentials have been saved in your Certbot configuration directory at /etc/letsencrypt. You should make a secure backup of this folder now. This configuration directory will also contain certificates and private keys obtained by Certbot so making regular backups of this folder is ideal. - If you like Certbot, please consider supporting our work by: Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate Donating to EFF: https://eff.org/donate-le

      Si siguió las instrucciones de instalación de Nginx en los requisitos previos, ya no necesitará la asignación de perfil HTTP redundante:

      • sudo ufw delete allow 'Nginx HTTP'

      Para verificar la configuración, acceda una vez más a su dominio utilizando https://:

      https://your_domain
      

      Una vez más, debería ver el resultado de su aplicación junto con el indicador de seguridad de su navegador, el cual debería indicar que el sitio está protegido.

      Conclusión

      A través de esta guía, creó y aseguró una aplicación de Flask simple dentro de un entorno virtual de Python. Creó un punto de entrada de WSGI para que cualquier servidor de aplicación con capacidad para WSGI pueda interactuar con él y configuró el servidor de aplicación de Gunicorn para proporcionar esta función. Luego, creó un archivo de servicio systemd para iniciar automáticamente el servidor de aplicación en el inicio. También creó un bloque de servidor de Nginx que transmite el tráfico de clientes web al servidor de la aplicación, y reenvía solicitudes externas, y protegió el tráfico hacia su servidor con Let’s Encrypt.

      Flask es un framework muy sencillo, pero extremadamente flexible, diseñado para proporcionar funcionalidad a sus aplicaciones sin ser demasiado restrictivo respecto de la estructura y del diseño. Puede utilizar la pila general descrita en esta guía para hacer funcionar las aplicaciones de Flask que diseñe.



      Source link