• Yash Vishwakarma

Step-by-step guide for deploying a Flask application on Ubuntu using Gunicorn and Nginx

In this blog, we will be making a very simple flask application and will learn how to setup a Gunicorn server to launch the application. We will configure Nginx to act as frontend reverse proxy for our application.


Prerequisites:

  • A server with ubuntu installed.

  • Nginx installed. You can do this by running:

sudo apt update
sudo apt install nginx
  • A domain name configured to point to your server. You can easily get a free domain from Freenom. Make sure you create a ‘A’ record pointing to your server’s public IP address.


Step 1 – Installing all the required dependencies:

First let’s update the local package:


$ sudo apt update

Then we will install all the packages that you need along with python to build a development environment. These include ‘pip’ along with a few more packages. Do it by running:


$ sudo apt install python3-pip python3-dev build-essential libssl-dev libffi-dev python3-setuptools


Step 2 – Creating a virtual environment:

Next, let's create a virtual environment for our flask application to reside in. Let’s start by using the

virtual environment package ‘venv’:


$ sudo apt install python3-venv

Next, let’s make a new directory for our flask project. If you are cloning a project that you need to deploy, I suggest you do that before starting the virtual environment.


$ mkdir flask-project

Then change into the directory after you create it:


$ cd flask-project

Create a virtual environment to store the requirements for your flaks project:


$ python3 -m venv venv

This will create a virtual environment named venv within your project directory.

Now let’s activate this virtual env:


$ source venv/bin/activate

Your command prompt will change and you will see the name of your virtual environment in parenthesis.




Step 3 – Setting up a Flask application.

Now that we have enabled a virtual environment, let's install Flask and make a very simple web application that says “Hello World!”. You can also alternatively clone a flask project in here and install it’s requirements.

Let’s install Flask and Gunicorn:


(venv)$ pip install flask gunicorn

With this, we have successfully installed the packages for Flask and Gunicorn in our virtual environment.


Creating a simple Application:

We need to keep in mind that flask is a micro framework and hence it does not include many tools that other much more powerful frameworks may. While your application might be more complex, for this demonstration, we will create a simple single page application. We will need just a single python file for this that we will call “app.py”. Also, we are using the ‘nano’ text editor:


(venv)$ sudo nano app.py

The application will live in this file.


from flask import Flask
app = Flask(__name__)

@app.route('/', methods=['GET'])
def hello():
        return "<h1>Hello World!</h1>"

if __name__ == "__main__":
        app.run(debug=True, host='0.0.0.0', port=8080)


This defines what content to present when the root domain is accessed. Here we are running the app on port number 8080 but you can run it on any other port you wish to. Save and close the file when you’re finished. If you’re using nano, you can do this by using CTRL + O to then Enter to save the file and then CTRL + X and Enter to exit nano.

Then you can test your Flask application by running the following:


$ python app.py

You should see an output similar to:



Visit your server’s IP address followed by :8080 in your web browser

http://your_server_ip:8080

You should see something like the following:



When you are finished, hit CTRL + C in your terminal to stop the Flask development server.



Step 4 – Configure Gunicorn:

Gunicorn is a python WSGI HTTP Server for UNIX. The Gunicorn server is broadly compatible with various web frameworks including Flask. You can learn more about Gunicorn from: https://gunicorn.org/


First let’s check if Gunicorn can serve the application correctly by passing it the name of our application. In case you have multiple files in your flask project, you may have to create an entry point for the same.

To check gunicorn’s ability to serve your application, run:


(venv)$ gunicorn –bind 0.0.0.0:8080 app:app

You should see an output similar to:



Visit your server's IP once again followed by the port number 8080.

http://you_server_ip:8080

You will see the output as:




Once you are done, press CTRL + C to end the process.

We don’t need the virtual environment anymore and we can deactivate it. To deactivate the virtual env run the following command:


(venv)$ deactivate

Now let’s create a system unit file. Creating a system unit file allows the Ubuntu's unit system to automatically serve the flask application whenever the server boots up.

Create a unit file ending with the extension ‘.service’ within the /etc/system/system directory to begin:


$ sudo nano /etc/system/system/flask-project.service

Inside, start with the [Unit] section, which is used to specify metadata and dependencies. Add a description of your service here and tell the ‘Unit’ system to only start this after the networking target has been reached:


[Unit]
Description=Gunicorn instance to serve flask-project
After=network.target


Next, create a [Service] section. This will specify the user and group that you want the process to run under. Provide your regular user account ownership of the process since it owns all of the relevant files. Also, give group ownership to the www-data group so that Nginx can communicate with the Gunicorn processes. Remember to replace the username here with your own username:

CODE:


[Unit]
Description=Gunicorn instance to serve flask-project
After=network.target

[Service]
User=ubuntu
Group=www-data
WorkingDirectory=/home/ubuntu/flask-project
Environment="PATH=/home/ubuntu/flask-project/venv/bin"
ExecStart=/home/ubuntu/flask-project/venv/bin/gunicorn --workers 1 --bind unix:flask-project.sock -m 007 app:ap


In this, we map out the working directory and set the PATH environment variable so that the init system knows that the executables for the process are located inside your virtual environment. The ExecStart is the command to just start the process. In this case the command will start just 1 worker process, create and bind to a unix socket file, flask-project.sock, within your project directory. Also set an umask value of 007 so that the socket file is created to give access to the owner and group, while restricting other access.

Systemd requires that you give the full path to the gunicorn executable, which is installed within your virtual environment.

Finally, add an [Install] section. This will tell systemd what to link this service to if you enable it to start at boot. You want this service to start when the regular multi-user system is up and running:

CODE:


[Unit]
Description=Gunicorn instance to serve flask-project
After=network.target

[Service]
User=ubuntu
Group=www-data
WorkingDirectory=/home/ubuntu/flask-project
Environment="PATH=/home/ubuntu/flask-project/venv/bin"
ExecStart=/home/ubuntu/flask-project/venv/bin/gunicorn --workers 1 --bind unix:flask-project.sock -m 007 app:app

[Install]
WantedBy=multi-user.target


Now your system file is complete. Save and close it.

Now let’s start the gunicorn service that you have created:


$ sudo systemctl start flask-project

Then enable it so that it starts at boot:


$ sudo systemctl enable flask-project

Check the status:


$ sudo systemctl status flask-project

You should receive the output similar to:



If it is not Active or you receive any other errors, solve them before moving on.



Step 5 – Configure Nginx to Proxy Requests

Now your gunicorn application server is up and running, waiting for requests on the socket file in the project directory. Next let’s configure Nginx to pass requests to that socket file.

Begin by creating a new server block configuration file in Nginx’s sites-available directory. We’ll call this flask-project to stay consistent with the rest of the guide:


$ sudo nano /etc/nginx/sites-available/flask-project

In this file we will open up a server block and tell Nginx to listen on the default port 80. Also tell it to use this block for requests for your server’s domain name.

We will also add a location block that matches every request. Within this block, include the “proxy_params” parameter that specifies some general proxying parameters that need to be set. Then, pass the requests to the socket you defined using the proxy_pass directive:


server {
    listen 80;
    server_name your_domain;

    location / {
        include proxy_params;
        proxy_pass http://unix:/home/ubuntu/flask-project/flask-project.sock;
    		}
 }


Save and close this file.

To enable this Nginx block configuration that we have just written, link the file to the sites-enabled directory. You can do this by running the following command:


$ sudo ln -s /etc/nginx/sites-available/flask-project /etc/nginx/sites-enabled

With the link to the directory created, you can now test your Nginx file for syntax errors.


$ sudo nginx -t 

If you have any errors make sure to solve them before moving on.

Restart the Nginx process to read the new-configuration:


$ sudo systemctl restart nginx

Then allow full access to the Nginx server:


$ sudo ufw allow ‘Nginx Full’

Now if you go to http://yourdomain in your browser, you will see your website up and running.




527 views0 comments

Recent Posts

See All

PEP8