How to Install Django, Nginx, and Gunicorn on a Virtual Server
Django is a web framework for developing mobile applications and websites using Python. It includes a built-in server for local testing and simple solutions, but you'll typically need a more robust setup for production. This guide will walk you through installing Django on Ubuntu and configuring it for production.
Prerequisites Copy link
- A VPS running Ubuntu
- Basic firewall settings
- A user with
sudoprivileges
Install Packages from the Ubuntu Repository Copy link
First, let's update the apt packages to ensure we use the latest releases. Then, install Python 3 and other necessary packages:
sudo apt update
sudo apt install python3-pip python3-dev libpq-dev postgresql postgresql-contrib nginx curlThis command will install pip (Python's package manager), Python-related files, Gunicorn (a Python WSGI HTTP server), PostgreSQL (a relational database system), and Nginx (a web server).
Create a Database and User in PostgreSQL Copy link
PostgreSQL uses "peer authentication" by default, allowing users to connect without entering a password if the OS user matches the database user. You can switch to the postgres system user using the following command:
sudo -u postgres psqlIn the PostgreSQL interface, create a new database for your project:
CREATE DATABASE myproject;Then, create a user with a secure password:
CREATE USER myprojectuser WITH PASSWORD 'password';To optimize settings, configure the user with UTF-8 encoding, "read committed" transaction isolation, and the UTC timezone:
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';Now, grant all privileges on the database to this user:
GRANT ALL PRIVILEGES ON DATABASE myproject TO myprojectuser;Exit the PostgreSQL prompt:
\qYour PostgreSQL database setup is now complete.
Set Up a Python Virtual Environment Copy link
You'll need to install virtualenv to create an isolated environment for your project:
sudo -H pip3 install --upgrade pip
sudo -H pip3 install virtualenvCreate a new directory for your project and navigate to it:
mkdir ~/myprojectdir
cd ~/myprojectdirNow, create a virtual Python environment:
virtualenv myprojectenvActivate the virtual environment:
source myprojectenv/bin/activateYou’ll see the prompt change, indicating that you're now working inside the virtual environment:
(myprojectenv)user@host:~/myprojectdir$Install Django, Gunicorn, and the PostgreSQL adapter psycopg2:
pip install django gunicorn psycopg2-binaryCreate and Configure Your Django Project Copy link
Now, create a new Django project inside the directory:
django-admin startproject myproject ~/myprojectdirModify Django settings. Open the settings file to configure it:
nano ~/myprojectdir/myproject/settings.pyAt the top of the file, add the following:
import osNext, find the ALLOWED_HOSTS directive. This determines which addresses can connect to your Django instance. Add the necessary IP addresses or domains within square brackets:
ALLOWED_HOSTS = ['your_server_domain_or_IP', 'second_domain_or_IP', 'localhost']Then, scroll to the DATABASES section. Replace the default configuration with the PostgreSQL settings:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'myproject',
'USER': 'myprojectuser',
'PASSWORD': 'password',
'HOST': 'localhost',
'PORT': '',
}
}At the end of the file, define where Django should store static files. This will be needed when setting up Nginx:
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static/')Save and exit the file.
Now, apply database migrations and create a superuser to manage the project:
~/myprojectdir/manage.py makemigrations
~/myprojectdir/manage.py migrate
~/myprojectdir/manage.py createsuperuserSet a username, password, and email. After this, if you plan to collect all static content in one place, run the following command:
~/myprojectdir/manage.py collectstaticThis will require confirmation before moving files to the static folder. Allow access to port 8000 through the firewall using UFW:
sudo ufw allow 8000Start the Django development server:
~/myprojectdir/manage.py runserver 0.0.0.0:8000Visit http://server_domain_or_IP:8000 in your browser to verify that everything is working. If the Django index page appears, your setup is successful! You can also access the admin panel at http://server_domain_or_IP:8000/admin using the superuser credentials you created.
To stop the development server, press <Ctrl+C> in the terminal.
Creating Socket and systemd Files for Gunicorn Copy link
Gunicorn creates a socket at startup via systemd, which listens for incoming connections. First, create a new file:
sudo nano /etc/systemd/system/gunicorn.socketIn this file, create a new [Unit] section to describe the socket, a [Socket] section to define where the socket is located, and an [Install] section for enabling the socket at startup:
[Unit]
Description=gunicorn socket
[Socket]
ListenStream=/run/gunicorn.sock
[Install]
WantedBy=sockets.targetSave and close the file. Next, create the systemd service file:
sudo nano /etc/systemd/system/gunicorn.serviceStart with the [Unit] section to define metadata and dependencies, specifying that the service should start after the network is up:
[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.targetIn the [Service] section, define the user, group, working directory, and command to start Gunicorn. Replace user with your username. In this example, we use 3 worker processes:
[Service]
User=user
Group=www-data
WorkingDirectory=/home/user/myprojectdir
ExecStart=/home/user/myprojectdir/myprojectenv/bin/gunicorn \
--access-logfile - \
--workers 3 \
--bind unix:/run/gunicorn.sock \
myproject.wsgi:applicationFinally, in the [Install] section, define where the services should be linked upon activation:
[Install]
WantedBy=multi-user.targetClose the file and save the changes.
Now, start the Gunicorn socket and enable it to run at boot:
sudo systemctl start gunicorn.socket
sudo systemctl enable gunicorn.socketChecking the Gunicorn Socket Copy link
To verify that the Gunicorn socket is running, check its status:
sudo systemctl status gunicorn.socketMake sure the gunicorn.sock file exists in the /run directory:
file /run/gunicorn.sockThe output should confirm that the socket exists:
/run/gunicorn.sock: socketIf the socket fails to start, use the following command to diagnose the issue:
sudo journalctl -u gunicorn.socketCheck for any errors in the file, and correct them if necessary.
Diagnosing Socket Activation Copy link
It's important to note that when gunicorn.socket is running, gunicorn.service will be inactive. You can confirm this with:
sudo systemctl status gunicornThe output should show the service is inactive.
Now, test the socket connection with curl:
curl --unix-socket /run/gunicorn.sock localhostIf you see HTML data, Gunicorn has successfully started. Recheck the status of the service:
sudo systemctl status gunicornThe status should be Running. If you encounter errors, check the Gunicorn log for details:
sudo journalctl -u gunicornReload and restart the systemd daemon if needed:
sudo systemctl daemon-reload
sudo systemctl restart gunicornConfiguring Nginx as a Reverse Proxy for Gunicorn Copy link
Now, set up Nginx as a reverse proxy. Create a new Nginx configuration file:
sudo nano /etc/nginx/sites-available/myprojectIn this file, configure Nginx to listen on port 80 and respond to your domain or server IP address:
server {
listen 80;
server_name server_domain_or_IP;
}Next, define the location of static files and instruct Nginx to ignore issues related to favicon.ico:
server {
listen 80;
server_name server_domain_or_IP;
location = /favicon.ico { access_log off; log_not_found off; }
location /static/ {
root /home/user/myprojectdir;
}
}Finally, create a block that passes all other requests to the Gunicorn socket:
server {
listen 80;
server_name server_domain_or_IP;
location = /favicon.ico { access_log off; log_not_found off; }
location /static/ {
root /home/user/myprojectdir;
}
location / {
include proxy_params;
proxy_pass http://unix:/run/gunicorn.sock;
}
}Save and close the file. Link this configuration to the sites-enabled directory:
sudo ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabledAdd the www-data user to your group:
sudo usermod -a -G ${USER} www-dataCheck for syntax errors in the Nginx configuration:
sudo nginx -tIf no errors are found, restart Nginx:
sudo systemctl restart nginxNow, delete the rule allowing access through port 8000, and open port 80 for Nginx:
sudo ufw delete allow 8000
sudo ufw allow 'Nginx Full'Finally, visit your server's domain or IP address to confirm everything works.
Before going live, make sure to secure your site with SSL/TLS using a certificate from Let’s Encrypt.
Conclusion Copy link
This guide has walked you through installing and configuring Django with PostgreSQL, Gunicorn, and Nginx on Ubuntu. Once configured, you can start building your Django application in this environment.