1. Update Your Server
It’s always a good idea to start by updating your server.
sudo apt-get update
sudo apt-get upgrade
Now we have the latest and greatest packages installed on the server.
2. Use a Virtual Environment for Python
The venv module allows you to create virtual Python environments. This allows you to isolate installed packages from the system.
After installing venv, make a directory to house your virtual environments, and then create a virtual environment named env using venv. You can call your virtual environment whatever you prefer.
sudo apt-get install python3-venv
mkdir Workstations && cd Workstations
python3 -m venv env
Now activate your virtual environment.
source env/bin/activate
You will see the name of your virtual environment in the parenthesis as a prefix to your env
3. Create a Django Project
Now we install the Django web framework using the pip package installer.
pip install Django
Next let’s create a Django project with django-admin which should be on your path by default. Feel free to choose a project name that suites you. For example we will use the name of our project called mysite.
django-admin startproject mysite
cd mysite
Now test our project using following commands:
python manage.py runserver 0.0.0.0:8000
In a browser, you should be able to visit mysite:8000 and see the default Django landing page, if not, you might you be see a error message like this:
if you see this error message, add your domain name to the mysite/settings.py
file.
Try to visit mysite.com:8000
again and this time you will see the Django landing page.
4. Get Started with uWSGI
First we need to install the web server gateway interface (WSGI). In this case, we will be using uWSGI
. You will also need the development packages for your version of Python to be installed.
sudo apt-get install python3.8-dev
sudo apt-get install gcc
pip install uwsgi
We will see to send requests from the client to Nginx which will pass them to a socket that will hand them off to uWSGI before finally being given to Django.
Create a file called server-test.py
with the following content:
def application(env, start_response):
start_response('200 OK', [('Content-Type','text/html')])
return [b"Hello World!"]
Let's test our uWSGI directly talking to python with the following command
uwsgi --http :8000 --wsgi-file server-test.py
In a browser, you should be able to visit mysite.com:8000 and see the test Hello World!
If this works for you, we have demonstrated that uWSGI is able to pass requests to Python.
Now we can similarly serve the Django Project with the following command:
uwsgi --http :8000 --module mysite.wsgi
Note that this works because the path mysite/wsgi.py exists.
5. Configure the Nginx Web Server
Install Nginx with apt-get as follows:
sudo apt-get install nginx
Now with Nginx installed, you will be able to visit the default Welcome to nginx!
page in your browser at http://mysite.com .
Let’s tell Nginx about our Django project by creating a configuration file at /etc/nginx/sites-available/mysite.conf
. Change the highlighted lines to suite your needs.
# the upstream component nginx needs to connect to
upstream django {
server unix:///home/emdad/mysite/mysite.sock;
}
# configuration of the server
server {
listen 80;
server_name mysite.com www.mysite.com;
charset utf-8;
# max upload size
client_max_body_size 75M;
# Django media and static files
location /media {
alias /home/emdad/mysite/media;
}
location /static {
alias /home/emdad/mysite/static;
}
# Send all non-media requests to the Django server.
location / {
uwsgi_pass django;
include /home/emdad/mysite/uwsgi_params;
}
}
We need to create the /home/emdad/mysite/uwsgi_params
file highlighted above on line 26 as well.
uwsgi_param QUERY_STRING $query_string;
uwsgi_param REQUEST_METHOD $request_method;
uwsgi_param CONTENT_TYPE $content_type;
uwsgi_param CONTENT_LENGTH $content_length;
uwsgi_param REQUEST_URI $request_uri;
uwsgi_param PATH_INFO $document_uri;
uwsgi_param DOCUMENT_ROOT $document_root;
uwsgi_param SERVER_PROTOCOL $server_protocol;
uwsgi_param REQUEST_SCHEME $scheme;
uwsgi_param HTTPS $https if_not_empty;
uwsgi_param REMOTE_ADDR $remote_addr;
uwsgi_param REMOTE_PORT $remote_port;
uwsgi_param SERVER_PORT $server_port;
uwsgi_param SERVER_NAME $server_name;
Next we can publish our changes by creating a symbolic link from sites-available
to sites-enabled
like so:
sudo ln -s /etc/nginx/sites-available/mysite.conf /etc/nginx/sites-enabled/
We must edit the mysite/settings.py
file to explicitly tell Nginx where our static files reside.
First add import os at the very beginning:
"""
Django settings for mysite project.
Generated by 'django-admin startproject' using Django 3.1.2.
For more information on this file, see
https://docs.djangoproject.com/en/3.1/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/3.1/ref/settings/
"""
import os
from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
and STATIC_ROOT = os.path.join(BASE_DIR, "static/") at the very end:
...
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.1/howto/static-files/
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, "static/")
With these changes in place, we can now tell Django to put all static files in the static folder.
python manage.py collectstatic
Restart the Nginx server to apply changes.
sudo /etc/init.d/nginx restart
At this point if you visit http://mysite.com a browser, you will probably see an Nginx 502 Bad Gateway error,
mkdir media
wget https://www.google.com/logos/doodles/2020/thank-yo…c-transportation-workers-6753651837108759-2xa.gif -O media/media.gif
Finally visit http://mysite.com/media/media.gif in a browser and you should see the image
6. Get Nginx, uWSGI, and Django to Work Together
Let’s take this one step further and have Nginx, uWSGI, and Django work together with the help of the UNIX socket.
uwsgi --socket mysite.sock --module mysite.wsgi --chmod-socket=666
You can actually try the above command without the --chmod-socket=666
argument and/or with a --chmod-socket=664
argument instead. If either of those work for you, just keep that in mind going forward.
Once again, visit http://mysite.com in a browser, and this time you should see the default Django landing page!
7. Configure uWSGI for Production
we configure a file at the root of your Django project called mysite_uwsgi.ini .
[uwsgi]
# full path to Django project's root directory
chdir = /home/emdad/mysite/
# Django's wsgi file
module = mysite.wsgi
# full path to python virtual env
home = /home/emdad/env
# enable uwsgi master process
master = true
# maximum number of worker processes
processes = 10
# the socket (use the full path to be safe
socket = /home/emdad/mysite/mysite.sock
# socket permissions
chmod-socket = 666
# clear environment on exit
vacuum = true
# daemonize uwsgi and write messages into given log
daemonize = /home/emdad/uwsgi-emperor.log
You can then proceed to start up uwsgi and specify the ini file:
uwsgi --ini mysite_uwsgi.ini
visit http://mysite.com in a browser and see the default Django landing page if everything works correctly.
As one last configuration option for uWSGI, let’s run uWSGI in emperor mode. This will monitor the uWSGI config file directory for changes and will spawn vassals (i.e. instances) for each one it finds.
cd /home/emdad/mysite/env/
mkdir vassals
sudo ln -s /home/emdad/mysite/mysite_uwsgi.ini /home/emdad/env/vassals/
Now you can run uWSGI in emperor mode as a test.
uwsgi --emperor /home/emdad/env/vassals --uid www-data --gid www-data
Visit http://mysite.com a browser and you will see the default Django landing page if everything works correctly.
Finally, we want to start up uWSGI when the system boots. Create a systemd service file at /etc/systemd/system/emperor.uwsgi.service with the following content:
[Unit]
Description=uwsgi emperor for mysite domains website
After=network.target
[Service]
User=emdad
Restart=always
ExecStart=/home/emdad/mysite/env/bin/uwsgi --emperor /home/emdad/mysite/env/vassals --uid www-data --gid www-data
[Install]
WantedBy=multi-user.target
Enable the service to allow it to execute on system boot and start it so you can test it without a reboot.
systemctl enable emperor.uwsgi.service
systemctl start emperor.uwsgi.service
Visit http://mysite.com a browser and you will see the default Django landing page if everything works correctly.
Check the status of the service and stop it as follows:
systemctl status emperor.uwsgi.service
systemctl stop emperor.uwsgi.service
Now reboot your system to make sure that your website is accessible at startup.
Top comments (0)