Django is a framework that can help your Python application or website take off. Django also includes a simplified development server for testing code locally, but any production service requires a more secure and powerful web server.
In this article, we explain how to install and configure several components on a VPS with the HestiaCP(Ubuntu 20.04) image to support and serve Django applications. First, you will create a Mysql database and configure the Gunicorn application server to interact with the applications. Then, you will create templates in HestiaCP to configure Nginx as a reverse proxy for Gunicorn, giving you access to its security and performance features for serving the applications.
Install the required packages
To begin, you will need to download and install all the required items from the Ubuntu repositories. You will then also use Python's pip package manager to install additional components.
To do this, run the following commands:
# apt update && apt upgrade -y
# apt install -y python3-pip python3-dev libmysqlclient-dev pkg-configThis will install pip, the Python development files needed to install Gunicorn later, and the libraries required to interact with Mysql.
Create the Mysql database
Access the HestiaCP administration panel at https://ip_pública:8083, go to "DB" and click "Add Databases".
In the new window, set a database name, username, and password and click save.
Your database is now ready.
Create a Python virtual environment for your project
Now that you have your database, you can work on the remaining requirements to get the project ready. Install the Python requirements in a virtual environment to make them easier to manage.
To do this, you first need access to the virtualenv command. You can install it with pip.
# pip3 install virtualenvWith virtualenv installed, you can start setting up your project. Create a directory for your project files inside your domain's folder, then change to it:
# cd /home/nombre_usuario/web/nombre_dominio/public_html
# mkdir miproyecto
# cd miproyectoInside the project directory, create a Python virtual environment with the command:
# virtualenv miproyectoentornoThis will create a directory named “miproyectoentorno” inside the “miproyecto” directory. It will install a local version of Python and a local version of pip there. You can use this to install and configure an isolated environment for the project.
Before installing the Python requirements for your project, you must activate the virtual environment. You can do this by running:
# source miproyectoentorno/bin/activateThe prompt should change to indicate that you are now working inside a Python virtual environment. It should look something like this:
(miproyectoentorno)user@host:~/miproyecto$.With the virtual environment active, install Django, Gunicorn, and the mysqlclient adapter for Mysql using the local instance of pip:
# pip install django gunicorn mysqlclientRegardless of the Python version you are using, once the virtual environment is activated, you must use the pip command (not pip3).
Create and configure a new Django project
Since you already have a project directory, you need to tell Django to install the files there. This will create another directory inside the main one containing the actual code, which is normal, and place a management script in this directory.
# django-admin startproject miproyectoAdjust the project settings
The first thing to do after creating your files is to adjust the settings. Open the configuration file with a text editor:
# vi miproyecto/miproyecto/settings.pyFirst, find the section that configures database access. It starts with DATABASES. The configuration in the file is for a SQLite database. We have already created a Mysql database for our project, so you need to adjust the configuration.
Update the configuration with the information for the Mysql database. Then you need to tell Django to use the Mysqlclient adapter you installed with pip. You need to provide the database name, username, and password, then indicate that the database is local. You can leave PORT as an empty string, as in this example for "miproyecto/miproyecto/settings.py":
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'admin_django',
'USER': 'admin_app',
'PASSWORD': 'contraseña',
'HOST': 'localhost',
'PORT': '',
}
} NAME and USER must match the name and username that HestiaCP assigned internally when you created the database earlier:
Go to the end of the file and add the setting for where to store static files. This is necessary so that Nginx can handle requests for these objects. The following line tells Django to put them in a directory named “static” in the project's base directory:
STATIC_URL = 'static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static/')You also need to add the following at the beginning of the document:
import os
Finally, allow all connections in "Allowed Host" or specify which IPs can connect:
ALLOWED_HOSTS = ['*',]Save and close the file when you have finished making changes.
You can now migrate the initial database schema to the MySQL database using the management script:
# cd miproyecto
# ./manage.py makemigrations
# ./manage.py migrateCreate an administrative user for the project by typing:
# ./manage.py createsuperuserYou will need to choose a username, provide an email address, and choose and confirm a password.
You can collect all static content in the directory location you configured by typing:
# ./manage.py collectstaticYou will need to confirm this operation. The static files will be saved in a directory named “static” inside the project directory.
To run the tests now, port 8000 must be open on your server and in the HestiaCP panel. Check whether the port is already open for your server. If it is not, open it by following this other article in our knowledge base:
Manage rules for a firewall profile in the client panel
In HestiaCP, go to Configuración -> Firewall -> Add rule and create a rule like the following:
Once you have opened the port, you can test the project by starting the Django development server with the command:
# ./manage.py runserver 0.0.0.0:8000To check it, use any browser to access your domain or your server's IP, followed by port 8000: http://IP.DE.TU.SERVIDOR:8000.
You should see the default Django page:
If you add /admin to the end of the URL in the address bar, you can log in with the administrative username and password you created with the “createsuperuser” command
After authenticating, you can access Django's default administration interface:
When you have finished exploring the interface, press “CTRL+C” in your server's console window to stop the development server.
Check whether Gunicorn can serve the project
The last thing to do before leaving the virtual environment is to test Gunicorn to make sure it can serve the application. You can easily do this by typing:
# cd miproyecto
# gunicorn --bind 0.0.0.0:8000 miproyecto.wsgi:applicationThis will start Gunicorn on the same interface where the Django development server runs. You can go back and test the application again. Keep in mind that the administration interface will have no styling, because Gunicorn does not handle the static content responsible for it.
You passed a module to Gunicorn by specifying the relative path to Django's wsgi.py file, which is the entry point to our application, using Python module syntax. A function named “application” is defined inside this file and is used to communicate with the application.
When you have finished testing, press “CTRL-C” in your server's console window to stop Gunicorn.
You have now finished configuring the Django application. You can exit the virtual environment by typing: “deactivate”
Create a systemd service file for Gunicorn
You have verified that Gunicorn can interact with the Django application, but you need to implement a more robust way to start and stop the application server. To do this, create a systemd service file.
Create and open a systemd service file for Gunicorn with sudo privileges using a text editor:
# vi /etc/systemd/system/gunicorn.serviceStart with the [Unit] section, which specifies metadata and dependencies. Add a description of your service here and tell the init system to start it only after the network target has been reached:
[Unit]
Description=gunicorn daemon
After=network.targetNext, open the [Service] section. In it, specify the user and group under which you want the process to run. Specify your regular login user, since it owns all the relevant files. For the group, specify “www-data” so that Nginx can communicate easily with Gunicorn.
Next, set the working directory and specify the command you will use to start the service. In this case, you need to specify the full path to the Gunicorn executable, which is installed inside the virtual environment. Bind it to the Unix socket inside the project directory, since Nginx is installed on the same server. This is more secure and faster than using a network port. You can also specify any optional Gunicorn settings here. For example, below we have specified 3 worker processes:
[Unit]
Description=gunicorn daemon
After=network.target
[Service]
User=root
Group=www-data
WorkingDirectory=/home/admin/web/c5ce05be-dedd-4994-9169-14ba6ed0218e.clouding.host/public_html/miproyecto/miproyecto
ExecStart=/home/admin/web/c5ce05be-dedd-4994-9169-14ba6ed0218e.clouding.host/public_html/miproyecto/miproyectoentorno/bin/gunicorn --workers 3 --bind unix:/home/admin/web/c5ce05be-dedd-4994-9169-14ba6ed0218e.clouding.host/public_html/miproyecto/miproyecto.sock miproyecto.wsgi:applicationFinally, add the [Install] section. This tells the system what to link the service to if you enable it to start at boot. This service should start when the regular multi-user system is up and running:
[Unit]
Description=gunicorn daemon
After=network.target
[Service]
User=root
Group=www-data
WorkingDirectory=/home/admin/web/c5ce05be-dedd-4994-9169-14ba6ed0218e.clouding.host/public_html/miproyecto/miproyecto
ExecStart=/home/admin/web/c5ce05be-dedd-4994-9169-14ba6ed0218e.clouding.host/public_html/miproyecto/miproyectoentorno/bin/gunicorn --workers 3 --bind unix:/home/admin/web/c5ce05be-dedd-4994-9169-14ba6ed0218e.clouding.host/public_html/miproyecto/miproyecto.sock miproyecto.wsgi:application
[Install]
WantedBy=multi-user.target
Your systemd service file is now complete. Save and close it. You can now start the Gunicorn service you created and enable it to start at boot:
# sudo systemctl start gunicorn
# sudo systemctl enable gunicornConfigure Nginx Proxy Pass for Gunicorn
Now that Gunicorn is configured, you need to configure Nginx to forward traffic to the process. Since we are working in HestiaCP, we do this by creating a template for Django. To do this, create the following files:
# touch /usr/local/hestia/data/templates/web/nginx/django.tpl
# touch /usr/local/hestia/data/templates/web/nginx/django.stpl
# chmod 755 /usr/local/hestia/data/templates/web/nginx/django.tpl
# chmod 755 /usr/local/hestia/data/templates/web/nginx/django.stpl
Add the following code to the file django.tpl:
#=======================================================================#
# Default Web Domain Template #
# DO NOT MODIFY THIS FILE! CHANGES WILL BE LOST WHEN REBUILDING DOMAINS #
#=======================================================================#
server {
listen %ip%:%proxy_port%;
server_name %domain_idn% %alias_idn%;
include %home%/%user%/conf/web/%domain%/nginx.forcessl.conf*;
location = /favicon.ico { access_log off; log_not_found off; }
location /static/ {
root %home%/%user%/web/%domain%/public_html/miproyecto/miproyecto;
}
location / {
proxy_set_header Host $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:%home%/%user%/web/%domain%/public_html/miproyecto/miproyecto.sock;
}
location ~ /\.ht {return 404;}
location ~ /\.svn/ {return 404;}
location ~ /\.git/ {return 404;}
location ~ /\.hg/ {return 404;}
location ~ /\.bzr/ {return 404;}
include %home%/%user%/conf/web/%domain%/nginx.conf_*;
}Add the following code to the file django.stpl:
#=======================================================================#
# Default Web Domain Template #
# DO NOT MODIFY THIS FILE! CHANGES WILL BE LOST WHEN REBUILDING DOMAINS #
#=======================================================================#
server {
listen %ip%:%proxy_ssl_port% ssl http2;
server_name %domain_idn% %alias_idn%;
ssl_certificate %ssl_pem%;
ssl_certificate_key %ssl_key%;
ssl_stapling on;
ssl_stapling_verify on;
error_log /var/log/%web_system%/domains/%domain%.error.log error;
include %home%/%user%/conf/web/%domain%/nginx.hsts.conf*;
location = /favicon.ico { access_log off; log_not_found off; }
location /static/ {
root %home%/%user%/web/%domain%/public_html/miproyecto/miproyecto;
}
location / {
proxy_set_header Host $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:%home%/%user%/web/%domain%/public_html/miproyecto/miproyecto.sock;
}
location ~ /\.ht {return 404;}
location ~ /\.svn/ {return 404;}
location ~ /\.git/ {return 404;}
location ~ /\.hg/ {return 404;}
location ~ /\.bzr/ {return 404;}
include %home%/%user%/conf/web/%domain%/nginx.ssl.conf_*;
}Use the templates you created in the HestiaCP panel
Access the HestiaCP panel at https://nombre_host:8083 with the username "admin" and the password shown in the client panel.
In the Hestia panel, go to "WEB" and then click the domain where you want to use the Django template.
In the "Soporte Proxy NGINX" section, click the drop-down that shows "default" by default and select "django".
Finally, open port 80 if it is not already open. Since access to the development server is no longer needed, you can delete the rule for port 8000 that you created earlier.
You should now be able to visit your domain and see your application.