September 5, 2022

2151 words 11 mins read

Instalando tu propio Servidor Shiny y RStudio en una Raspberry Pi

Instalando tu propio Servidor Shiny y RStudio en una Raspberry Pi

Este artículo se publicó originalmente en 2018 y muchas cosas han cambiado desde entonces, por lo que lo reescribí por completo para tener en cuenta los avances más recientes en la compatibilidad con la arquitectura arm64 dentro del ecosistema R.

En 2018, participé en un tema de foro en Community RStudio donde @jladata preguntaba si una Raspberry Pi 3B+ podría convertirse en un servidor Shiny viable. De hecho, yo uso una Raspberry Pi para ese mismo propósito, así que decidí compartir con la comunidad R mi experiencia al configurar Shiny y Rstudio Server de forma nativa en una Raspberry Pi.

En esos días había casi cero soporte para arquitecturas ARM (ya sea x32 o x64), por lo que la mayor parte del software tenía que compilarse desde la fuente en el mismo Pi, lo que hace que el proceso de instalación sea un esfuerzo titánico con muchisimas horas de espera.

Hoy en día, las cosas han cambiado y tenemos un mejor soporte para la arquitectura arm64 debido a los esfuerzos de la comunidad e incluso soporte oficial de RStudio en proceso. En este renovado artículo, te guiaré a través de las opciones de instalación que tenemos disponibles actualmente.

✏️ También tengo un artículo relacionado que muestra cómo automatizar el proceso de instalación usando Ansible.

Preparando la Raspberry Pi

Primero, necesitas un sistema operativo de 64 bits para tu Pi (asegúrate de que sea de 64 bits ya que RStudio solo es compatible con la arquitectura arm64), estas instrucciones de instalación funcionan tanto para Raspberry Pi OS como para Ubuntu, puedes descargar cualquiera de los dos usando el software Raspberry Pi Imager (sitio oficial). También, asegúrate de actualizar las bibliotecas de tu sistema con sudo apt update && sudo apt dist-upgrade antes de comenzar.

Aunque no es obligatorio, recomiendo realizar las siguientes acciones utilizando la aplicación sudo raspi-config (en Ubuntu, primero debes instalarla con sudo apt install raspi-config):

  • Expandir el sistema de archivos (Advanced Options / Expand Filesystem).
  • Definir tu configuración regional, asegúrate de elegir una opción UTF.8 para evitar problemas de compilación (Localisation Options / Locale).
  • Deshabilitar “Interfaces de red predecibles” (Advanced Options / Network Interface Names).

A continuación, debes configurar una IP estática para que puedas encontrar la Pi fácilmente en tu red.

Para configurar una IP estática en Raspberry Pi OS, ejecuta estos comandos. Esta es una configuración de IP de muestra para una conexión por cable, modificala de acuerdo a tus propias necesidades:

# Configuración IP de muestra:
sudo nmcli c mod 'Wired connection 1' ipv4.addresses 192.168.3.101/24 ipv4.method manual
sudo nmcli con mod 'Wired connection 1' ipv4.gateway 192.168.3.1
sudo nmcli con mod 'Wired connection 1' ipv4.dns "192.168.3.1"
sudo nmcli c down 'Wired connection 1' && sudo nmcli c up 'Wired connection 1'

Y para configurar la IP en Ubuntu, debes crear este archivo, sudo nano /etc/netplan/01-netcfg.yaml, agregar este contenido (edítalo según sea necesario) y aplicar la configuración con este comando, sudo netplan apply.

network:
    version: 2
    renderer: networkd
    ethernets:
        eth0:
            dhcp4: false
            addresses:
                - 192.168.0.101/24
            nameservers:
                addresses: [8.8.8.8, 8.8.4.4, 192.168.0.1]
            routes:
                - to: default
                  via: 192.168.0.1

En caso de que tengas un modelo de Raspberry Pi con poca RAM, debes agregar algo de memoria sawp para el proceso de instalación. Para los modelos Pi de 1 GB, 3 GB de sawp serían suficientes, puedes hacerlo con estos comandos:

sudo /bin/dd if=/dev/zero of=/var/swap.1 bs=1M count=3072
sudo chmod 600 /var/swap.1
sudo /sbin/mkswap /var/swap.1
sudo /sbin/swapon /var/swap.1
sudo sh -c 'echo "/var/swap.1 swap swap defaults 0 0 " >> /etc/fstab'

Para evitar el uso innecesario de la memoria swap y proteger tu tarjeta SD, abre este archivo, sudo nano /etc/sysctl.conf, y agrega esta línea al final:

    vm.swappiness=10

Instalar R

Tienes algunas opciones para instalar R en tu Pi:

  • Instalar desde los repositorios del Sistema Operativo
  • Compilar R desde la fuente
  • Instalar R usando rig
  • Instalar R desde el Proyecto R4Pi

Como ahora hay varias opciones, he movido esta sección a un artículo aparte que puedes consultar aquí para obtener más detalles.

Siempre que sea posible (con un sistema operativo compatible), recomiendo usar el repositorio de paquetes de R4Pi como tu fuente de paquetes R, ya que proporciona archivos binarios precompilados que hacen que la instalación sea más fácil y rápida.

Instalar Shiny Server

Actualmente, shiny-server no ofrece compatibilidad con ARM, por lo que la única opción para instalarlo en una Pi es compilar desde la fuente. Hay esperanza de que esto cambie en el futuro según la respuesta a este GitHub Issue, pero por el momento estamos atrapado con esto.

Primero, debes instalar las dependencias de paquetes R, si estás utilizando un repositorio CRAN, esto llevará un tiempo, pero es mucho más rápido si estás utilizando el repositorio R4Pi (disponible con R instalado desde R4Pi):

# Define tu repositorio de paquetes R (Debes escoger uno de estos)
# REPO="'http://cran.rstudio.com/'" # Para sistemas operativos no compatibles con los binarios compilados para RPi OS (basada en Debian 12)
# REPO="c('https://pkgs.r4pi.org/aarch64', 'http://cran.rstudio.com/')" # Para la versión antigua de RPi OS (basada en Debian 11)
REPO="c('https://pkgs.r4pi.org/bookworm', 'http://cran.rstudio.com/')" # Para la versión de RPi OS más reciente (basada en Debian 12)

# Asegúrate de que las dependencias del sistema estén instaladas
sudo apt install libcairo2-dev libxt-dev git cmake pandoc pandoc-citeproc-preamble

# Instala los paquetes R requeridos como sudo
sudo su - -c "R -e \"install.packages('Rcpp', repos=$REPO)\""
sudo su - -c "R -e \"install.packages('later', repos=$REPO)\""
sudo su - -c "R -e \"install.packages('fs', repos=$REPO)\""
sudo su - -c "R -e \"install.packages('R6', repos=$REPO)\""
sudo su - -c "R -e \"install.packages('Cairo', repos=$REPO)\""
sudo su - -c "R -e \"install.packages('httpuv', repos=$REPO)\""
sudo su - -c "R -e \"install.packages('mime', repos=$REPO)\""
sudo su - -c "R -e \"install.packages('jsonlite', repos=$REPO)\""
sudo su - -c "R -e \"install.packages('digest', repos=$REPO)\""
sudo su - -c "R -e \"install.packages('htmltools', repos=$REPO)\""
sudo su - -c "R -e \"install.packages('xtable', repos=$REPO)\""
sudo su - -c "R -e \"install.packages('sourcetools', repos=$REPO)\""
sudo su - -c "R -e \"install.packages('shiny', repos=$REPO)\""
sudo su - -c "R -e \"install.packages('rmarkdown', repos=$REPO)\""

✏️ Es necesario instalar los paquetes de R como sudo para que shiny-server pueda usarlos, no instales estos paquetes desde la consola de R usando tu usuario habitual.

Ahora, puedes instalar shiny-server con estos comandos:

# Descarga el código fuente de la última versión shiny-server desde GitHub
git clone --depth 1 --branch v1.5.20.1002 https://github.com/rstudio/shiny-server.git

# Compila el código fuente
cd shiny-server
DIR=`pwd`
PATH=$DIR/bin:$PATH
mkdir tmp
cd tmp
PYTHON=`which python`
sudo cmake -DCMAKE_INSTALL_PREFIX=/usr/local -DPYTHON="$PYTHON" ../
sudo make
mkdir ../build

# Modifique algunos enlaces de descarga y SHASUMs para compatibilidad con arm64
sed -i '8s/.*/NODE_SHA256=98d81a2d08f88646541d282b7ccc32429f8706ddcb30943fc3779ef9674ebb93/' ../external/node/install-node.sh # SHAMSUM para node-v16.18.1-linux-arm64.tar.xz
sed -i 's/linux-x64.tar.xz/linux-arm64.tar.xz/' ../external/node/install-node.sh
sed -i 's/https:\/\/github.com\/jcheng5\/node-centos6\/releases\/download\//https:\/\/nodejs.org\/dist\//' ../external/node/install-node.sh
sed -i 's/sha512-3RAVyfbptsR6HOFA0BFNLyw8ZXXDRWf5P3tIslbNt12kTikaRWepRR9vLHMyibIZeNfScI9uGqcn1KfbIAeuXA==/sha512-ZwrJM2WaOJesJGZlejLqAiBAE6Ts2PZNk1pQ\/x1uTMsQw83BaXWShjqCbhh5bPQUNrlx2Ijz1dOr0hLmlkxKag==/' ../npm-shrinkwrap.json

# Instala el node para arm64 y reconstruye los módulos node
(cd .. && sudo ./external/node/install-node.sh)
(cd .. && ./bin/npm --python="${PYTHON}" install --no-optional)
(cd .. && ./bin/node ./ext/node/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js --python="${PYTHON}" rebuild)

# Instala shiny-server
sudo make install

# Configura shiny-server
sudo mkdir -p /etc/shiny-server
sudo cp ../config/default.config /etc/shiny-server/shiny-server.conf
cd
sudo rm -rf shiny-server
sudo ln -s /usr/local/shiny-server/bin/shiny-server /usr/bin/shiny-server
sudo useradd -r -m shiny
sudo mkdir -p /var/log/shiny-server
sudo mkdir -p /srv/shiny-server
sudo mkdir -p /var/lib/shiny-server
sudo chown shiny /var/log/shiny-server

# Edita el archivo shiny-server.service
sudo nano /etc/systemd/system/shiny-server.service 
    # Pega el siguiente contenido
    
    [Unit]
    Description=ShinyServer

    [Service]
    Type=simple
    ExecStart=/usr/bin/env bash -c 'exec /usr/local/shiny-server/bin/shiny-server >>     /var/log/shiny-server.log 2>&1'
    KillMode=process
    ExecReload=/usr/bin/env kill -HUP $MAINPID
    ExecStopPost=/usr/bin/env sleep 5
    Restart=on-failure
    RestartSec=1
    StartLimitInterval=45
    StartLimitBurst=3

    [Install]
    WantedBy=multi-user.target

# Edita el archivo shiny-server para logrotate
sudo nano /etc/logrotate.d/shiny-server 
    # Pega el siguiente contenido
    
    /var/log/shiny-server.log {
       rotate 12
       copytruncate
       compress
       missingok
       size 1M
    }

# Establece los permisos para los archivos
sudo chown root:root /etc/systemd/system/shiny-server.service
sudo chmod 644 /etc/systemd/system/shiny-server.service
sudo chown root:root /etc/logrotate.d/shiny-server
sudo chmod 644 /etc/logrotate.d/shiny-server

# Inicia el servicio
sudo systemctl daemon-reload
sudo systemctl enable shiny-server
sudo systemctl start shiny-server

# Crea los enlaces simbolicos para pandoc y las aplicaciones de muestra
sudo ln -s -f /usr/bin/pandoc /usr/local/shiny-server/ext/pandoc/pandoc
sudo ln -s -f /usr/bin/pandoc-citeproc-preamble /usr/local/shiny-server/ext/pandoc/pandoc-citeproc
sudo ln -s /usr/local/shiny-server/samples/sample-apps /srv/shiny-server/sample-apps
sudo ln -s /usr/local/shiny-server/samples/welcome.html /srv/shiny-server/index.html

# Establece los permisos de usuario adecuados, estoy asumiendo que tu usuario es "pi", cámbialo si no lo es
sudo groupadd shiny-apps
sudo usermod -aG shiny-apps pi
sudo usermod -aG shiny-apps shiny
cd /srv/shiny-server
sudo chown -R pi:shiny-apps .
sudo chmod g+w .
sudo chmod g+s .
cd

Instala RStudio Server

En el pasado, la única forma de instalar RStudio Server en una Pi era compilar desde la fuente y esto requería mucho tiempo (me tomó 3 días la última vez que probé en una Pi 3B+) y era muy propenso a fallar porque RStudio IDE está en desarrollo activo.

Afortunadamente, en los últimos días, RStudio ha puesto a disposición compilaciones “experimentales” del IDE para arm64 (escribí un artículo al respecto), están compiladas para Ubuntu 20/22 LTS, pero los binarios para Ubuntu 22 también son compatibles con Raspberry Pi OS. Puedes consultar las compilaciones diarias disponibles aquí. Elije un enlace de acuerdo con el sistema operativo que estás utilizando, también ten en cuenta que estas compilaciones están destinadas a pruebas, por lo que es probable que tengan errores o sean inestables, si tienes problemas para instalar la última versión disponible, intenta con una versión anterior .

Las siguientes instrucciones usan un enlace para Ubuntu 22 (compatible con Raspberry Pi OS), recuerda cambiar el enlace si deseas usar otro sistema operativo o una versión más reciente del IDE:

sudo apt install gdebi
wget https://s3.amazonaws.com/rstudio-ide-build/server/jammy/arm64/rstudio-server-2023.12.0-daily-232-arm64.deb
sudo gdebi rstudio-server-2023.12.0-daily-232-arm64.deb
sudo rm rstudio-server-2023.12.0-daily-232-arm64.deb

✏️ Actualizaré esta sección una vez que el soporte arm64 se convierta en una función estable del RStudio IDE.

Instalar Servicios de Soporte Adicionales (opcional)

Nginx es un servidor web de bajos requisitos, que resulta útil para autohospedar archivos HTML, pero también para usarlo como proxy inverso (más información sobre esto en la siguiente sección). Puedes instalarlo con este comando:

sudo apt install nginx

También, para trabajar con conjuntos de datos “más grandes que la memoria” (ten en cuenta que la Pi no tiene mucha RAM), tener un RDBMS es útil. Personalmente prefiero PostgreSQL ya que es de código abierto y tiene capacidades impresionantes, puedes instalar PostgreSQL con este comando:

sudo apt install postgresql libpq-dev postgresql-client postgresql-client-common

Pasos Adicionales (opcional)

Crea direcciones URL agradables para Shiny y Rstudio Server (por ejemplo, http://your-ip/shiny/your-app en lugar de http://your-ip:3838/your-app) utilizando Nginx como proxy inverso, solo necesitas reemplazar el contenido de este archivo, sudo nano /etc/nginx/sites-enabled/default, con esto:

map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

server {
    listen 80 default_server;
    listen [::]:80 default_server;
    
    root /var/www/html;
    
    index index.html index.htm;
    
    server_name _;
    
    location / {
        try_files $uri $uri/ =404;
    }
    
    rewrite ^/shiny$ $scheme://$http_host/shiny/ permanent;
    
    location /shiny/ {
        rewrite ^/shiny/(.*)$ /$1 break;
        proxy_set_header    Host $host;
        proxy_set_header    X-Real-IP $remote_addr;
        proxy_set_header    X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header    X-Forwarded-Proto $scheme;
        proxy_pass          http://localhost:3838;
        proxy_read_timeout  20d;
        proxy_buffering off;
        
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        proxy_http_version 1.1;
        
        proxy_redirect      / $scheme://$host/shiny/;
    }
    
    location /rstudio/ {
        rewrite ^/rstudio/(.*)$ /$1 break;
    
        proxy_pass http://localhost:8787;
    
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        proxy_read_timeout 20d;
        proxy_buffering off;
    
        proxy_set_header X-RStudio-Root-Path /rstudio;
    
        proxy_set_header Host $host:$server_port;
    }
}

En Raspberry Pi OS, hay un problema extraño en el que Nginx se inicia antes de que RStudio Server pueda iniciarse y el proxy inverso falla. Una solución para esto es editar este archivo, sudo nano /etc/systemd/system/multi-user.target.wants/nginx.service, y reemplazar la parte que dice After=network.target con After=network-online.target y recargar el daemon con sudo systemctl daemon-reload. Puedes omitir esto si estás usando Ubuntu.

Ahora tienes que reiniciar Nginx para aplicar los cambios:

sudo systemctl restart nginx

Si deseas tener acceso a tu servidor desde orígenes remotos (a través de Internet), debes seguir estos pasos adicionales:

  • Si no tienes una IP pública estática:
    • Abre una cuenta en un servicio de DNS dinámico (por ejemplo, https://www.noip.com)
    • Configura Dynamic DNS en tu enrutador/módem, si no tiene esa opción, puedes instalar un cliente DDNS en tu servidor.
    • Opcionalmente, configura tu nombre de dominio personal para que apunte a tu servicio DDNS.
  • Si tienes un IPv4 publico, configura el reenvío de puertos en tu enrutador/módem:
    • Para SSH, SCP y SFPT, abre el puerto TCP/UDP 22
    • Si no has configurado Nginx, abre el puerto 8787 para RStudio Server.
    • Si no has configurado Nginx, abre el puerto 3838 para Shiny Server.
    • Para HTTP abre el puerto TCP 80 (también para usar Nginx como proxy inverso).
    • Para PostgreSQL abre el puerto TCP/UDP 5432
    • Asegúrate de tener “Block WAN Traffic” deshabilitado en tu enrutador/módem.

Si estás interesado, tengo un artículo que brinda un ejemplo de cómo configurar el reenvío de puertos en casa.

Comentarios finales

El soporte para arm64 en general está aumentando rápidamente, por lo que es muy probable que las cosas cambien en un futuro próximo. Voy a hacer todo lo posible para mantener este artículo actualizado con los últimos desarrollos para que puedan aprovechar los beneficios.

El rendimiento es relativamente pobre, especialmente para gráficos, pero es utilizable. Ten en cuenta que aunque la Raspberry Pi tiene 4 núcleos, no son rápidos y la mayoría de los paquetes R no usan computación paralela.

Edit this page
comments powered by Disqus