September 5, 2022

2102 words 10 mins read

Setting up your own Shiny and RStudio Server on a Raspberry Pi

Setting up your own Shiny and RStudio Server on a Raspberry Pi

This article was originally published back in 2018 and a lot has changed since then, so I have completely re-write it to take into account the most recent advancements in support for the arm64 architecture within the R ecosystem.

Back in 2018, I participated in a forum topic at Community RStudio where @jladata was asking if a Raspberry Pi 3B+ could make it as a viable Shiny server. I actually use a Raspberry Pi for that very purpose so I decided to share with the R community, my experience setting up Shiny and Rstudio Server natively on a Raspberry Pi.

In those days there was almost zero support for ARM architectures (either x32 or x64) so most of the software had to be compiled from source on the Pi itself, which makes the installation process a titanic effort with lots and lots of waiting hours.

Nowadays, things have changed and we have better support for the arm64 architecture due to community efforts and even official RStudio support in the works. In this renewed article I’m going to guide you through the installation options we have currently available.

✏️ I also have a related article showing how to automate the installation process using Ansible.

Prepare The Raspberry Pi

First, you need a 64-bit operating system for your Pi (make sure it’s 64-bit since RStudio only has support for the arm64 architecture), these installation instructions work for both Raspberry Pi OS and Ubuntu, you can download either of those using the Raspberry Pi Imager software from their official site. Also, make sure to update your system libraries with sudo apt update && sudo apt dist-upgrade before you start.

Although not mandatory, I recommend performing the following actions using the sudo raspi-config application (In Ubuntu you need to install it first with sudo apt install raspi-config):

  • Expand the filesystem (Advanced Options / Expand Filesystem).
  • Configure your locale, and make sure to choose an UTF.8 option to avoid compilation issues (Localisation Options / Locale).
  • Disable “Predictable network interfaces” (Advanced Options / Network Interface Names).

Next, you need to set a static IP for the Pi so you can easily find it on your network.

For setting a static IP on Raspberry Pi OS, run these commands. This is a sample IP configuration for a wired connection, modify accordingly with your own needs:

# Sample static IP configuration:
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'

And for setting the IP on Ubuntu you have to create this file, sudo nano /etc/netplan/01-netcfg.yaml,add this content (edit as needed) and apply the configuration with this command, 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

In case you have a low-RAM Raspberry Pi model, you have to add some swap memory for the installation process. For 1GB Pi models, 3GB of swap would be enough, you can do it with these commands:

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'

For preventing unnecessary use of swap memory and protect your SD card, open this file, sudo nano /etc/sysctl.conf, and add this line at the end:

vm.swappiness=10

Install R

You have a few options for installing R on your Pi:

  • Install from the Operating System’s repositories
  • Compile R from source
  • Install R using rig
  • Install R from the R4Pi Project

Since there are several options now I have moved this section to a separate article that you can consult here for more details.

Whenever possible (whit a compatible OS), I strongly recommend using the R4Pi package repository as your R packages source since it provides precompiled binaries that make installation easier and faster.

Install Shiny Server

Currently, shiny-server offers no ARM support so the only option for installing it on the Pi is to compile from source. There is hope this will change in the future as per the response on this GitHub Issue, but for the time being we are stuck with this.

First, you need to install the R package dependencies, if you are using a CRAN repository, this is going to take a while, but it is much quicker if you are using the R4Pi repository (available with R installed from R4Pi):

# Define your R package repository (You have to choose one of these)
# REPO="'http://cran.rstudio.com/'" # For OSes that are not compatible with R binaries build for RPi OS (Debian 12 based)
# REPO="c('https://pkgs.r4pi.org/aarch64', 'http://cran.rstudio.com/')" # For legacy RPi OS (Debian 11 based)
REPO="c('https://pkgs.r4pi.org/bookworm', 'http://cran.rstudio.com/')" # For the latest RPi OS (Debian 12 based)

# Make sure the system dependencies are installed
sudo apt install libcairo2-dev libxt-dev git cmake pandoc pandoc-citeproc-preamble

# Install required R packages as 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)\""

✏️ It’s necessary to install R packages as sudo for shiny-server to be able to use them, do not install these packages from the R console using your regular user.

Now, you can install shiny-server with these commands:

# Download the source code for the latest shiny-server release from GitHub
git clone --depth 1 --branch v1.5.20.1002 https://github.com/rstudio/shiny-server.git

# Compile the source code
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

# Modify some download links and SHASUMs for compatibility with arm64 
sed -i '8s/.*/NODE_SHA256=98d81a2d08f88646541d282b7ccc32429f8706ddcb30943fc3779ef9674ebb93/' ../external/node/install-node.sh # SHAMSUM for 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

# Install node for arm64 and rebuild node modules
(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)

# Install shiny-server
sudo make install

# Configure 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

# Edit the shiny-server.service file
sudo nano /etc/systemd/system/shiny-server.service 
    # Paste the following content
    
    [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

# Edit the shiny-server logrotate file
sudo nano /etc/logrotate.d/shiny-server 
    # Paste the following content
    
    /var/log/shiny-server.log {
       rotate 12
       copytruncate
       compress
       missingok
       size 1M
    }

# Set permissions for the files
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

# Start the service
sudo systemctl daemon-reload
sudo systemctl enable shiny-server
sudo systemctl start shiny-server

# Create symlinks for pandoc and the sample apps
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

# Set proper user permissions, I'm assuming your user is "pi", change it if it isn't
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

Install Rstudio Server

In the past, the only way to install RStudio Server on a Pi was to compile from source and this was extremely time-consuming (took me 3 days the last time I tried on a Pi 3B+) and very prone to failure because the RStudio IDE is under active development.

Luckily, in recent days, RStudio has made available “experimental” builds of the IDE for arm64 (I wrote an article about it), they are compiled for Ubuntu 20/22 LTS and RedHat 9 but the Ubuntu 22 binaries are compatible with Raspberry Pi OS as well. You can check the available daily builds here. Choose a link accordingly to the operating system you are using, also, have in mind that these builds are meant for testing so they are likely to have bugs or be unstable, if you have problems installing the latest one available, try with an older version.

The following instructions use a link for Ubuntu 22 (Raspberry Pi OS compatible), remember to change the link if you want to use another OS or a more recent IDE version:

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

✏️ I’ll update this section once the arm64 support becomes a stable feature for the RStudio IDE.

Install Additional Support Services (optional)

Nginx is a low-requirements web server, which comes in handy to self-host HTML files but also to use as a reverse proxy (more about this in the next section). You can install it with this command:

sudo apt install nginx

Also, for working with “bigger than memory” data sets (have in mind that the Pi doesn’t have much RAM), having an RDBMS comes in handy. I personally prefer PostgreSQL since it’s open-source and has impressive capabilities, you can install PostgreSQL with this command:

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

Extra Steps (optional)

Make pretty URLs for Shiny and Rstudio Server (e.g. http://your-ip/shiny/your-app instead of http://your-ip:3838/your-app) by using Nginx as a reverse proxy, you only need to replace the content this file, sudo nano /etc/nginx/sites-enabled/default, with this:

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;
    }
}

On Raspberry Pi OS there is a weird issue where Nginx starts before RStudio Server is able to start, and the reverse proxy fails. A walk-around for this is to edit this file, sudo nano /etc/systemd/system/multi-user.target.wants/nginx.service, and replace the part that says After=network.target with After=network-online.target and reload the daemon with sudo systemctl daemon-reload. You can omit this if you are using Ubuntu.

Now you have to restart Nginx to apply the changes:

sudo systemctl restart nginx

If you want to have access to your server from remote origins (over the internet) you must follow these extra steps:

  • If you don’t have a static public IP:
    • Open an account in a Dynamic DNS Service (e.g. https://www.noip.com)
    • Configure Dynamic DNS in your router/modem, if you don’t have that option, you can install a DDNS client on your server.
    • Optionally configure your personal domain name to point to your DDNS service
  • If you have a public IPv4, configure port forwarding in your router/modem:
    • For SSH, SCP and SFPT open port TCP/UDP 22
    • If you haven’t configured Nginx, open port 8787 for RStudio.
    • If you haven’t configured Nginx, open port 3838 for Shiny server.
    • For HTTP open port TCP 80 (also for using Nginx as a reverse proxy).
    • For PostgreSQL open port TCP/UDP 5432
    • Make sure you have “Block WAN traffic” disabled on your router/modem.

If you are interested, I have an article that provides an example of how to configure port forwarding at home.

Final Comments

Arm64 support in general is increasing rapidly, so very likely things are going to change in the near future. I’m going to try my best to keep this article up to date with the latest developments so you can leverage the benefits.

Performance is relatively poor, especially for plotting, but usable. Keep in mind that even though the Raspberry Pi has 4 cores they are not fast ones and most of the R packages don’t use parallel computing.

Edit this page
comments powered by Disqus