Deploy Django project with nginx and uWSGI
I’m a fan of python, I find it cool, simple, elegant. When I wanted to start my first project, I searched if they exist a framework for web development with Python. That’s how I found Django and I used it for my first project (Hachther Frence): I found it great. But one of my challenges was to deploy my project in production and that is why I decide to write this article: “Deploy Django project with nginx and uWSGI” to share my experience.
All Django developers know this command: ./manager.py runserver 0.0.0.0:8000
which is used to start the server in development mode. My first reflex was to start this command in background and configure nginx to connect on it: BIG MISTAKE. I quickly started to have performance issues and that when I find out that this was not the way to deploy a project in production mode.
In the next, I will show you how I managed to deploy my project on Ubuntu 16.04. So, all commands used will be Ubuntu commands.
Before Deploy Your Project
Before the deployment, there is a set of elements you need to check at the security or optimisation point of view. In order to do that you can type this command manager.py check --deploy
to check the parameters below.
SECRET_KEY
This is used for security of encrypted data on the project. This value must be long, random and secret. So, in order to keep it secret you must not share it in your repository: you can store it in an environment variable
os.environ['SECRET_KEY']
or you can save it in a file:
with open('/etc/secret_key.txt') as f: SECRET_KEY = f.read().strip()
DEBUG an ALLOWED_HOSTS
You must set DEBUG variable to DEBUG = False
in the configuration file. This will put your project in production mode.
When you set DEBUG to False, you must set ALLOWED_HOSTS with the list of hosts allowed to have access to your project. Example: ALLOWED_HOSTS = (example1.domain.com, example2.domain.com, ...)
Other Parameters
For the optimisation purpose of your application, you must think about elements like: cache, databases, logging, etc. Go to this link for more detail: https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/.
Now that everything is OK on the Django side, let us continue with uWSGI.
uWSGI
uWSGI is a fast and dynamic server content. It stays between the web server (nginx in our case) and you Django application. uWSGI is an implementation of WSGI (Web Server Gateway Interface) protocol which uses to respond to the client request by using the Unix socket.
Installation
Installation is quite simple. You can use pip the packet manager of python and install the version in the repository or you can install it from a link.
# Install current stable version. $ pip install uwsgi # Or install LTS (long-term support) version. $ pip install https://projects.unbit.it/downloads/uwsgi-lts.tar.gz
Configure and start uWSGI
Configure and start can be done in two ways: by passing the parameters in command line or by setting parameters in an ini file and pass the file path as parameters in command line.
We will use the second option: we will create a .ini file, put all parameters within and launch uwsgi server with this command: uwsgi --ini /path/to/uwsgi.ini
Let’s create a “config” folder at the root of the project and put the uwsgi.ini file within (you can change the name). Find below what the content will look like.
[uwsgi] # variables projectname = ProjectName base = /absolute/path/to/project/ # configuration master = True pythonpath = %(base) chdir = %(base) env = DJANGO_SETTINGS_MODULE=%(projectname).settings module = [ProjectName].wsgi:application socket = /tmp/%(projectname).sock http-socket = 127.0.0.1:8001 uid = 33 gid = 33 touch-reload = %(base)/config/uwsgi.ini vacuum = True processes = 5 harakiri = 40
Brief description of above parameters:
- projectname: containing the name of the project.
- base: containing the absolute path of the project.
- master: use to launch the process as master.
- pythonpath: is the absolute path to the source code of the project. In our case we use base variable (%(base)).
- chdir: the folder from which we want it to be launched. In our case we launch it from the project folder.
- env: set environment variables on the start-up. We will set DJANGO_SETTINGS_MODULE which contains the settings of the project.
- module: in this case it is [ProjectName].wsgi:application
- socket: where the socket will be created. Our choose was to create it in /tmp/ with the project name.
- http-socket: this is to make your project natively speak with the HTTP protocol.
- uid and gid: to set the user and the group which will be used to launch the process. This can be useful to manage access right.
- touch-reload: use it to reload the process each time the last modification date of this file is changed. This can be used to manage the changes.
- vacuum: to delete the socket with the process end.
- processes: to set the number of processes to launch.
- harakiri: a request will be killed if the execution is taking more time than set in this parameter.
Once configure is done, you can use this command (uwsgi --ini /path/to/config.ini
) to launch your project.
Now, let give access to the project to the public by configuring nginx.
Configuration of nginx
The aim here is to configure a reverse proxy in nginx to communicate with your project. We assume that nginx is already installed if it is not the case, just type this command: sudo apt-get install nginx
to install it.
Create a config file in /etc/nginx/sites-enabled/[ProjectName].conf
and in this file, you can put the sample configuration below.
upstream [ProjectName] { server unix:///tmp/[ProjectName].sock; } server { listen 80; server_name example.domaine.com; location /static/ { alias /chemin/vers/projet/static/; } location /media/ { alias /chemin/vers/projet/media/; } location / { include /etc/nginx/uwsgi_params; uwsgi_pass [ProjectName]; } }
Replace [ProjectName] by the name of your project. Once the configuration is OK reload nginx and you are done. You can now access to your project through the internet with your domain name.
Conclusion
Configuration previously done allow to deploy your Django project in production mode. The touch-reload parameter really helps me to manage change on my project. Each time I make a change, I just need to type this command to reload the project: touch /path/to/uwsgi.ini
and apply the last changes.
Sources: