Ep.23 Deploying Flask to a VM
Deploying a Flask app on a virtual machine | Learning Flask Ep. 23
Introduction
In this guide, we're going to be building a very simple Flask application that accepts a query string in the URL, renders a template and displays the query string keys & values in a table.
We're going to be deploying the app on a Google Cloud virtual machine using Ubuntu 18.04.
You can find the small amount of source code at the Github repo Here if you'd like to follow along.
The puspose of this guide is to cover the setup of a VM and a basic introduction to deploying a Flask application with Nginx & uwsgi.
A few things to note about this guide:
We won't be using a domain name
We won't be creating certificates/serving HTTPS requests
We'll be using Github as a remote repository
How to follow this guide
There's a few ways to follow along:
Clone the repo to your local machine and set up a new remote repository
Copy the source and create the files/directories yourself on your local machine
Either way, you'll need to push your code to a remote repo as we'll be pulling the code into the virtual macine.
Dependencies
Flask
uwsgi
Running the application locally
Create a new virtual environment with
python -m venv <name_of_your_environment>
Clone the repo or create the project files individually
Activate the virtual environment
Install the dependencies with
pip install -r requirments.txt
or withpip install flask uwsgi
If you're copying the source code and creating the files/directories yourself, be sure to generate a requirements.txt
file by running the following command from the app parent directory:
Running the application with the Flask development server
In this example, the entrypoint to our application is run.py
.
Enter the following commands in the same directory as run.py
to run the app with the Flask development server:
Access the app in your browser at 127.0.0.1:5000
.
Running the appliaction with uwsgi locally
To run the application locally with uwsgi
, run the uwsgi
command followed by the name of the development ini
file:
Access the app in your browser at 127.0.0.1:9090
.
Server setup
In this example, we'll be deploying our application to a virtual machine on Google cloud platform.
Create a Google cloud account and/or sign into the console.
Creating a free VM
Create a new project
Click the menu icon in the top left of the console
Select Compute engine > VM instances
Wait for Compute engine to get ready
Click create
Name the instance
In
Machine type
, select micro (1 shared vCPU) - It's free!In
Boot disk
, select Ubuntu 18.04 LTS and click selectIn the
Firewall
section, tick both Allow HTTP traffic and Allow HTTPS trafficLeave everything as is and click create
Wait for the instance to become ready
You'll see your External IP address, make a note of it for later!
Adding a network tag
Now that the instance is ready, we need to add a network tag to enable us to test the application using uwsgi
(Optional)
Click on the VM instance
Click
EDIT
at the top of the pageIn the
Network tags
section, addflask
(You may need to add a comma after it)Scroll down and hit
Save
Adding new a firewall rule
We're going to use port 9090 to test the application with uwsgi
. But first, we need to add a new firewall rule. (Optional)
Select the menu in the Google cloud console
Click VPC network > Firewall rules
Click
Create firewall rule
at the top of the pageName it
uwsgi-testing
Give it a description of
uwsgi testing on port 9090
In
Targets
, selectSpecified target tags
In
Target tags
, enterflask
In
Source filter
, selectIP Ranges
In
Source IP ranges
, enter0.0.0.0/0
In
Protocols and ports
, selectSpecified protocols and ports
Select
TCP
and enter9090
Click
Create
To make sure the new firewall rule has been applied:
Navigate back to the VM instance
Menu/Compute engine/VM instances
Click on the menu icon next to your VM instance and select
View network details
In the firewall rules and routes details section, you should see uwsgi-testing
.
We're going to come back and disable this rule after we've tested the application with uwsgi!
Connecting to the VM
We're going to use the Google cloud shell provided to connect to our VM.
Click the
SSH
button under theConnect
section to launch a terminalA new shell should be spawned with your username@instance in the prompt
Update the machine
Update the system packages:
Installing Python3.7
We're going to use Python3.7.2 and use pyenv
to manage our Python installations.
Clone the pyenv
repo (It will clone into your user home directory by default):
For pyenv
to work, you'll need to add a few lines to your .bashrc
file.
Run the following commands to update your .bashrc
and reload the shell:
Install the required Python build dependencies:
Once the dependencies have been installed, we can install Python3.7.2:
You should see (This may take some time on the micro instance!):
Once installed, run the following command to check Python3.7.2 has been installed:
You should see 3.7.2
.
Now set the system Python as 3.7.2:
Start a python interpreter with the python
command to double check the right version is being called. You should see:
Cloning the app
We'll need a method to get the application code from your local machine to the VM.
Assuming you've cloned this repo to your local machine and set up a new repote origin for yourself, or just copied the code and setup a new repo, we're going to clone into the app on the virtual machine.
Move into the home directory:
Clone the repo, being sure to replace the URL with the URL of YOUR repo!:
IMPORTANT
If you've cloned this repo, rename the simple-flask-demo
parent directory to app
. Otherwise, just make sure the application parent directory is named app
.
If you need to rename simple-flask-demo
on the virtual machine, you can do so with:
The file/directory structure should look like this (where the parent app
directory is located in your user home directory):
Installing the dependencies
We need to create a new virtual environment and install the required packages.
Move into the parent app
directory:
Running the ls
command should return:
Create a new virtual environment. We're going to call ours env
(You should too!):
Activate it:
Upgrade pip:
Install the Python dependencies (This may take a few minutes on a micro instance):
Testing
We can quickly test our application using uwsgi.
First, we need to add a firewall rule using ufw
:
Now, make sure ufw
is enabled:
Run the following to make sure ufw
is enabled and port 9090 is exposed:
You should see:
Running with uwsgi
Assuming the following:
Your virtual environment is active
You've created a new firewall rule to allow
9090
in the Google Cloud consoleYou've enabled
ufw
and added9090
as a rule on the VM
Make sure you're in the same directory as dev.ini
and run the application with the following:
You should see some output from uwsgi in the terminal to let you know uwsgi has started and is running.
open up a new browser window and head to your virtual machines IP address followed by :9090
, for example:
You should see the application running! Feel free to send a query string in the URL to have it parsed and returned in the table.
We're going to be using Nginx as a reverse proxy to handle HTTP requests, so once you've had some fun with the application, stop uwsgi with Ctrl + c
.
Disable the development port
We used ufw
to enable traffic on port 9090
but now we need to delete it:
Run sudo ufw status
to confirm the rule has been deleted. You should see:
Disabling the firewall rule in GCP
We should remove the firewall rule we created for testing in the Google cloud console.
Navigate to Menu > VPC networking > Firewall rules
Click
uwsgi-testing
from the list of rulesClick
Delete
at the top of the page to remove the rule
If you head back to your VM instance and select View network details
from the dropdown menu, you'll see the firewall rule has been removed.
Installing Nginx
We're going to use Nginx to handle incoming HTTP requests to our application, so we need to install and configure it.
In stall Nginx with the following command:
Adjusting the UFW firewall
Just like how we enabled port 9090
for testing our app with uwsgi
, we need to enable a few ports to enable Nginx.
ufw
will see it as an available application if it's installed. We can chack this by running:
You'll see something similar to this:
We're only going to be serving our application over HTTP on port 80, so we need to enable it with the following:
This will allow HTTP traffic on port 80
, the default HTTP port.
We can check the rule has been applied with:
You should see:
Checking Nginx
We can see Nginx is running by heading the the IP address of the virtual machine in a new browser window.
You should be greeted with a default Welcome to nginx!
page.
We can also check with systemd
that Nginx is running.
systemd
is a software suite that manages services and processes and will start Nginx when your server boots:
You should see:
There's still a few more steps before we can access our application:
Configure Nginx to reverse proxy requests to uwsgi
Create a
systemd
unit file to automatically startuwsgi
and serve our app
We'll start by creating the systemd
unit file.
Systemd unit file
We're going to use nano
to create a .service
unit file. We'll call ours app.service
.
IMPORTANT
This guide assumes you've used the same directory and file names that we've used throughout this tutorial.
You'll also need to replace <yourusername>
with your actual username! You can see your username in your terminal prompt I.e your-username@your-instance
Open nano
with the following:
Add the following:
Save and close the file with Ctrl + c
, followed by y
then Enter
.
Start the process:
Enable the process:
Check the process status:
You should see:
Now we can move on to the final step, configuring Nginx!
Configuring Nginx
We need to create a new server block in Nginx's sites-available
. We'll use nano
again to create a new file called app
:
IMPORTANT
Just as with the systemd
unit file, you'll need to replace <username>
with your username and <your_ip_address>
with the IP address of your virtual machine!
Add the following:
If you'd like to use your own domain name, replace <your_ip_address>
with:
You'll need update your domain registrar to point the domain to the server IP address if you want to use a custom domain, which we're not going to cover in this guide.
We need to link the server block we've just created in sites-available
to sites-enabled
:
We can check Nginx for syntax errors with the following:
You should see:
We can now restart the Nginx service:
Testing the application
Assuming you've not had any syntax errors or used different directory/filenames. Go to your IP address in a browser and you should see the application in action.
Try sending a query string in the URL such as:
You should see the query string arguments displayed in the table!
Updating your app
In this scenario, the best way to make changes to your application:
Make changes and test locally
Push the changes to your remote Github repo
Pull the changes from your virtual machine
To pull any changes to you've made to your application, make sure you're in the app
parent directory:
Pull the repo with the following command:
Every time you pull any changes from your remote repo, you'll need to restart the app
service with:
If you make any changes to the Nginx sites-enabled
file, you'll need to restart Nginx with:
Wrapping up
This was just a quick guide to deploying a Flask app to a virtual machine using Nginx & uWSGI and as you can see, it's relitively simple.
We used Google Cloud but of course, you could achieve the same result using any other provider such as AWS, Linode, Digital Ocean etc. If you do decide to use another cloud platform, you may not have to bother configuring custom firewall rules, it's really platform dependent.
By modern standards, deploying an application this way may seem slow, especially when compared to using Docker or a hosted service like Google App Engine, however I hope it demonstrates that it's really not that difficult!Last modified · 21 Mar 2019
Reference : https://pythonise.com/series/learning-flask/deploy-a-flask-app-nginx-uwsgi-virtual-machine
Last updated