Run a Flask App with WSGI and NGINX on EC2

In the previous post titled Create a Simple Flask App on EC2, we create a simple Hello World Flask app and deployed it on an EC2 instance. On running our app, we say a warning message that read –

WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.

What this is telling us is that, while Flask has an inbuilt web server and serves our purpose for development, it is not suitable for production. In this post, we will further our previous post, and use WSGI server to talk to our Flask app and NGINX to handle the traffic between WSGI server and our web browser.

At this point, the assumption is that we already have our EC2 instance running, our virtual environment (named flask_env) has been created and sourced and we have our basic Hello World Flask app ready and tested. Let us take this further so that we are using a production kind set up and can hit our app from a web browser using the EC2 instance’s public ip instead of setting up tunnel like we did before.

Step1: Install WSGI

Once we ssh into out EC2 install, have our virtual env sourced, we will install WSGI using pip as shown below.

(flask_env) ubuntu@xxxx:~/flask_test$ pip3 install WSGIserver==1.3

Step2: Update Flask App to use WSGI

Once WSGI is installed successfully, we are ready to use it in our Flask app. Before we ran our app using Flask, now we will use WSGI to run our Flask app. For this, we will first import wsgiserver and modify the last line of our app to now use wsgiserver and finally start the wsgiserver.

(flask_env) ubuntu@xxxx:~/flask_test$ vi app.py 

In the vi, modify the code so it looks like below –

from flask import Flask
import wsgiserver

# a flask instance
app = Flask(__name__)

@app.route('/', methods=['GET'])
def index():
    return 'Hello World!'

if __name__ == "__main__":
    server = wsgiserver.WSGIServer(app, host='127.0.0.1',port=5000)
    server.start()

Step3: Test WSGI server

At this point, we can run our app, use tunnel to connect to our instance and test if we can access “localhost:5001” in browser just like we did in Steps4-5 in the previous post linked at the beginning of this post.

Notice that we no longer get the development server warning message now and the app just starts running.

Step4: Install NGINX

Now that we have WSGI server set up, running and tested, we can not install NGINX. To do so, running the below command. Once it is successfully installed, we can run the version command to check its version.

(flask_env) ubuntu@xxxx:~/flask_test$ sudo apt install nginx
(flask_env) ubuntu@xxxx:~/flask_test$ nginx -v
nginx version: nginx/1.14.0 (Ubuntu)

Step5: Configure NGINX

Once NGINX is installed, we will see the default configuration in the /etc/nginx/sites-enabled/ directory.

(flask_env) ubuntu@xxxx:~/flask_test$ ls /etc/nginx/sites-enabled/
default

Let us rename the default config to default.org so that we can create our own config with that name.

(flask_env) ubuntu@xxxx:~/flask_test$ sudo mv /etc/nginx/sites-enabled/default /etc/nginx/sites-enabled/default.org 
(flask_env) ubuntu@xxxx:~/flask_test$ ls /etc/nginx/sites-enabled/
default.org

Let us now add our config.

sudo vi /etc/nginx/sites-enabled/default

In vi, add the following config and save it. Note that I have used 5000 as the port where the requests will be forwarded. Recall that we used the same port in our app and that is where we will service our requests. If these do not match, NGINX will not be able to pass our requests to the right place. As for the port it is listening to, we have left it to the default http port 80.

server {
    listen 80;
    server_name ec2-xxxx.compute-1.amazonaws.com;
    access_log  /var/log/nginx/test.log;

    location / {
        proxy_pass http://127.0.0.1:5000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

Another way of achieving this could be to save the config with any custom name and point the NGINX to that config instead of the default one. Once the config is saved, we will need to restart our NGINX server for the updated config to take affect.

sudo service nginx restart

Note how we have prefixed all our commands related to NGINX with “sudo” as we will run into permission related issues

Step6: Allow http Traffic

Before moving to the next step, make sure the EC2 instance is configured with the rule allowing http traffic. The security tab of the EC2 instance on the console should have the entry shown in screenshot below.

Step7: Access the Service

Now that our NGINX server is running with out updated config and our WSGI server is running, we should now be able to access our app from a web browser by typing our EC2 instance’s public address. On doing so, we should see this on our page –

Hello World!

One thought on “Run a Flask App with WSGI and NGINX on EC2”

Leave a Reply

Your email address will not be published. Required fields are marked *