Host Web App

Connect to the instance

Connect to the instance using the following command. Replace <Your Public DNS(IPv4) Address> with your instance’s public DNS address.

chmod 400 myGPT.pem
ssh -i "myGPT.pem" ubuntu@ec2-54-151-28-127.us-west-1.compute.amazonaws.com

Now we install miniconda:

sudo apt-get update
wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O ~/miniconda.sh
bash ~/miniconda.sh -b -p ~/miniconda
echo "PATH=$PATH:$HOME/miniconda/bin" >> ~/.bashrc
source ~/.bashrc

Get the code from our repository and install the requirements.

git clone XYZ
pip install -r requirements.txt

Tmux

sudo apt-get install tmux
tmux new -s StreamSession  # create a new session called StreamSession
tmux list-sessions  # to discover sessions
tmux attach -t StreamSession  # to reatach
tmux kill-session -t StreamSession  # to kill session

To leave tmux session, press Ctrl+b and then d.

Add DNS name

One option is to add subdomain, for example mygpt.nenadbozinovic.com will now go to IP address of the EC2 instance. The port will be 80 by default.

dns

Prep instance for remote control via aws ssm

First we need to assume user role, which is done by specifying AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY. And we need to make sure this user has the necessary permissions to send command, by attaching SendCommand policy to the user.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "ssm:SendCommand",
            "Resource": "*"
        }
    ]
}

We need to create keygen and add it to GitHub, checkout blog and add it the safe list:

git clone git@github.com:nesaboz/blog.git
sudo timedatectl set-timezone America/Los_Angeles  # set the timezone
timedatectl status
TZ='America/Los_Angeles' date
find . -name output.log

optional, we can add our repo directory (in my case blog) to the safe list:

sudo git config --system --add safe.directory /home/ubuntu/blog
ssh-keyscan github.com >> ~/.ssh/known_hosts  # add github.com to known hosts is obtained from output of: git remote -v

We also need to make sure instance can accept commands, this should be default and done by snap, double check it is installed, enabled, and active:

snap services amazon-ssm-agent

We need to run streamlit so we need to execute these commands:

git -C ~/blog pull
streamlit run ~/chatbot/myGPT.py --server.enableCORS false --server.enableXsrfProtection false

Note that --server.enableCORS false --server.enableXsrfProtection false reduces security but allows app to run on servers. One can get away running without the flags too.

At this point we should verify myGPT is running fine.

However, to run these commands remotely, it might seem easy, but there are few more things to do: - when we call git command remotely it will execute with different user, so we need to specify user, in this case ubuntu, - we need to kill the previous streamlit process, if it is running, since only one version counts when accessing URL (other apps would run at ports 8502 that are not even exposed), - we need nohup call so the process can run in the background (similar to tmux above), - we need to specify path to streamlit, since it is not in the PATH

  • we should also redirect output to a file so we can see what is happening

So the command looks like this:

sudo -u ubuntu git -C /home/ubuntu/blog pull
sudo pkill -f streamlit
nohup /home/ubuntu/miniconda/bin/streamlit run /home/ubuntu/chatbot/myGPT.py --server.enableCORS false --server.enableXsrfProtection false

We should also append everything to a log file, and add a date to the beggining:

date > /home/ubuntu/output.log
sudo -u ubuntu git -C /home/ubuntu/blog pull >> /home/ubuntu/output.log 2>&1
sudo pkill -f streamlit >> /home/ubuntu/output.log 2>&1
nohup /home/ubuntu/miniconda/bin/streamlit run /home/ubuntu/chatbot/myGPT.py --server.enableCORS false --server.enableXsrfProtection false >> /home/ubuntu/output.log 2>&1

The > rewrites output.log and >> appends while 2>&1 redirects both stderr to stdout:

>> /home/ubuntu/output.log 2>&1

Put it all together in aws ssm

So now that we have commands, let’s execute remote command using AWS Systems Manager (or aws ssm):

aws ssm send-command \
    --document-name "AWS-RunShellScript" \
    --targets "Key=instanceids,Values=i-08b8b6691ed2e1b6d" \
    --parameters commands="date > /home/ubuntu/output.log && sudo -u ubuntu git -C /home/ubuntu/blog pull >> /home/ubuntu/output.log 2>&1 && sudo pkill -f streamlit >> /home/ubuntu/output.log 2>&1 && nohup /home/ubuntu/miniconda/bin/streamlit run /home/ubuntu/chatbot/myGPT.py --server.enableCORS false --server.enableXsrfProtection false >> /home/ubuntu/output.log 2>&1" \
    --region us-west-1

We can now go to the remote machine and check the output.log:

(base) ubuntu@ip-172-31-18-61:~$ cat output.log 
Thu Feb  8 17:56:43 PST 2024
Already up to date.
  Stopping...

Collecting usage statistics. To deactivate, set browser.gatherUsageStats to False.


  You can now view your Streamlit app in your browser.

  Network URL: http://172.31.18.61:8501
  External URL: http://54.151.28.127:8501

we can see what is running on the instance:

ps aux | grep -E "streamlit|PID"
kill <PID>  # if you need to

the output looks like this:

(base) ubuntu@ip-172-31-18-61:~$ ps aux | grep -E "streamlit|PID"
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root       33774  0.1 13.9 623640 135188 ?       Sl   00:55   0:01 /home/ubuntu/miniconda/bin/python /home/ubuntu/miniconda/bin/streamlit run /home/ubuntu/blog/nbs/projects/myGPT/myGPT.py --server.enableCORS false --server.enableXsrfProtection false
ubuntu     33856  0.0  0.2   7004  2304 pts/0    S+   01:15   0:00 grep --color=auto -E streamlit|PID

the process with user root is the one that we started remotely, it is taking 0.1% of CPU and 13.9% of the memory.