Post

Deploying Shiny for Python App as an AWS Web Application

Overview

This guide will take you step by step into deploying your Shiny for Python Application into an AWS EC2 instance.

Throughout the guide, there will be screenshots that may be difficult to see. Just click on the images to view the text contained in them more clearly.

The guide assumes that you have a working Shiny Application able to run on a local enviornment. If this is not the case, make sure you test your application ahead of deployment to make sure that it works.

It is recommended that you upload your Shiny Application to Github (or any other remote repository) so that it is easier copying files from your local machine to AWS servers.

It is also recommended that you have a requirements.txt file from your local python virtual environment to make downloading dependecies on the server easier.

Setup an AWS Account

This won’t be covered in this document but you can find plenty of videos or articles of going through the steps of registering for AWS. New accounts should have access to some free credits on EC2 so this should cost nothing or very little depending on how long you plan to keep the server up.

Start an EC2 Instance

EC2 is Amazon Web Service’s general compute server service. We can use an EC2 instance as a way to run a web server, run our machine learning model, display visualization, and store files all in one place. While AWS offers many other services that specialize in some aspects of these areas, EC2 is a hassle free way to run a working prototype.

Note that the layout and placement of buttons on the AWS websites can change drastically at a later time from publishing, but most principles should stay consistent.

When you enter your AWS dashboard it should look like this:

EC2 dashboard

To start an EC2 instance, search for “EC2” in the search bar of the dashboard and you should see these options

EC2 search

Click on EC2 under Services and it should bring you into the EC2 Dashboard. Here we can launch instances of our servers. To do ths click on the bright orange button that says “Launch instance”

EC2 dashboard

It brings you to a page where you can set up settings needed to launch an instance.

EC2 instance

The first step is to name your instance. Here we will name ours shiny-webserver but this can be whatever you would like.

We will also select Ubuntu under Application and OS Images. You can use any major linux distribution (Red Hat/CentOS, Ubuntu, openSUSE) that is compatible with Shiny Server but since Ubuntu has a large community around it, this will be our choice.

EC2 instance type

Next we will keep our instance type as the default option t2.micro, but depending on your use case you can change how powerful you would like the server you launch to be. Since t2.micro has a free tier eligible, we will just keep that as is

EC2 keypair

Key pair is a way to log into our server without needing a password, but using a file to authenticate instead. This is required so we will set up a key pair login. Click on Create new key pair

EC2 create keypair

We will name our key pair shinykey, set the key pair type to ED25519 (optional), and keep it as the default .pem file format.

Click Create key pair and it should be downloaded from your browser.

Move it into a safe folder that you will remember later. We will need to know where this key file is to log into our server later.

EC2 network settings

Next, we set up our network settings. This part is crucial to exposing the right ports to our server to the internet.

There are two options here depending on how far you want to go with your deployment.

Option 1) If you aren’t sure how to set up reverse proxies, like nginx and SSL certs and just want to get the app running, check the box that says Allow HTTP traffic from the internet to open up port 80.

Some web browsers will default to HTTPS and will block HTTP websites. You will get an ugly “Secure Site Not Availible” Warning if you do not set up SSL certs. While this does not ruin the functionality of the app, if you want to follow the recommended step and set up HTTPS with SSL certificates, follow option 2 below.

Option 2) If you intend to set up both a reverse proxy and SSL certificates, which is highly encouraged when setting up a reverse proxy, check the box that says Allow HTTPS traffic from the internet. This opens up port 443 for HTTPS connections.

Now, there are additional configurations to the network we need to make. Click on Edit at the top right corner next to the title Network settings and you will see the expanded menu.

EC2 network settings expanded

Scroll down a bit to the button that says Add security group rule at the bottom of Inbound Security Group Rules

Click Add security group rule

EC2 network settings add port 3838

We want to set a rule that exposes port 3838 that is used by the Shiny Server. To do this we select Custom TCP as the type, Anywhere as the source type and add 3838 to the Port range.

After this is done, we are basically done with setting up our server.

EC2 storage

EC2 will ask us to configure our storage volumes, but we will leave it as the default option. Unless you specifically know that you will need more storage due to model/project size, 8 GiB should be fine.

Click the orange Launch instance button on the right, and your EC2 instance should spin up.

Go back to your EC2 dashboard by expanding the left sidebar and clicking Dashboard at the top.

Look under the Resources section and click Instances (running) to see your new instance.

EC2 instances There appears to be two running instances in this image but this was just one that was running from before on my account

Click on the instance ID of your shiny-webserver to open up more information on your instance.

EC2 instance info

Connect to EC2 Instance

To connect to this webserver we can click the white box that says Connect on the top right of the page.

EC2 instance connect info

Here it tells you the steps to connect to the EC2 instance through SSH.

Make sure you have OpenSSH installed (it should come as default in most systems including Windows)

Follow the steps given above and SSH into your ec2 instance.

EC2 instance ssh Example commands of how to run in modified wsl environment

EC2 instance ssh fingerprint

Be sure to say yes to the the fingerprinting so that the instance can add you to a list of known hosts.

EC2 instance ssh success

Now we are successfully SSH’d into our EC2 instance!

Environment Setup

First, we will update our linux host by running:

1
sudo apt update && sudo apt upgrade

Set up Shiny Server

We will install Shiny Server from the instructions here

  1. Select Ubuntu as your server version
  2. If you are running only Shiny for Python apps, you can skip installing the Shiny R package (as referenced here)
  3. Install Shiny Server by running the following commands.
1
2
3
4
5
6
7
   sudo apt-get install gdebi-core

   wget https://download3.rstudio.org/ubuntu-18.04/x86_64/shiny-server-1.5.22.1017-amd64.deb

   sudo gdebi shiny-server-1.5.22.1017-amd64.deb

   sudo systemctl enable shiny-server

sudo systemctl enable shiny-server makes sure that Shiny Server automatically runs at boot time when the instance restarts.

Verify that the app is running by going to your to your instance’s Public IPv4 Address or Public IPv4 DNS appended by :3838 on your browser.

The Public IPv4 Address or Public IPv4 DNS can be found in the instance summary of your instance.

EC2 instance info

For example: http://98.84.181.154:3838 or http://ec2-98-84-181-154.compute-1.amazonaws.com:3838

Note that the URLs use http and not https. If you do not include this part, there is a high chance that the website will not connect, so make sure your URL are in the form http://<Insert your Public IPv4 Address/DNS Here>:3838

HTTP warning

If you encounter a page like this, click Continue to HTTP Site

Shiny Server boilerplate

You should be able to see that page for Shiny Server appears. If you see errors in the right column, you can safely ignore it.

Troubleshooting

If you don’t see any website, first make sure the URL is correct, then check if the Shiny Server is running correctly by running:

1
2
sudo systemctl restart shiny-server
sudo systemctl status shiny-server

If it is not active, check your config file exists at /etc/shiny-server/shiny-server.conf . If not, follow the instructions to set up the Default Configuration here, but change run_as shiny; to run_as ubuntu and then run

1
sudo systemctl restart shiny-server

Setup Shiny App

Now we will be setting up our shiny app in this environment.

First, make sure that git is install in the system

1
sudo apt install git

Next, we make sure that python3, pip, vnev (for python virtual environment) is installed in the system.

1
2
3
4
5
sudo apt install python3

sudo apt install python3-pip

sudo apt install python3-venv

Since now we have our necessary packages installed, clone your remote Git repository where your shiny app resides onto the local system.

1
git clone <repository name>.git

When you ls you should see only 2 directories, your repository and the shiny server debian package (which you can ignore).

Example directory structure in /home/ubuntu:

1
2
3
4
5
6
7
8
9
10
11
12
13
.
├── home-valuations-ML-deployment (my git repository)
│   ├── ...
│   ├── models
│   │   ├── avm_model.json
│   │   └── avm_model_features.json
│   └── shiny-dashboard
│       ├── __pycache__
│       ├── app.py
│       ├── ...
│       ├── requirements.txt
│       └── shared.py
└── shiny-server-1.5.22.1017-amd64.deb

Setup Python Virtual Environment

We need to set up python virtual environment for our shiny app.py to run in.

To set that up, we will add it into the same directory as our shiny app.

Note that the location of the virtual environment does not matter, so feel free to install it where it is comfortable for you. We only have to remember where we put it so that we can link our python interpreter to the Shiny Server.

After cd ing into our shiny-dashboard directory, to create our python virtual environment, we run:

1
python3 -m venv shinyvenv

Our directory structure should look like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
.
├── home-valuations-ML-deployment
│   ├── ...
│   ├── models
│   │   ├── avm_model.json
│   │   └── avm_model_features.json
│   └── shiny-dashboard
│       ├── __pycache__
│       │   ├── ...
│       │   └── shared.cpython-313.pyc
│       ├── app.py
│       ├── ...
│       ├── requirements.txt
│       ├── shared.py
│       └── shinyvenv
│           ├── bin
│           ├── include
│           ├── lib
│           ├── lib64 -> lib
│           └── pyvenv.cfg
└── shiny-server-1.5.22.1017-amd64.deb

To activate this environment we run:

1
source shinyvenv/bin/activate

from the parent directory of our shinyvenv (A.K.A shiny-dashboard)

The environment is activated. You can check by making sure the beginning of the shell prompt has shinyvenv indicated like this: (shinyvenv) ubuntu@ip-172-31-25-18:~/home-valuations-ML-deployment/shiny-dashboard$

Next, you want to install python dependencies for the project.

Here I will use my requirements.txt file that I exported during my local python virtual environment here to install my dependencies. If you do not have this, you will have to manually install all the dependencies using pip.

1
pip install -r requirements.txt

At this point you can try running the shiny app, but you won’t be able to see the dashboard because shiny run’s default port is set to 4000 and 4000 is not exposed on our server.

Q: Why do we even need shiny server if you can just run shiny directly and expose port 4000?

A: The shiny dashboard does not render ui items correctly if you use shiny directly. You will get a bunch of unrendered HTML and need to use shiny server to get full functionality.

“Move” Git Repsitory to default Shiny Server Path

Shiny Server finds shiny applications by default in this location: /srv/shiny-server/

We want to move our repository to that directory, but copying it takes time and storage. We can “move” the location of the repository without actually moving it or copying it by using symbolic links.

Symbolic links are like shortcuts so we can store the shortcut link in the /srv/shiny-server/ path while still having our repository in /home/ubuntu/

To achieve this we use ln -s command like this:

1
sudo ln -s /home/ubuntu/<repository name> /srv/shiny-server/<repository name>

For me it would be:

1
sudo ln -s /home/ubuntu/home-valuations-ML-deployment /srv/shiny-server/home-valuations-ML-deployment

This creates a bridge between /srv/shiny-server/home-valuations-ML-deployment to /home/ubuntu/home-valuations-ML-deployment

Setup Shiny Server Config

We need to set up the configuration on Shiny Server so it uses the python interpreter inside our virtual environment and knows where our shiny app is located. Read more about the config file in section 2 of the Shiny Server Admin Guide.

The default configuration file is found in /etc/shiny-server/shiny-server.conf

To edit this file we will use the command

1
sudo nano /etc/shiny-server/shiny-server.conf

We edit the config file to be:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Instruct Shiny Server to run applications as the user "ubuntu"
run_as ubuntu;

# Define a server that listens on port 80
server {
  listen 80;

  # Define a location at the base URL
  location / {

    python /srv/shiny-server/<enter your repository name here>/<path to your venv directory>;
    # Host the directory of Shiny Apps stored in this directory
    site_dir /srv/shiny-server/<enter your repository name here>/<path to your shiny app directory>;

    # Log all Shiny output to files in this directory
    log_dir /var/log/shiny-server;

    # When a user visits the base URL rather than a particular application,
    # an index of the applications available in this directory will be shown.
    directory_index on;
  }
}

We change the port number to use the standard HTTP port 80. We also set location of the python interpreter path for shiny to the virtual environment python location and set the shiny app directory so that the shiny server can find our app.

Don’t forget any semi-colons at the end of each line

An example of my config file is here:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Instruct Shiny Server to run applications as the user "ubuntu"
run_as ubuntu;

# Define a server that listens on port 80
server {
  listen 80;

  # Define a location at the base URL
  location / {

    python /srv/shiny-server/home-valuations-ML-deployment/shiny-dashboard/shinyvenv;
    # Host the directory of Shiny Apps stored in this directory
    site_dir /srv/shiny-server/home-valuations-ML-deployment/shiny-dashboard;

    # Log all Shiny output to files in this directory
    log_dir /var/log/shiny-server;

    # When a user visits the base URL rather than a particular application,
    # an index of the applications available in this directory will be shown.
    directory_index on;
  }
}

Restart the Shiny Server for the config file to take effect.

1
sudo systemctl restart shiny-server

Check if the Shiny Server has restarted correctly.

1
sudo systemctl status shiny-server

If everything looks good, check your URL to see if your shiny dashboard is up. The URL is slightly different this time from the previous time we opened the webpage. This time it is http://<Insert your Public IPv4 Address/DNS Here> without the :3838

Example: http://98.84.181.154 or http://ec2-98-84-181-154.compute-1.amazonaws.com

If this doesn’t work try it with :80 appended to your URL

You should see your Shiny dashboard!

shiny dashboard

Setup Reverse Proxy with Nginx

WORK IN PROGRESS

Set up SSL Certificate and Renewal

Instruction Here using Certbot

1
sudo certbot --nginx

to setup both certbot and nginx

This post is licensed under CC BY 4.0 by the author.