Installing Django on Ubuntu, uWSGI, PostgreSQL, and Celery+Redis
1. Install Python3 (If not installed)
$ sudo apt-get update
$ sudo apt-get install python3 python3-dev
2. Install PostgreSQL
$ sudo apt-get update
$ sudo apt-get install postgresql postgresql-contrib libpq-dev
During the Postgres installation, an operating system user named postgres was created to correspond to the postgres PostgreSQL administrative user.
We need to change to this user to perform administrative tasks:
$ sudo su - postgres
Log into a Postgres session by typing:
$ psql
First, we will create a database for our Django project. Each project should have its own isolated database for security reasons.
We will call our database myproject in this guide, but it’s always better to select something more descriptive:
> CREATE DATABASE myproject;
Remember to end all commands at an SQL prompt with a semicolon.
Create a database user which we will use to connect to and interact with the database.
> CREATE USER myprojectuser WITH PASSWORD 'password';
Modify a few of the connection parameters for the user just created to speed up database operations.
We are setting the default encoding to UTF-8, and timezone to UTC which Django expects.
We are also setting the default transaction isolation scheme to “read committed”, which blocks reads from uncommitted transactions.
> ALTER ROLE myprojectuser SET client_encoding TO 'utf8';
> ALTER ROLE myprojectuser SET default_transaction_isolation TO 'read committed';
> ALTER ROLE myprojectuser SET timezone TO 'UTC';
Give our database user access rights to the database we created:
> GRANT ALL PRIVILEGES ON DATABASE myproject TO myprojectuser;
Exit the SQL prompt to get back to the postgres user’s shell session:
> \q
Exit out of the postgres user’s shell session to get back to your regular user’s shell session:
$ exit
Optionally Change the
$ sudo nano /etc/postgresql/X/main/pg_hba.conf
local all postgres peer
Should be:
local all postgres md5
- If you can’t find this file, running ‘locate pg_hba.conf’ should show you where the file is.
After altering this file, restart PostgreSQL server.
$ sudo service postgresql restart.
3. Pull the project from Git store
$ cd ~
$ git clone https://gitlab.com/path/myproject.git
$ cd myproject/
Install Virtualenv
$ python3 -m venv venv
$ source venv/bin/activate
(venv) sudo -H pip3 install --upgrade pip
(venv) pip install -r requirements.txt
4. Configure the Django Database Settings
Now that we have a project, we need to configure it to use the database we created.
Install the psycopg2 package (if not in the requirement.txt) that will allow us to use the database we configured:
$ (venv) pip install psycopg2
Open the main Django project settings file located within the child project directory:
$ nano ~/myproject/myproject/settings.py
. . .
The simplest case: just add the domain name(s) and IP addresses of your Django server
ALLOWED_HOSTS = [ 'example.com', '203.0.113.5']
To respond to ‘example.com’ and any subdomains, start the domain with a dot
ALLOWED_HOSTS = ['.example.com', '203.0.113.5', 127.0.0.1] ALLOWED_HOSTS = ['your_server_domain_or_IP', 'second_domain_or_IP', . . .] . . . STATIC_URL = '/static/' STATIC_ROOT = os.path.join(BASE_DIR, 'static/')
Towards the bottom of the file, you will see a DATABASES section, change it to:
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.psycopg2', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. 'NAME': 'myproject', # Or path to database file if using sqlite3. # The following settings are not used with sqlite3: 'USER': 'myuser', 'PASSWORD': 'password', 'HOST': '127.0.0.1', # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP. 'PORT': '', # Set to empty string for default. } }
When you are finished, save and close the file.
5. Migrate the Database and Test your Project
Now that the Django settings are configured, we can migrate our data structures to our database and test out the server.
We can begin by creating and applying migrations to our database. Since we don’t have any actual data yet, this will simply set up the initial database structure:
$ cd ~/myproject
$ python manage.py makemigrations
$ python manage.py migrate
After creating the database structure, we can create an administrative account by typing:
$ python manage.py createsuperuser
Select a username, provide an email address, and password for the account.
Once you have an admin account set up, you can test that your database is performing correctly by starting up the Django development server:
$ python manage.py runserver 0.0.0.0:8000
In your web browser, visit your server’s domain name or IP address followed by :8000 to reach default Django root page:
http://server_domain_or_IP:8000
6. Install and Configure uWSGI
$ cd project/path
$ sudo pip3 install uwsgi
Test the uwsgi
$ uwsgi --http :8080 --home /home/myproject --chdir /home/myproject -w myproject.wsgi
Press CTRL+C to stop
Create uwsgi INI file
$ nano /etc/uwsgi/sites/myproject.ini [uwsgi] chdir = /home/myproject home = /home/myproject/venv module = myproject.wsgi:application master = true processes = 5 #socket = /run/uwsgi/myproject.sock protocol = http # Must be set to use http socket with systemd socket = :8080 chmod-socket = 666 vacuum = true die-on-term = true
To have uWSGI serve HTTP (instead of the binary uwsgi protocol) under Systemd socket activation, set protocol to http; for instance, in an INI, do this:
$ sudo nano /etc/systemd/system/uwsgi.service
[Unit] Description=uWSGI Emperor [Service] ExecStartPre=/bin/bash -c 'mkdir -p /run/uwsgi; chown www-data:www-data /run/uwsgi' ExecStart=/usr/local/bin/uwsgi --emperor /etc/uwsgi/sites Restart=always KillSignal=SIGQUIT Type=notify NotifyAccess=all [Install] WantedBy=multi-user.target
Make the file executable.
$ sudo chmod a+x /etc/systemd/system/uwsgi.service
Run the service
$ systemctl start uwsgi.service
$ systemctl status uwsgi.service
7. Install and Configure Nginx as a Reverse Proxy
$ sudo apt-get install nginx
$ sudo nano /etc/nginx/sites-available/myproject
server { listen 80; server_name myproject.com www.myproject.com; location = /favicon.ico { access_log off; log_not_found off; } location /static/ { root /home/myproject; } location / { include uwsgi_params; #uwsgi_pass unix:/run/uwsgi/myproject.sock; proxy_pass http://127.0.0.1:8080; } }
$ sudo ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled
$ sudo nginx -t
$ sudo service nginx restart
8. Troubleshoot
For NGINX errors
$ sudo tail -f /var/log/nginx/error.log
For others errors not in the standard log files
$ sudo tail -f /var/log/syslog
9. Using Celery and Redis for Background Task Processing
Step 1: Add celery.py
Inside the “myproject” directory, create a new file called celery.py:
$ nano ~/myproject/myproject/celery.py
from future import absolute_import import os from celery import Celery from django.conf import settings # set the default Django settings module for the 'celery' program. os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings') app = Celery('myproject') # Using a string here means the worker will not have to # pickle the object when using Windows. app.config_from_object('django.conf:settings', namespace='CELERY') app.autodiscover_tasks() @app.task(bind=True) def debug_task(self): print('Request: {0!r}'.format(self.request))
Step 3: Install Redis as a Celery “Broker”
$ sudo apt update
$ sudo apt install redis-server
$ sudo nano /etc/redis/redis.conf
The supervised directive is set to no by default. Since you are running Ubuntu, which uses the systemd init system, change this to systemd
$ sudo systemctl restart redis.service
$ sudo systemctl status redis
$ redis-cli
127.0.0.1:6379> ping
PONG
Check the redis binding
$ sudo netstat -lnp | grep redis
Once Redis is up, add the following code to your settings.py file:
$ nano ~/myproject/myproject/settings.py
# CELERY STUFF BROKER_URL = 'redis://localhost:6379' CELERY_RESULT_BACKEND = 'redis://localhost:6379' CELERY_ACCEPT_CONTENT = ['application/json'] CELERY_TASK_SERIALIZER = 'json' CELERY_RESULT_SERIALIZER = 'json' CELERY_TIMEZONE = 'UTC' CELERY_BEAT_SCHEDULE = { 'task1': { 'task': 'Joliba.tasks.task1', 'schedule': crontab(minute='*/10'), }, }
Install the celery and redis package (if not in the requirement.txt)
(venv) $ pip install celery redis
Restart the uwsgi application
$ sudo systemctl restart uwsgi.service
10. Add SSL for the website using letsencrypt.
Adding SSL with Let’s Encrypt and NGINX