Deploying Flask Applications with Nginx and Gunicorn on Ubuntu
This article will describe how to deploy a simple Flask app on Ubuntu using Gunicorn and Nginx.
Prerequisites Copy link
To follow this guide, you will need:
-
A cloud server running Ubuntu 20.04 or higher, with Nginx installed.
-
A non-root user with
sudoprivileges. -
A domain name with its A record pointing to your cloud server's IP address.
Install components Copy link
To begin with, we will install several packages necessary for our application, including pip for managing Python components.
sudo apt update
sudo apt install python3-pip python3-dev build-essential libssl-dev libffi-dev python3-setuptoolsConfigure Python virtual environment Copy link
Virtual environments allow you to separate the dependencies of applications hosted on the same server.
Install python3-venv:
sudo apt install python3-venvCreate a directory for your Flask project files.
mkdir ~/myprojectMove to this directory:
cd ~/myprojectNow, create a virtual environment:
python3 -m venv myprojectenvAnd activate it:
source myprojectenv/bin/activateIn the terminal, you will see that now you're working within the virtual environment:
(myprojectenv)user@host:~/myproject$Configure the Flask application Copy link
Update pip:
pip install -U pipDownload Flask and Gunicorn:
pip install gunicorn flaskCreating an app
Now, let's create a simple Flask application called myproject.py:
nano ~/myproject/myproject.pyAdd the code below to the file.
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "<h1>Hello<h1>"
if __name__ == "__main__":
app.run(host='0.0.0.0')
Save the changes and close the file.
Before launching the app to check if the code works, make sure your firewall allows traffic on port 5000. On Ubuntu, it's probably ufw, so run:
sudo ufw allow 5000Now we can run our Flask app:
python myproject.pyGo to http://your_server_ip:5000. The browser should display "Hello!". Go back to the terminal and press CTRL+C to disconnect the Flask server.
Creating a WSGI entry point
Let's move on to creating an entry point to our app:
nano ~/myproject/wsgi.pyAdd the following code to the file:
from myproject import app
if __name__ == "__main__":
app.run()
Save changes.
Configure Gunicorn Copy link
Before continuing, verify the Gunicorn server can serve our program correctly.
Go to the project directory:
cd ~/myprojectAnd run the command:
gunicorn --bind 0.0.0.0:5000 wsgi:appYou should see a similar output:
[2024-05-23 15:52:19 +0000] [9211] [INFO] Starting gunicorn 20.1.0
[2024-05-23 15:52:19 +0000] [9211] [INFO] Listening at: http://0.0.0.0:5000 (9211)
[2024-05-23 15:52:19 +0000] [9211] [INFO] Using worker: sync
[2024-05-23 15:52:19 +0000] [9213] [INFO] Booting worker with pid: 9213
Again, go to http://your_server_ip:5000 and verify that the "Hello!" message is displayed.
In the terminal, press Ctrl+C to stop the application and deactivate the virtual environment:
deactivateTo be able to launch Gunicorn automatically, let's create a systemd unit file:
sudo nano /etc/systemd/system/myproject.serviceAnd add the following content to it:
[Unit]
Description=Gunicorn instance for myproject
After=network.target
[Service]
User=username
Group=www-data
WorkingDirectory=/home/username/myproject
Environment= "PATH=/home/username/myproject/myprojectenv/bin"
ExecStart=/home/username/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app
[Install]
WantedBy=multi-user.target
Save the changes and close the file. Now you can start the Gunicorn service and enable it so it runs at boot:
sudo systemctl start myproject
sudo systemctl enable myprojectCheck the status to verify that Gunicorn is running:
sudo systemctl status myprojectConfigure Nginx Copy link
Let's move on to working with the Nginx web server. First, create a configuration file in the sites-available directory:
sudo nano /etc/nginx/sites-available/myprojectAdd the following directives to the file:
server {
listen 80;
server_name your_domain www.your_domain;
location/{
include proxy_params;
proxy_pass http://unix:/home/username/myproject/myproject.sock;
}
}
And save the changes. Apply the new configuration:
sudo ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabledNext, add the www-data user to the current user group:
sudo usermod -a -G ${USER} www-dataCheck the Nginx configuration:
sudo nginx -tIf everything is fine, restart the web server:
sudo nginx -s reloadComplete the setup by adjusting the firewall settings. For example, we no longer need the rule about access through port 5000; we can safely delete it. Instead, add another rule to open a connection to the Nginx server:
sudo ufw delete allow 5000
sudo ufw allow 'Nginx Full'Try accessing your server from a browser via http://your_domain. The program shouls display the "Hello!" message.
Install an SSL certificate Copy link
Finally, let's install an SSL certificate to secure traffic.
We will issue a Let's Encrypt SSL using Certbot. The recommended way to install Certbot is through snap. More information can be found in the official Certbot documentation.
Run the command below to ensure you are using the latest version of snapd:
sudo snap install core; sudo snap refresh coreIf you previously installed any Certbot packages using the apt package manager, remove them with the command:
sudo apt-get remove certbotInstall Certbot via snap:
sudo snap install --classic certbotExecute the following command to ensure that the certbot command can be run:
sudo ln -s /snap/bin/certbot /usr/bin/certbotObtain the certificate and automatically make the necessary changes to the Nginx configuration:
sudo certbot --nginxCertbot will automatically update the certificate. You can test the update by running the command:
sudo certbot renew --dry-runTry going to your domain via HTTPS (https://your_domain) to make sure the secure connection works.
Conclusion Copy link
In this tutorial, we deployed a simple Flask app on an Ubuntu server using the Python virtual environment, configured Gunicorn and Nginx, and secured our application with an SSL certificate.
By the way, with Hostman, you can run your workloads on efficient NL VPS that support low latency for EU-based users. Check this out, we have plenty of budget VPS hosting options for your projects.