step-by-step guide to installing a Django project using supervisor and Pyenv on a Ubuntu server

How to Deploy a Django Project with Gunicorn, Pyenv, and Nginx or Apache

how to deploy django app using gunicorn, supervisor on ubuntu server


This guide walks you through installing and deploying a Django application using Gunicorn, Pyenv, and Nginx or Apache on a Linux server.

Target OS: Ubuntu 22.04 LTS or other modern Debian-based distributions.

1. Create a Non-Root User


sudo adduser webapp
sudo usermod -aG sudo webapp

2. Install System Dependencies (as root)


sudo apt update
sudo apt install -y make build-essential libssl-dev zlib1g-dev \
libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm \
libncurses5-dev libncursesw5-dev xz-utils tk-dev libffi-dev liblzma-dev \
python-openssl git

3. Switch to webapp User and Install Pyenv


su - webapp

Install Pyenv


curl https://pyenv.run | bash

Add this to ~/.bashrc:


echo -e '\n# Pyenv Setup\nexport PATH="$HOME/.pyenv/bin:$PATH"\n\
eval "$(pyenv init --path)"\neval "$(pyenv init -)"' >> ~/.bashrc
source ~/.bashrc

Install Python (e.g., 3.10.5)


pyenv install -v 3.10.5
pyenv virtualenv 3.10.5 virtual
pyenv activate virtual
python --version
Now, we have installed python 3.10.5 using pyenv and we can use 'pyenv activate virtual' to activate the virtual environment,

4. Set Up Your Django Project

Create Project Directory and Virtual Environment

As we installed python, you can clone your git repo to this webapp user location.

Install Django and Gunicorn

Normally, there will be requirements.txt file and we can install those with
pip install -r requirements.txt
Make sure to install GuniCorn if it's not already mentioned on requirements file. You can manually install as below
pip install gunicorn

Start Your Django Project

Once the requirements are installed, you can check if there is any issues by running check command.

python manage.py check
Kindly ensure that you have activated virtual environment and running it from location same as manage.py. To test the application locally, you can run below command however it will be exited once you stoped the command.

python manage.py runserver

5. Configure Gunicorn and supervisor

Inorder to better serve the application, we can use the Gunicorn. Please add below gunicorn.conf file under webapp user.

chdir = "/home/webapp/ottu/ottu"
daemon = False
errorlog = "/home/webapp/logs/gunicorn.error_log"
keepalive = 20
loglevel = "debug"
proc_name = "gunic_yourwebsite_webapp"
pidfile = "/home/webapp/run/gunic.pid"
reload = True
reload_extra_files = "/home/webapp/yourwebsite/yourwebsite/config/wsgi.py"
timeout = 300
user = "webapp"
workers = 3
Now, we need to use supervisor. Please install it as follow

sudo apt install -y supervisor
Once done, start the supervisord as below

sudo systemctl enable supervisor
sudo systemctl start supervisor
sudo systemctl status supervisor
Now, we can add below configuration on /etc/supervisord.d/ location with below config file

[program:webapp]
command=/home/webapp/.pyenv/versions/virtual/bin/gunicorn -c /home/webapp/gunicorn.conf config.wsgi:application
directory=/home/webapp/ottu/ottu
autostart=true
autorestart=true
startretries=3
startsecs=5
numprocs=1
user=webapp
stdout_logfile=/home/webapp/logs/webapp.out.log
stderr_logfile=/home/webapp/logs/webapp.err.log
We can run below commands to update and start the supervisor

supervisorctl reread
supervisorctl update
supervisorctl status

6. Set Up Reverse Proxy

Using Nginx (preferred)


sudo apt install nginx
sudo nano /etc/nginx/sites-available/myproject

server {
    listen 80;
    server_name yourwebsite.com www.yourwebsite.com;

    # Redirect www to non-www and force HTTPS
    if ($host ~* ^www\.(.*)) {
        return 301 https://$1$request_uri;
    }

    return 301 https://yourwebsite.com$request_uri;
}

server {
    listen 443 ssl;
    server_name yourwebsite.com www.yourwebsite.com;

    # SSL Certificates
    ssl_certificate     /etc/pki/tls/certs/yourwebsite_localhost.crt;
    ssl_certificate_key /etc/pki/tls/private/yourwebsite_localhost.key;
    ssl_trusted_certificate /etc/pki/tls/certs/yourwebsite_ca.cabundle;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5:!SEED:!IDEA;

    # HSTS
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

    # Redirect www to non-www
    if ($host ~* ^www\.(.*)) {
        return 301 https://$1$request_uri;
    }

    # Static files
    location /static/ {
        alias /home/webapp/yourwebsite/yourwebsite/staticfiles/;
    }

    location /media/ {
        alias /home/webapp/yourwebsite/yourwebsite/yourwebsite/media/;
    }

    # Well-known path (e.g., for Let's Encrypt)
    location ^~ /.well-known/ {
        alias /home/webapp/public_html/.well-known/;
    }

    # Proxy to app server
    location / {
        proxy_pass http://127.0.0.1:8589;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header X-Real-IP $remote_addr;

        proxy_connect_timeout 300;
        proxy_send_timeout 300;
        proxy_read_timeout 300;
        send_timeout 300;
    }

    # Security headers
    server_tokens off;
}

sudo ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled
sudo nginx -t
sudo systemctl restart nginx

OR Using Apache


sudo apt install apache2 libapache2-mod-wsgi-py3
sudo nano /etc/apache2/sites-available/myproject.conf


ServerName yourwebsite.com
ServerAlias www.yourwebsite.com

# Redirect www to non-www
RewriteEngine on
RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
RewriteRule ^ https://%1%{REQUEST_URI} [L,NE,R=301]

ProxyPassMatch ^/.well-known !
Alias /.well-known /home/webapp/public_html/.well-known

#RewriteEngine on
RewriteCond %{SERVER_NAME} =yourwebsite.com
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]



ServerName yourwebsite.com
ServerAlias www.yourwebsite.com


# Redirect www to non-www
RewriteEngine on
RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
RewriteRule ^ https://%1%{REQUEST_URI} [L,NE,R=301]
#RewriteRule ^ https://yourwebsite.com%{REQUEST_URI} [L,R=301]


    Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
#    Header edit Set-Cookie ^(.*)$ $1;HttpOnly;Secure



ProxyPass /static/ !
Alias /static/ /home/webapp/yourwebsite/yourwebsite/staticfiles/

        Require all granted


ProxyPass /media/ !
Alias /media/ /home/webapp/yourwebsite/yourwebsite/yourwebsite/media/

        Require all granted

ProxyPassMatch ^/.well-known !
Alias /.well-known /home/webapp/public_html/.well-known

        Require all granted


ProxyPreserveHost On
RequestHeader set X-Forwarded-Proto "https"
RequestHeader set "Host" "yourwebsite.com"
ProxyPass / http://127.0.0.1:8589/ connectiontimeout=300 timeout=300 Keepalive=On
ProxyPassReverse / http://127.0.0.1:8589/


  Require all granted
  AllowOverride all



SSLEngine on
SSLProtocol all -SSLv2 -SSLv3
SSLCipherSuite HIGH:MEDIUM:!aNULL:!MD5:!SEED:!IDEA
SSLCertificateFile /etc/pki/tls/certs/yourwebsite_localhost.crt
SSLCertificateKeyFile /etc/pki/tls/private/yourwebsite_localhost.key
SSLCertificateChainFile /etc/pki/tls/certs/yourwebsite_ca.cabundle
  

ServerSignature Off
ServerTokens Prod

sudo a2ensite myproject
sudo systemctl restart apache2

7. Final Test

Open your domain in a browser. You should see your Django website live.

Conclusion

You’ve successfully deployed a Django project using Pyenv (user-local for webapp), Gunicorn, supervisor and either Nginx or Apache on Ubuntu 22.04.

Comments