Epistemic Noise
All articles

Production

Deploy multiple Flask Applications using Nginx and Gunicorn

This blog post is a step-by-step tutorial on how to deploy multiple Flask Applications on a Linux server using Nginx and Gunicorn.

I suppose you already have a server that you can ssh to using an IP address. I also assume that you have a basic understanding of creating Flask apps. The VPS I’m using in this tutorial runs on Ubuntu.

Local machine

In my local machine, I have a Flask app that I want to deploy on my remote VPS (actually I have two apps, but let’s just focus on one application at the moment).

My application is located in a directory named chatbot, which contains the main Flask app file (app.py), my virtual environment (chatvenv), and some helping files. So, in my local machine, I use the scp command to copy all my project's files to the remote server.

scp -r Desktop/chatbot ubuntu@IP_ADDRESS:~/

Bear in mind that, depending on your server configuration, you might be asked to provide a password. Also, make sure you change your local path, as well as the username and IP address of your remote server.

Virtual Private Server

Let’s now connect to our VPS:

ssh ubuntu@IP_ADDRESS
sudo apt install python3-pip
sudo apt install python3-venv
python3 -m venv chatvenv
source chatvenv/bin/activate
pip install -r requirements.txt
export FLASK_APP=app.py
flask run --host=0.0.0.0

You can check if everything is going well by trying to reach out to your application through the browser: http://IP_ADDRESS:5000/

Nginx and Gunicorn

There are two problems with our approach so far. First, Flask is running in development mode. Second, the application is running in the foreground, and if we hit ^C to get back our terminal, the application will no longer be reachable.

To handle this we’ll use a web server (Nginx), a Web Server Gateway Interface (Gunicorn), and daemonize our execution so that the app will be running in the background.

sudo apt install nginx
pip install gunicorn
cd ~/chatbot
gunicorn --bind 0.0.0.0:5000 app:app

Note that in the last command, the first app refers to the name of the flask app file, while the second app refers to the name you used inside that file to create the application: app = Flask(__name__).

It’s time now to allow Ubuntu’s init system to automatically start Gunicorn and serve the Flask app whenever the server boots.

# /etc/systemd/system/chatbot.service
[Unit]
Description=Gunicorn instance to serve chatbot
After=network.target
 
[Service]
User=ubuntu
Group=www-data
WorkingDirectory=/home/ubuntu/chatbot
Environment="PATH=/home/ubuntu/chatbot/chatvenv/bin"
ExecStart=/home/ubuntu/chatbot/chatvenv/bin/gunicorn --workers 3 --bind unix:chatbot.sock -m 007 app:app
 
[Install]
WantedBy=multi-user.target
sudo systemctl start chatbot
sudo systemctl enable chatbot
sudo systemctl status chatbot

Configure Nginx to proxy requests

# /etc/nginx/sites-available/chatbot
server {
  listen 80;
  server_name IP_ADDRESS;
 
  location / {
    include proxy_params;
    proxy_pass http://unix:/home/ubuntu/chatbot/chatbot.sock;
  }
}
sudo ln -s /etc/nginx/sites-available/chatbot /etc/nginx/sites-enabled
sudo nginx -t
sudo systemctl restart nginx
sudo ufw allow 'Nginx Full'

Finally, you can check your app at http://IP_ADDRESS.

Add another Flask application

Move the second Flask application to the VPS, create another virtual environment, then another systemd service — this time betapp — bound to a unix socket.

For Nginx, pick another port than 80 (here 5000):

server {
  listen 5000;
  server_name IP_ADDRESS;
 
  location / {
    include proxy_params;
    proxy_pass http://unix:/home/ubuntu/betapp/betapp.sock;
  }
}

Restart Nginx, and visit your two applications at http://IP_ADDRESS and http://IP_ADDRESS:5000.

Conclusion

Flask APIs are excellent tools for putting your trained machine learning models into production. In this tutorial we went through the process of how to deploy Flask apps using Nginx and Gunicorn.