Hosting Flask Apps on Nginx

Hi there, in this article, we would be looking at how to host a Flask app on Nginx (a webserver) on an Ubuntu Virtual Machine.

A webserver is a computer that has web server software installed (Apache, Nginx, Microsoft IIS) and serves resources, which could be webpages or multimedia files, over the web, to fulfill client's requests over the internet.

Nginx is a webserver that can be used as reverse proxy, load balancer, mail proxy and HTTP Cache. It is widely used due to it's ability to scale websites better.

The first thing, we do is to provision an Ubuntu Virtual Machine (I use Microsoft Azure) and then login to it via SSH.

To follow along with this article, you are expected to have a flask application already built and in a git repository. If you don't, you could use this

We then run the following command to update our repositories:

sudo apt update

Dependig on the version of your Ubuntu VM, you might want to upgrade your Python version. After this, we continue with the steps below:

  • Step 1: We clone our app's GitHub repository into our VM:

    sudo apt update
    git clone <repo-url>
    
  • Step 2: We change our directory's name to app

    ls
    mv <repo-name>/ app
    

    (The ls command is to list all the files and directories in our current work environment)

  • Step 3: We cd into our directory, create a virtual environment and activate it

    sudo apt-get install python3-venv
    python3 -m venv <virtual-environment-name>
    source <virtual-environment-name>/bin/activate
    
  • Step 4: We install the requirements in our requirements.txt file

    pip3 install -r requirements.txt
    

run pip3 list to see a list of all installed dependencies

If uWSGI does not install, run the following;

sudo apt-get install build-essential python3-dev
pip3 install uwsgi

So far, so good!

  • Step 5: Now, we check if our app runs on uwsgi, but first we have to set our Uncomplicated Fire Wall (ufw) to allow both incoming and outgoing connections on port 9090, the port we would be making use of.
sudo ufw enable
sudo ufw allow 9090

Expected result:

image

Running sudo ufw status shows us the current state of our firewall; whether it is active or not and the ports our firewall gives us access to.

  • Step 6: run the following
    uwsgi dev.ini
    
  • You might see the following in the output: image

run this,

sudo apt-get install libpcre3 libpcre3-dev
pip3 install uwsgi -I --no-cache-dir

then re-run the command

uwsgi dev.ini

In your browser visit

<vmipaddress>:9090/

We expect to see our Flask app displayed via this port.

  • Step 7: we delete the firewall rule and deactivate our virtual environment

    sudo ufw delete allow 9090
    deactivate
    
  • Step 8: install nginx

    sudo apt install Nginx
    

    Now, we check the apps recognized by ufw and instruct it to allow for connection to Nginx:

    sudo ufw app list
    sudo ufw allow 'Nginx HTTP'
    

To confirm if Nginx was properly installed, we type our VM's IP address in our browser.

Expected result: image

Omoshiroi...

  • Step 9: we create systemd unit file to reboot the server running our app
    sudo nano /etc/systemd/system/<custom-name-of-service-app>.service
    
    Example:
    sudo nano /etc/systemd/system/app.service
    
    And type in the following contents in our file:
[Unit]
Description=A simple Flask uWSGI application
After=network.target

[Service]
User=<yourusername>
Group=www-data
WorkingDirectory=/home/<yourusername>/app
Environment="PATH=/home/<yourusername>/app/venv/bin"
ExecStart=/home/<yourusername>/app/venv/bin/uwsgi --ini <name-of-app-ini file>

[Install]
WantedBy=multi-user.target
  • Step 10: we enable the service file we just created
    sudo systemctl start <name-of-app>
    sudo systemctl enable app <name-of-app>
    

Expected output: image

To check if the file is running, type:

sudo systemctl status app

Also if a mistake is made in our service file and we correct it, we have to reload the daemon and restart systemctl

image

  • Step 11: we configure nginx by creating a config file

    sudo nano /etc/nginx/sites-available/<name-of-file>
    

    And type in the following contents:

    server {
    listen 80;
    server_name <your_ip_address> <your_domain_name>;
    
    location / {
        include uwsgi_params;
        uwsgi_pass unix:/home/<username>/app/app.sock;
    }
    }
    

To check if there are any errors in our nginx configuration file, we run sudo nginx -t image

  • Step 12: we link our config file to sites-enabled directory (Nginx server blocks configuration files are stored in /etc/nginx/sites-available directory, which are enabled through symbolic links to the /etc/nginx/sites-enabled/ directory):
    sudo ln -s /<path-to-config-file>/<config-file-name> /etc/nginx/sites-enabled
    
    Example:
    sudo ln -s /etc/nginx/sites-available/app /etc/nginx/sites-enabled/
    

Running a syntax check at this point, comes in handy

  • Step 13: we restart nginx for our changes to take effect
    sudo systemctl restart nginx
    
    In our browser, we type in our VM's IP address without adding a port becase in our nginx config file, we have defined a port for nginx to listen on

tada!! image IP address

image Azure custom domain name

Feel free to share your IP address with friends to check out your app

Thank you for your time!!!

Find below the GitHub repo for this task: Github repo

Feel free to connect with me via Linkedin

Gokigen'yō