This article describes how to deploy a Python WSGI application using Gunicorn and Nginx. Before proceeding with the tutorial, it’s a good idea to first familiarize yourself with the terms WSGI, Gunicorn, and Nginx. Web Server Gateway Interface or WSGI is a specification that describes how a web server (in this case Nginx) interacts with a Python web application/framework.
Though some Python web frameworks have a built-in development server for running web applications, it is not recommended to use it for production. Therefore, you need a server like Gunicorn, a robust and secure application server that connects to and runs Python application instances via a WSGI interface.
Nginx is a web server used with Gunicorn as a reverse proxy that accepts incoming HTTP requests from clients and redirects them to Gunicorn.
Prerequisites
For deploying a web application you need a server with a public IP address, we will be using a Debian virtual machine deployed on Azure.
Installing required packages
Following the Linux command will install Python3, pip package installer, and Nginx on the Debian machine,
sudo apt install python3 python3-pip nginx
Setup a development environment for your project
First, let us configure the development environment, this step can be skipped but it is always a good idea to use a dedicated development environment for each project, this can be achieved using a python virtual environment. To create one just run the following commands:
mkdir python_web_app; cd python_web_app
This will create a dedicated folder for the project, you can name it anything you want and cd (change directory) to go into your newly created directory then run the following command that will create a virtual environment for your project.
python3 -m venv venv ls
Now let’s activate the virtual environment and start using it.
source venv/bin/activate pip install gunicorn
Create a WSGI App and configure it for deployment
Now that the environment is ready, let’s create a WGI app in Python,
nano app.py
This will create an empty file now paste the following code in there,
def application(env, start_response): status = "200 OK" response_headers = [('Content-Type', 'text/plain; charset=utf-8')] start_response(status, response_headers) message = "neveropen is a best coding platform.".encode('utf-8') return [message]
The above code is a very simple WSGI App that we are going to deploy in this article.
Using Gunicorn to serve the project
Now run the following command,
gunicorn app:application --bind 0.0.0.0:8000
The above command will allow the WSGI app to start taking client requests on localhost port 8000.
Creating system Socket and Service files for Gunicorn
Now that you’ve tested that Gunicorn with your Django application, you should implement a more robust way of starting and stopping the application server. To accomplish this, we will create systemd service and socket files, by running the following commands.
sudo nano /etc/systemd/system/gunicorn.socket
This will open the system socket file for Gunicorn with sudo privileges, and add the following stuff to the file, which creates a [Unit] section to describe the socket, a [Socket] section to define the socket location, and a [Install] section to make sure the socket is created at the right time, once done just save and close the file.
[Unit] Description=gunicorn socket [Socket] ListenStream=/run/gunicorn.sock [Install] WantedBy=sockets.target
sudo nano /etc/systemd/system/gunicorn.service
Now, let’s create and open a systemd service file for Gunicorn (the filename should match the socket filename) and add the following content to the file. It should look something like this.
As you can see It contains 3 sections :
- [Unit]: This is used to specify metadata and dependencies.
- [Service]: it specifies the user and group that you want the process to run under, also giving group ownership to the www-data group so that Nginx can communicate with Gunicorn.
- [Install]: This will tell systemd what to link this service to if you enable it to start at boot.
Enabling and checking socket and service files for Gunicorn.
The following commands will start running the Gunicorn socket service and will enable it to start automatically on boot.
sudo systemctl enable gunicorn.socket sudo systemctl start gunicorn.socket
Output:
Check the status of the Gunicorn process to find out whether it was able to start
sudo systemctl status gunicorn
Output:
If something goes wrong you can see the logs for the Gunicorn process by running the following command:
sudo journalctl -u gunicorn.socket
Configure Nginx proxy
Let’s configure Nginx to work along gunicorn and handle HTTP requests for this we need to create a server block,
sudo nano /etc/nginx/sites-available/python_web_app
server { listen 80; server_name server_domain_or_IP; location = /favicon.ico { access_log off; log_not_found off; } location /static/ { root <project path>; } location / { include proxy_params; proxy_pass http://unix:/run/gunicorn.sock; } }
Here you can find all the configurations that can be done in Nginx, once finished run the following command,
sudo ln -s /etc/nginx/sites-available/python_web_app /etc/nginx/sites-enabled
It is going to enable the file by linking it to the site-enabled directory.
All done now just run these commands to test the Nginx file for any errors etc.
sudo nginx -t sudo systemctl restart nginx
A Python WSGI App is deployed successfully.