Django is a python framework used for developing dynamic websites and applications. It follows the MVC (Model-View-Controller) architecture. Using Django speeds up the development process as most of the underlying tasks are handled by it.
This tutorial will teach you how to install the Django framework on a Ubuntu 22.04 server. You will also create a demo project and test it out.
Prerequisites
-
A server running Ubuntu 22.04.
-
A non-root sudo user.
-
Make sure everything is updated.
$ sudo apt update $ sudo apt upgrade
Install Django
There are several methods by which you can install Django. Deciding which works for you best depends on how you want to configure your development environment and your needs. Each method has its own set of pros and cons. Let us go through all these methods.
Install from Ubuntu Repositories
The simplest method to install Django is using Ubuntu's repositories. Ubuntu 22.04 ships with Python 3.10. You can verify it using the following command.
$ python3 -V Python 3.10.4
Install Django using the following command.
$ sudo apt install python3-django
Run the following command to verify the successful install.
$ django-admin --version 3.2.12
The Django version shipped with Ubuntu is the current LTS version which is supported till 2024. However, it is not the current version. If you want to install a recent release, this method is not for you.
Install using pip
This is the most common way to install Django. The recommended way to do it is by creating a virtual Python environment. This allows you to install Python packages without affecting the system.
Install pip
and venv
module. venv
is used to create Python virtual environments and pip
install Python packages.
$ sudo apt install python3-pip python3-venv
Let us create a demo project directory.
$ mkdir ~/sampleproject $ cd ~/sampleproject
Create a virtual environment using the following command. Replace sample_env
with the name, you want to call your virtual environment.
$ python3 -m venv sample_env
This installs a portable version of Python, pip within your project directory. To install any packages into the project, you must activate the environment using the following command.
$ source sample_env/bin/activate
Your shell prompt will change to reflect the virtual environment.
(sample_env) navjot@django:~/sampleproject$
Now that the virtual environment is activated, use pip
to install Django. Run the following command to install Django.
(sample_env) $ pip install django
Verify the installation.
(sample_env) $ django-admin --version 4.0.5
Depending upon your project requirements, you can install a different version of Django in the following way.
(sample_env) $ pip install django==3.2.1
Verify the installation.
(sample_env) $ django-admin --version 3.2.1
As you can see, this method installs a newer version of Django than the version obtained from the Ubuntu repository.
To exit the virtual environment, run the following command.
(sample_env) $ deactivate
Install the development version
You can also use pip
to install the development version of Django. For this, we will grab the development version from Django's Github repository.
Clone the repository to the ~/django-dev
directory using the following command.
$ git clone https://github.com/django/django ~/django-dev
Switch to the newly created directory.
$ cd ~/django-dev
Create the virtual environment.
$ python3 -m venv dev_django_env
Activate the environment.
$ source dev_django_env/bin/activate
Install Django using pip
. The -e
flag installs it in an editable mode which is required if you are installing from version control.
(dev_django_dev) $ pip install -e ~/django-dev
Verify the installation.
(dev_django_dev) $ django-admin --version 4.2.dev20220628195651
As you can see, the version here is the latest development version. The development version of Django is not useful for production environments.
Create a Sample Project
Let us build a sample Django project. Create a directory for the sample project.
$ mkdir ~/dj-sample $ cd ~/dj-sample
Create a Python virtual environment.
$ python3 -m venv sample_proj
Activate the environment.
$ source sample_proj/bin/activate
Install Django.
(sample_proj) $ pip install django
To build the project, we need to use the startproject
command. This command creates another directory that includes:
- A management script,
manage.py,
used to administer Django-specific tasks. - A directory with the same name as the project that includes the project code.
We will create the project directory in our current working directory. To do that, use the dot(.) character at the end of the following command.
(sample_proj) $ django-admin startproject demoproject .
Next, we need to migrate the database using the migrate
command. Migrations in Django propagate changes you make to your models into your database schema. Python uses SQLite database by default.
(sample_proj) $ python manage.py migrate
You will get the following output.
Operations to perform: Apply all migrations: admin, auth, contenttypes, sessions Running migrations: Applying contenttypes.0001_initial... OK Applying auth.0001_initial... OK Applying admin.0001_initial... OK Applying admin.0002_logentry_remove_auto_add... OK Applying admin.0003_logentry_add_action_flag_choices... OK Applying contenttypes.0002_remove_content_type_name... OK Applying auth.0002_alter_permission_name_max_length... OK Applying auth.0003_alter_user_email_max_length... OK Applying auth.0004_alter_user_username_opts... OK Applying auth.0005_alter_user_last_login_null... OK Applying auth.0006_require_contenttypes_0002... OK Applying auth.0007_alter_validators_add_error_messages... OK Applying auth.0008_alter_user_username_max_length... OK Applying auth.0009_alter_user_last_name_max_length... OK Applying auth.0010_alter_group_name_max_length... OK Applying auth.0011_update_proxy_permissions... OK Applying auth.0012_alter_user_first_name_max_length... OK Applying sessions.0001_initial... OK
Next, create an administrative user to access Django's admin interface.
(sample_proj) $ python manage.py createsuperuser
You will be prompted for a username, email, and password.
Username (leave blank to use 'navjot'): Email address: name@example.com Password: Password (again): Superuser created successfully.
Test the Development Server
It is time to test the application. For that, you need to modify the ALLOWED_HOSTS
directive in the Django settings. This directive defines the list of IP addresses and domain names that are given access to the Django application.
Open the settings file using the following command.
(sample_proj) $ nano demoproject/settings.py
Find the following entry.
ALLOWED_HOSTS = []
Enter your server IP address in the square brackets. Each entry should be enclosed within quotations and multiple entries need to be separated via commas. Entering www.example.com
will be matched exactly. However, .example.com
will match example.com
and www.example.com
, and any other subdomain of example.com
. Therefore, using the period sign to prefix a domain name to match it and its subdomains is recommended.
ALLOWED_HOSTS = ['<yourserver_ip_address>']
We have used the IP address to match our server. Save the file by pressing Ctrl + X and entering Y when prompted.
Before you test the development server, you need to configure the firewall to allow Django to work. Django uses port 8000 by default. Open the port using the Uncomplicated Firewall(UFW).
(sample_proj) $ sudo ufw allow 8000
Start the development server.
(sample_proj) $ python manage.py runserver 0.0.0.0:8000
Launch the URL http://<yourserver_ip_address>:8000
in your browser and you will get the following screen.
You can access the admin interface by following the URL http://<yourserver_ip_address>:8000/admin/
and you will see the following login screen.
Enter the credentials created earlier to log in to the admin panel shown below.
Once you finish your demo project, you can close the server by pressing Ctrl + C in your terminal.
Install and Test Gunicorn
Run persistent Django server using nohup
So far, Django's service is not persistent. To make the service persistent, there are two methods. The first method involves using the nohup
utility. The nohup
is a POSIX command which means no hang up. It is used to execute commands in a way that does not stop even when a user logs out.
Make sure you have exited the server from the terminal by pressing Ctrl + C.
Run the following command to run Django's development server.
(sample_proj) $ nohup python manage.py runserver 0.0.0.0:8000 &
Now, your Django server will keep running until you kill it manually. The command will give you the process ID and output another command.
[1] 42595 (sample_proj) $ nohup: ignoring input and appending output to 'nohup.out' ^C
Press Ctrl + C to exit. The original Django server will keep running. You can verify by opening the URL in your browser.
Once you are finished, you need to kill the process. The nohup
command gives you one process ID. But in reality, two processes are being run. To find the IDs for both processes, run the following command.
(sample_proj) $ ps aux | grep manage.py navjot 42650 3.6 1.8 47792 38168 pts/0 S 02:28 0:00 python manage.py runserver 0.0.0.0.:8000 navjot 42651 7.9 2.0 344904 41708 pts/0 Sl 02:28 0:00 /home/navjot/dj-sample/sample_proj/bin/python manage.py runserver 0.0.0.0:8000 navjot 42657 0.0 0.1 6612 2172 pts/0 S+ 02:28 0:00 grep --color=auto manage.py
As you can see, two processes are being run, one with ID 42650 and the other one with ID 42651.
Run the following command to shut the server using the process IDs you obtained above.
(sample_proj) $ sudo kill -9 42650 42651
Install Gunicorn
The second method to run a persistent Django server requires you to install Gunicorn and Nginx web servers. Gunicorn is a Python WSGI HTTP server. It will interface with the Django application and then Nginx will act as a reverse proxy to Gunicorn. This method has the added benefit of providing you with the security and performance that comes with using Nginx.
Install Gunicorn.
(sample_proj) $ pip install gunicorn
Before proceeding, we need to test Gunicorn's ability to serve the project. Run the following command to run Gunicorn.
(sample_proj) $ gunicorn --bind 0.0.0.0:8000 demoproject.wsgi
This will start Gunicorn on the same interface Django was running on. To verify, open the URL http://<yourserver_ip_address>:8000
in your browser and you will get the same Django homepage. This means that Gunicorn is running perfectly.
When you are finished testing, press Ctrl + C on the terminal to exit Gunicorn.
Deactivate the virtual environment to go back to your regular shell.
(sample_proj) $ deactivate
Create a Socket and Service file for Gunicorn
The first step is to create a Gunicorn socket file. The Gunicorn socket will be created at boot time and listen for connections. When a connection occurs, the systems
will automatically start the Gunicorn process to handle it.
Create and open the Gunicorn socket file for editing.
$ sudo nano /etc/systemd/system/gunicorn.socket
Paste the following code in it.
[Unit] Description=gunicorn socket [Socket] ListenStream=/run/gunicorn.sock [Install] WantedBy=sockets.target
Save the file by pressing Ctrl + X and entering Y when prompted.
Next, create and open the Gunicorn service file for editing.
$ sudo nano /etc/systemd/system/gunicorn.service
Paste the following code in it.
[Unit] Description=django gunicorn daemon Requires=gunicorn.socket After=network.target [Service] User=navjot Group=nginx WorkingDirectory=/home/navjot/dj-sample ExecStart=/home/navjot/dj-sample/sample_proj/bin/gunicorn \ --access-logfile - \ --workers 3 \ --bind unix:/run/gunicorn.sock \ demoproject.wsgi:application [Install] WantedBy=multi-user.target
Save the file by pressing Ctrl + X and entering Y when prompted. Replace navjot
with your system username. The nginx
group will allow the Nginx server to communicate with Django.
Reload the system daemon to refresh the systemd files.
$ sudo systemctl daemon-reload
Enable and start the Gunicorn socket file.
$ sudo systemctl start gunicorn.socket $ sudo systemctl enable gunicorn.socket
Check the status of the Gunicorn socket.
$ sudo systemctl status gunicorn.socket
You will receive a similar output.
? gunicorn.socket - gunicorn socket Loaded: loaded (/etc/systemd/system/gunicorn.socket; disabled; vendor preset: enabled) Active: active (listening) since Thu 2022-06-30 01:43:24 UTC; 20s ago Triggers: ? gunicorn.service Listen: /run/gunicorn.sock (Stream) CGroup: /system.slice/gunicorn.socket Jun 30 01:43:24 django systemd[1]: Listening on gunicorn socket.
The Gunicorn service is still not running as you can check.
$ sudo systemctl status gunicorn.service ? gunicorn.service - django gunicorn daemon Loaded: loaded (/etc/systemd/system/gunicorn.service; disabled; vendor preset: enabled) Active: inactive (dead) TriggeredBy: ? gunicorn.socket
To test the socket activation mechanism, run the following command.
$ curl --unix-socket /run/gunicorn.sock localhost
You will receive the HTML output of the Django homepage in your terminal. This also starts Gunicorn to serve the application. Check the status of the service again and you will see that it is running now.
$ sudo systemctl status gunicorn.service ? gunicorn.service - django gunicorn daemon Loaded: loaded (/etc/systemd/system/gunicorn.service; disabled; vendor preset: enabled) Active: active (running) since Thu 2022-06-30 01:45:09 UTC; 12s ago TriggeredBy: ? gunicorn.socket Main PID: 42365 (gunicorn) Tasks: 4 (limit: 2241) Memory: 91.7M CPU: 1.128s CGroup: /system.slice/gunicorn.service ??42365 /home/navjot/dj-sample/sample_proj/bin/python3 /home/navjot/dj-sample/sample_proj/bin/gunicorn --access-logfile - --workers 3 --bind unix:/run/gunicorn.sock demoproject.wsgi:application ??42366 /home/navjot/dj-sample/sample_proj/bin/python3 /home/navjot/dj-sample/sample_proj/bin/gunicorn --access-logfile - --workers 3 --bind unix:/run/gunicorn.sock demoproject.wsgi:application ??42367 /home/navjot/dj-sample/sample_proj/bin/python3 /home/navjot/dj-sample/sample_proj/bin/gunicorn --access-logfile - --workers 3 --bind unix:/run/gunicorn.sock demoproject.wsgi:application ??42368 /home/navjot/dj-sample/sample_proj/bin/python3 /home/navjot/dj-sample/sample_proj/bin/gunicorn --access-logfile - --workers 3 --bind unix:/run/gunicorn.sock demoproject.wsgi:application Jun 30 01:45:09 django systemd[1]: Started django gunicorn daemon. Jun 30 01:45:09 django gunicorn[42365]: [2022-06-30 01:45:09 +0000] [42365] [INFO] Starting gunicorn 20.1.0 Jun 30 01:45:09 django gunicorn[42365]: [2022-06-30 01:45:09 +0000] [42365] [INFO] Listening at: unix:/run/gunicorn.sock (42365) Jun 30 01:45:09 django gunicorn[42365]: [2022-06-30 01:45:09 +0000] [42365] [INFO] Using worker: sync Jun 30 01:45:09 django gunicorn[42366]: [2022-06-30 01:45:09 +0000] [42366] [INFO] Booting worker with pid: 42366 .......
Install Nginx
The last step is to install and configure Nginx. Ubuntu 22.04 ships with an older version of Nginx. You need to download the official Nginx repository to install the latest version.
Import Nginx's signing key.
$ curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor \ | sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null
Add the repository for Nginx's stable version.
$ echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg arch=amd64] \ http://nginx.org/packages/ubuntu `lsb_release -cs` nginx" \ | sudo tee /etc/apt/sources.list.d/nginx.list
Update the system repositories.
$ sudo apt update
Install Nginx.
$ sudo apt install nginx
Verify the installation.
$ nginx -v nginx version: nginx/1.22.0
Configure Nginx
Create and open the file /etc/nginx/conf.d/django-gunicorn.conf
for editing.
$ sudo nano /etc/nginx/conf.d/django-gunicorn.conf
Paste the following code in it.
server { listen 80; server_name server_domain_or_IP; location = /favicon.ico { access_log off; log_not_found off; } location /static/ { root /home/navjot/dj-sample; } location / { proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_pass http://unix:/run/gunicorn.sock; } }
Replace the root location in the above file with the directory on your server.
Save the file by pressing Ctrl + X and entering Y when prompted.
Open the file /etc/nginx/nginx.conf
for editing.
$ sudo nano /etc/nginx/nginx.conf
Add the following line before the line include /etc/nginx/conf.d/*.conf;
.
server_names_hash_bucket_size 64;
Save the file by pressing Ctrl + X and entering Y when prompted.
Verify your Nginx configuration.
$ sudo nginx -t
If you see no errors, it means you are good to go.
You will also need to add the domain name to your ALLOWED_HOSTS
directive. Open the settings.py
file.
$ nano ~/dj-sample/demoproject/settings.py
Change the value for ALLOWED_HOSTS
variable.
ALLOWED_HOSTS = ['<yourserver_ip_address>','django.example.com']
Save the file by pressing Ctrl + X and entering Y when prompted.
Restart Gunicorn Socket and Service.
$ sudo systemctl restart gunicorn.socket $ sudo systemctl restart gunicorn.service
Start the Nginx server.
$ sudo systemctl start nginx
Open the HTTP port. You can also delete the 8000 port if you are not going to use it anymore.
$ sudo ufw delete allow 8000 $ sudo ufw allow http
Verify by opening the URL http://django.example.com
and the Django homepage will load up.
Install SSL
So far, your Django application is being served over a plaintext HTTP connection. It is highly recommended that you protect it via an SSL certificate. For this, use the Certbot tool using the Snapd tool. It is already installed on a Ubuntu 22.04 system.
Install the core Snapd repository.
$ sudo snap install core
Install Certbot.
$ sudo snap install --classic certbot $ sudo ln -s /snap/bin/certbot /usr/bin/certbot
Generate the certificate. The following command will also automatically configure Nginx.
$ sudo certbot --nginx --agree-tos --no-eff-email --staple-ocsp --preferred-challenges http -m name@example.com -d django.example.com
Open the HTTPS port first.
$ sudo ufw allow https
Visit the URL https://django.example.com
in your browser to confirm.
Conclusion
This concludes our tutorial, where you learned how to install Django and Gunicorn and Nginx on a Ubuntu 22.04 server. You also installed an SSL certificate to enhance the security of your Django project. If you have any questions, post them in the comments below.