In this Blog, we will discuss how to successfully deploy a Python Flask web application to an Ubuntu server. We won't discuss how to create a Flask application here, as I assume we already have one ready for deployment. We also did not discuss the process for creating a Ubuntu Linux server instance. You can choose your favorite platform for creating your server instance. We will focus on the deployment process deeply. So, let's begin.
Tools we will be using:
1. Ubuntu Linux (in Oracle Cloud) for Virtual Private Server,
2. Caddy as Web Server,
3. Gunicorn to run Python (Flask) web application in production server,
4. Git for Version Control and GitHub as code repository.
Procedure:
1. Setting up the Server:
To deploy our web application on the server we need to configure the server. First, connect to the server using SSH in the command line tool (one can also use other tools like PuTTY on a Windows machine). I will use SSH from the command prompt to connect to the server.
Open the command prompt and use the below command to connect with the server:
ssh <user_name>@<IP_address>
If you need to use any private key to connect to your server, use the below command:
ssh -i <full path to your key>\<file_name> <user_name>@<IP_address>
Once connected to the server, you need to update the package lists. Use the below command for that:
sudo apt update
Once completed, upgrade the installed packages by using the below command:
sudo apt upgrade
Upon completion, you are good to go for further processes.
2. Database Configuration:
I have used the PostgreSQL Database here. So, I need to install and configure PostgreSQL. I would like to mention here that, this step is optional and may vary depending on your Flask application. I have used PostgreSQL in my Flask application. Hence, I would need to configure PostgreSQL on the server.
For example, if you are using SQLite database in your application, then you don't have to worry about database installation and configuration as SQLite comes inbuilt with Python, so, your database installation will be done automatically with Python installation. But if you are using any other Database like PostgreSQL or MySql then you have to install and configure those databases on the server.
Let's install PostgreSQL on the server. Use the below command to install PostgreSQL:
sudo apt install postgresql postgresql-contrib
Once finished we need to configure the user and database. PostgreSQL has a default user 'postgres'. To switch to 'postgres' user use the following command:
sudo su postgres
Now you need to open psql shell to perform any activity with PostgreSQL and for that type 'psql' and hit enter. You should see the psql shell (postgres=#) open.
To change the default user password use the below command:
ALTER USER postgres WITH PASSWORD <new_password>
To create the database use the below command:
CREATE DATABASE <database_name>
Note: This database we are going to use in our Flask application.
3. Installation of Caddy:
I will use Caddy as a web server here. To install Caddy we need to add and install a few packages first. Use the below commands one by one for that:
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install caddy
At this point of time, if we go to the server IP we should see the Caddy Welcome screen.
You can check the status of Caddy by using the following command:
sudo systemctl status caddy
Note: Sometimes you may not see the Caddy screen even though Caddy is up and running and see an error like 'page cannot be reached', in that case, you might have to allow TCP traffic for ports: 80 and 443 in your Virtual Cloud Network, if it is not allowed. This might prevent Caddy from running and you may not see the Caddy screen.
Also, consider allowing those ports in the Firewall if you are using one on your server.
4. Installation of Python:
Once this Caddy installation is successful we can now install Python. Use the following commands to install Python:
sudo apt install python3-pip python3-dev build-essential libssl-dev libffi-dev python3-setuptools
This will install Python and essential tools. Once this is done we can go for installing a virtual environment in Python.
5. Get Code from Git Repository:
Create a Git repository and push the code from the local repository. Now on the server run 'pwd' command to check your directory structure. If you are inside the home directory, you make a folder (if you prefer) to store the code inside it. Run 'mkdir <folder_name>' command for that. Change the directory to the newly created folder (cd <folder_name>). Now go to GitHub and copy the HTTPS link to clone the repository inside the folder you created on the server (as shown below).
Run the below command to clone the git repository:
git clone <HTTPS link>
Once the process is completed, you will have your Flask application code on the server.
6. Creating a Virtual Environment and storing Environmental Variables:
Creating a Virtual Environment is very important because that will allow you to install Python modules in an isolated environment and that way you can host multiple applications on a single server. To create a Virtual Environment run the below command:
python3 -m venv env
Note: You can replace the 'env' with the name you want to give to your virtual environment.
Now you have to activate the virtual environment by running the below command:
source evn/bin/activate
Note: Again you should replace the 'env' here with your virtual environment name.
Once the virtual environment is activated, you should see the virtual environment name in the bracket in your terminal as shown below:
Now, another important thing I want to mention here i.e. storing environment variables in the virtual environment. We will see how to use this powerful feature to store our sensitive information (such as API keys, passwords, etc.) as key-value pairs inside the virtual environment rather than storing them in our code directly. So, that we can make our code more safe to be shared publicly.
We can store environment variables in multiple ways. For example, we can run the following command in the terminal to add the environment variable:
export VAR_NAME=<variable_value>
But the problem is if we shut down or reboot the server, the stored variables might be deleted. So, what we can do here is, we can add those environment variables every time we shut down or reboot our server. But that is not so convenient, right? That's why we will add the above command in the activation script itself, so that, every time we run the activation script or activate the virtual environment, the variables will be added automatically.
For that cd to the virtual environment folder then cd to the bin folder and edit the 'activate' file with your favorite text editor (such as nano or vim). You the below command inside the bin folder to open the 'activate' file with the nano editor:
nano acviate
Now add the below line to add the environment variables in the activation script.
export VAR_NAME=<variable_value>
To save and close the file press ctrl + x then Y then Enter.
7. Installation of Python modules and Dependencies in the Virtual Environment:
Now we are ready to install the required Python modules and dependencies. I have listed out all the required modules in a file name 'requirements.txt' and saved it in the Python project folder. As I have cloned my repository from GitHub, so, this file is also available in the project folder on the server.
Use the below command to start installing the modules from the 'requirements.txt' file:
pip install -r requirements.txt
Note: Make sure the virtual environment is activated before running this command, otherwise the modules will be installed globally.
8. Deploying Flask application using Gunicorn on the Server:
Now we are ready to make our application up and running on the server, by using Gunicorn. Use the below command to run the Flask application with Gunicorn:
gunicorn main:app
Here you might have to modify your command depending on how you have named them. Here I have named my Python file as 'main' and the object 'app' is coming from the 'main.py' file.
At this point of time, we need to configure the Caddy server a bit to make the app up and running. Now, hit 'ctrl + c' to stop the Flask application from running and go back to your code in create a file name 'Caddyfile'.
Alright, we will now set up the reverse proxy for the server. Add the following code to the Caddyfile:
http://<IP of the server> {
reverse_proxy localhost:8000
}
Now stop the Caddy server and restart it with the newly added Caddy file.
caddy stop
sudo caddy start
Let's run the Flask app again:
gunicorn main:app
At this point of time, if you go to your server IP you should see your Flask application up and running.
9. Point Server IP to Domain:
Now it is time to point our server IP to a domain. For that of course we need to have one domain. If you don't have you can purchase any domain of your choice. Once you have the domain the rest things are pretty simple.
We have to update the DNS record of the domain. Update the 'A Record' of the domain and add the IP address of your server to it.
Now, we have to add a few lines in the Caddyfile as below and that's all. Caddy will automatically obtain the SSL certificates.
www.<your_domain_name> {
redir https://<your_domain_name>{uri}
}
<your_domain_name> {
reverse_proxy localhost:8000
}
We might have to wait for some time to allow our domain to be propagated all over the world to see our website up and running in the domain.
10. Update the Flask application:
Great, we are all set. Our application is now live on the internet. Now you might be thinking about how will you make some changes to your website if needed in the future. I will show you how you can make some modifications to your website. That is quite simple by the way.
Make the required modification to your code, save the file, and push it into GitHub. Now again login into your server, 'cd' to the project folder and pull the code from GitHub.
Now we have to restart the Gunicorn to start with the updated files. Run the below command to find out the running applications:
ps xf
You should see the Gunicorn workers up and running as follows:
Stop the processes:
kill <PID>
For example:
kill 19513
Run the Flask app again with Gunicorn using the following command:
gunicorn main:app &
You should see your modifications are applied and live.
Note: Add the '&' to run the Gunicorn in the background even after closing the terminal.
Great, we have come so far. Now our website is up and running in the production server in a scalable and maintainable way.