Prologue

In this article, I’d like to demonstrate on how to setup backend service of Django using uWSGI and Nginx. It mainly focus on the configurations of uWSGI and Nginx, rather than how to build Django project.

I use Ubuntu server. :)

Prerequisites

Before you start, you should have a Linux server, with conda environment.

Quick References

Here are some quick references for uWSGI and Nginx. You can expand it optianlly.

Quick References

uWSGI

1
2
uwsgi --ini uwsgi.ini  # start uwsgi service
uwsgi --stop uwsgi.pid # stop uwsgi service

Nginx

1
2
3
4
5
6
7
8
9
10
11
# start Nginx
sudo nginx
systemctl start nginx.service

# edit configuration
sudo vim /etc/nginx/conf.d/default.conf # default.conf may vary
sudo nginx -s reload # reload configuration

# stop Nginx
sudo nginx -s quit # stop after current process finishes its work
sudo nginx -s stop # stop immediately

Procedures

Step 1. Prepare Django

You should have your Django project ready. You should configure the virtual environment using conda. For example, your environment for this project is django. For the root directory of your project, here I use /home/server/backend as an example. This directory is where manage.py located.

Step 2. Setup uWSGI

Reference: https://www.runoob.com/python3/python-uwsgi.html

Introduction

uWSGI (source code), pronounced “mu wiz gee”, is a Web Server Gateway Interface (WSGI) server implementation that is typically used to run Python web applications.”

- From https://www.fullstackpython.com/uwsgi.html

Install uWSGI

Go to the root folder of your Django project, where manage.py is located. Activate your corresponding environment, here, I use django. Then, you can download and install uWSGI.

1
conda install -c conda-forge uwsgi

If you use pip to install uwsgi, you may encounter some errors due to gcc version. So a conda install is preferred.

Important! Notice that, a global uwsgi won’t work! In that case, uwsgi wouldn’t locate correct Python environment. So you have to download it in this way.

Add uwsgi.ini

To use uwsgi as a host of our Django project, we need a uwsgi.ini.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[uwsgi]
#socket = 127.0.0.1:5050
http = 127.0.0.1:5050
chdir = /home/server/backend
wsgi-file = /home/server/backend/backend_demo/wsgi.py
master = true
enable-threads = true
processes = 8
buffer-size = 65536
vacuum = true
daemonize = /home/server/backend/uwsgi.log
pidfile = /home/server/backend/uwsgi.pid
virtualenv = /home/ubuntu/opt/miniconda3/envs/django
uwsgi_read_timeout = 600
threads = 4
chmod-socket = 664

Some explanation to it. Technically, you can use relative path here. But absolute path can make sure no path related problem happens.

socket, http: For these two, only one is needed. If you use Nginx, then use socket, and there will be no need to add port number. If you use uwsgi to run Django directly, use http, and you need add port number here.

You may need to replace 127.0.0.1 with 0.0.0.0 if you could not access the server remotely.

chdir: This indicates the root folder of the backend project. This is where manage.py locates.

wsgi-file: This is the wsgi.py file of your project.

processes: This specifies the process number of uWSGI.

daemonize: Well, this is the log file. Daemon process of uWSGI will put logs here.

pidfile: This file stores the pid of uWSGI process, can be used to shut down uWSGI service.

virtualenv: The virtual environment of your Django project. This can be found under your conda installation location. Usually ${conda_home}/env/${env_name}.

The others are not that important, so I’m not going to spend time on them.

Launch uWSGI

Now that we haven’t setup Nginx yet, we should comment socket in uwsgi.ini out, and use http instead.

In your Django project root folder, run this to launch uWSGI. This tells it to use uwsgi.ini file to initialize, then it will run automatically.

1
uwsgi --ini uwsgi.ini

You can check it by find its processes.

1
ps aux | grep uwsgi

If no process, you can check uwsgi.log file for more information. If you installed uwsgi the same way as me, you should encounter no error.

Stop uWSGI

Well, start and end always come together. If you set pidfile, it will be quite easy.

1
2
uwsgi --stop uwsgi.pid
sudo pkill -f uwsgi # use it only when you don't have uwsgi.pid

Step 3. Setup Nginx

Introduction

Well, Nginx, pronounced “Engine-X”, is an HTTP and reverse proxy server, a mail proxy server, and a generic TCP/UDP proxy server.

Basically, it works like this. For front end, it monitors certain ports, such as the common 80. Then, depending on the url, it will redirect access to other ports, such as /api.

Install Nginx

Emm… Quite easy, huh.

1
sudo apt install nginx

Configure Nginx

Usually, Nginx configuration file locates here: /etc/nginx/conf.d/default.conf. The name of it can vary. If it doesn’t exist, just create one. And this operation need root permission.

1
sudo vim /etc/nginx/conf.d/default.conf

Tips: Almost all Nginx commands need root permission.

Then, add the following configurations to it. This configuration will set frontend to xx.xx.xx.xx:80, or simply xx.xx.xx.xx. And backend to xx.xx.xx.xx/api.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
server {
listen 80;
server_name xx.xx.xx.xx;

location / {
root /home/server/front;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}

location /api {
include /etc/nginx/uwsgi_params;
uwsgi_pass 127.0.0.1:4000;
}

error_page 497 https://$host$uri?$args;
}

Some explanations.

listen: The port of front end. Usually 80.

server_name: The public IP address of your server.

location: This is used to redirect access. For example, / here means xx.xx.xx.xx/, and /api means xx.xx.xx.xx/api. So, if a url is like xx.xx.xx.xx/api/login, it will redirect it to xx.xx.xx.xx:4000/api/login.

Notice! We could not access xx.xx.xx.xx:4000 directly.

More about location. Here, location / is for front end. root is the root folder of your front end project. And others can remain the same. location /api is for backend. Here, since we use uwsgi, so we should add a include for it. Then, is our uwsgi_pass, it should be the same as what we assigned in uwsgi.ini. It tells Nginx to redirect requests to uWSGI port.

/api here is just a prefix that we set in Django project. You can change it, of course. But make sure it is consistent with the url pattern in Django.

Launch Nginx

Now that we have configured Nginx, we can start it. Before we start, make sure you change uwsgi.ini to use socket instead of http. Remember?

First, launch Nginx service. You can use either of these. Perhaps it is already online.

1
2
sudo nginx
systemctl start nginx.service

Then, if any modification is made to the configuration file, a reload would be necessary.

1
sudo nginx -s reload

Now, you can access both frontend and backend.

Stop Nginx

Emm… Again, start and end. Here is how to stop Nginx.

1
2
sudo nginx -s quit # stop after current process finishes its work
sudo nginx -s stop # stop immediately

Well, this is it. Configuring internet service is really… annoying… Barnacles. 😵‍💫