# Deploy a Django application using Gunicorn and Nginx

### Differences by responsibility

**Django** is a web framework used to build web applications.

**Gunicorn** is an application server which transfers HTTP requests to web applications. It implements WSGI (Web Server Gateway Interface) which works as an interface between the web application and the web server.

**Nginx** is a web server that can be used as a reverse proxy server. It is capable of handling a large number of requests simultaneously.

Let's go step by step into this process

### Django app setup

First, we need to create a simple Django app with minimal requirements. Let's create a simple Django app by following these steps

```bash
mkdir djnago_gunicorn_nginx
cd djnago_gunicorn_nginx
python3 -m venv .env
source .env/bin/activate
pip install django
django-admin startproject django_gunicorn_nginx .
python manage.py runserver
```

Now if you go to http://127.0.0.1:8000, you should be able to see Django application running on your browser. We're not going to do any Django configurations here.

Now that your Django app is set up and running. Let's jump into the Gunicorn setup.

### Gunicorn install and setup

Install Gunicorn in your terminal

```bash
pip install gunicorn
```

Now, let's run your app via Gunicorn from shell by running this command

```bash
gunicorn -b 0.0.0.0:8000 --workers=2 django_gunicorn_nginx.wsgi:application
```

Congrats, you are just able to run your web application through Gunicorn.

Here '**\-b**' is binding the app to the socket '**0.0.0.0:8000**', **\--workers=2** means 2 worker processes are running for accepting requests. **Django\_gunicorn\_nginx.wsgi:application** refers to a pattern **$(MODULE\_NAME):$(VARIABLE\_NAME)** in which **MODULE\_NAME** would be to full dotted path to the module and **VARIABLE\_NAME** refers to a WSGI callable that should be found in the specified module.

Let's configure Gunicorn properly in our app.

First, create a directory named 'config'. Then follow these steps.

```bash
mkdir config
nano config/gunicorn.py
```

Now add the following inside the file.

```python
                                                                                                                                                                 """Gunicorn config for *development* environment"""
# Django wsgi appliation path, format MODULE_NAME:VARIABLE_NAME
wsgi_app = "django_gunicorn_nginx.wsgi:application"
# The granularity of error-log
loglevel = "debug"
# The number of processes will be running for handling requets
workers = "2"
# Socket to bind
bind = "0.0.0.0:8000"
# Restart worker when code changes
reload=True
# Write access and error log info
accesslog = errorlog = "/var/log/gunicorn/django_gunicorn_nginx.log"
# Redirect stdout/stderr to log file
capture_output=True
# PID file to fetch the process-id
pidfile = "/var/run/gunicorn/django_gunicorn_nginx.pid"
# Daemonize the gunicorn process
daemon = True
```

Let's create the necessary folders

```bash
sudo mkdir /var/{log,run}/gunicorn/
sudo chown -cR ubuntu:ubuntu /var/{log,run}/gunicorn/
```

Now start your app with Gunicorn by running this command

```bash
gunicorn -c config/gunicorn.py
```

Your app should be started running in the background through Gunicorn now.

If you want to see the logs generated for your app, please run the following command

```bash
tail -f /var/log/gunicorn/django_gunicorn_nginx.log
```

You should be able to see something like this

```bash
127.0.0.1 - - [16/Dec/2022:06:36:14 +0000] "GET /static/admin/css/fonts.css HTTP/1.1" 404 2170 "http://127.0.0.1:8000/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36" [2022-12-16 14:20:39 +0530] [3833089] [CRITICAL] WORKER TIMEOUT (pid:3833091) [2022-12-16 14:20:39 +0530] [3833089] [CRITICAL] WORKER TIMEOUT (pid:3833094) [2022-12-16 08:50:39 +0000] [3833091] [INFO] Worker exiting (pid: 3833091) [2022-12-16 08:50:39 +0000] [3833094] [INFO] Worker exiting (pid: 3833094) [2022-12-16 14:20:39 +0530] [4012073] [INFO] Booting worker with pid: 4012073 [2022-12-16 14:20:39 +0530] [3833089] [WARNING] Worker with pid 3833091 was terminated due to signal 9 [2022-12-16 14:20:39 +0530] [3833089] [DEBUG] 1 workers [2022-12-16 14:20:39 +0530] [4012075] [INFO] Booting worker with pid: 4012075 [2022-12-16 14:20:39 +0530] [3833089] [DEBUG] 2 workers
```

Let's configure your `config/gunicorn.py` and make it ready for deployment.

```python
import multiprocessing
import os                                                                                                                                                          """Gunicorn config for *development* environment"""
# Django wsgi appliation path, format MODULE_NAME:VARIABLE_NAME
wsgi_app = "django_gunicorn_nginx.wsgi:application"
# The granularity of error-log
loglevel = "warning"
# The number of worker threads for handling requests. Set as per your requirements
threads = multiprocessing.cpu_count() * 2
# The number of processes will be running for handling requets. Set as per requirements
workers = multiprocessing.cpu_count() * 2
# Socket to bind
bind = "0.0.0.0:8000"
# Restart worker when code changes
reload=True
# Write access and error log info
accesslog = errorlog = "/var/log/gunicorn/django_gunicorn_nginx.log"
# Redirect stdout/stderr to log file
capture_output=True
# PID file to fetch the process-id
pidfile = "/var/run/gunicorn/django_gunicorn_nginx.pid"
# Daemonize the gunicorn process
daemon = True
# The number of seconds to wait for requests on a Keep-Alive connection.
keepalive = 60
# Workers silent for more than this many seconds are killed and restarted.
timeout = 90
```

Do visit the official Gunicorn page for more details about the configuration [https://docs.gunicorn.org/en/stable/settings.html](https://docs.gunicorn.org/en/stable/settings.html)

To kill the process of running through Gunicorn, you can run this command.

```bash
sudo lsof -i :8000
```

To kill the process get the PID from the output logs and run the command.

```bash
kill <PID>
```

### Nginx configration

Install and run Nginx in your system.

```bash
sudo apt install nginx
sudo service nginx start
```

Let's add Nginx configuration file by nano-editor.

```bash
sudo nano /etc/nginx/conf.d/django_gunicorn.conf
```

Add the following content to your configuration file already opened via nano-editor.

```bash
access_log /var/log/nginx/djnago-gunicorn-access.log;
error_log /var/log/nginx/djnago-gunicorn-error.log;


server {
        listen 80;

        location / {
                proxy_pass http://localhost:8000;
                proxy_set_header HOST $host;
      }
}
```

Now we should remove the default file from /etc/nginx/sites-enabled as it might take priority over the django\_gunicorn.conf we created eariler.

And now we need to restart nginx.

```bash
sudo rm -rf /etc/nginx/sites-enabled/default
sudo service nginx restart
```

Now you should be able to see your django-app running via gunicorn and nginx by opening the localhost in your browser : [http://localhost/](http://localhost/)

For adding your server domain name in Nginx you need to add this right below the `listen 80;` line server\_name `<your-domain-name>.com;` . Also, you need to add the elastic-IP (for AWS) of your server to your DNS register under DNS settings.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1671253497415/-76IPVJr6.png align="center")

### Conclusion

If you can follow to the end and it was able to increase your knowledge, then I am  
well pleased.

Happy Learning !!
