In this blog, I am going to show you how to simply setup Django application on Cloudpanel 2 with Gunicorn and nginx
This tutorial is aimed at the Django user who wants to set up a production web server. It takes you through the steps required to set up Django so that it works nicely with Gunicorn and nginx. It covers all three components, providing a complete stack of web application and server software.
CloudPanel is a free software to configure and manage a server with an obsessive focus on simplicity.
Run static websites, PHP, Node.js and, Python applications.
Django is a high-level Python Web framework that encourages rapid development and clean, pragmatic design.
nginx (pronounced engine-x) is a free, open-source, high-performance HTTP server and reverse proxy, as well as an IMAP/POP3 proxy server.
Gunicorn, short for Green Unicorn, is a popular WSGI (Web Server Gateway Interface) HTTP server for running Python web applications. It’s a lightweight and production-ready server that can serve web applications built on frameworks like Flask, Django, and others.
gunicorn -w 4 -b 0.0.0.0:8000 your_django_app:app
Using Gunicorn is a common practice when deploying Python web applications, and it’s often part of the deployment stack alongside other tools like Nginx or Apache.
- First go to your Cloudpanel Hosting, then go to Add site
2. Create a Python site
3. Add and note details given below:
1) Domain name – www.tutorialslides.com
2) App port – 8090
3) Site User – tutorialslides
Now click on Create
4. Now install SSL Let’s Encrypt Certificate
5. Log in via SSH with the Root User and go to the directory: Use Filezilla or Else use Cloudpanel Filemanager to upload all your Django files except env or Venv folder
Now go to domain settings and copy directory path
Now login to SSH and let’s install Django and create venv
cd /home/tutorialslides/htdocs/www.tutorialslides.com
The below code will create a virtual environment called ENV
python -m venv env
# or
python3 -m venv env
Now activate ENV using below code
source env/bin/activate
If you see your terminal like this. then your ENV is running properly
(env)
Now install requirements.txt file
pip install -r requirements.txt
pip install django gunicorn psycopg2-binary
Now migrate your Django database for the first time.
python3 manage.py makemigrations
python3 manage.py migrate
If you followed the initial server setup guide, you should have a UFW firewall protecting your server. In order to test the development server, we’ll have to allow access to the port we’ll be using.
Create an exception for port 8000 by typing:
sudo ufw allow 8000
Finally, you can test our your project by starting up the Django development server with this command:
python3 manage.py runserver 0.0.0.0:8000
In your web browser, visit your server’s domain name or IP address followed by :8000
:
http://server_domain_or_IP:8000
settings.py
:
ALLOWED_HOSTS = ['localhost', '127.0.0.1', 'yourip:8090', 'www.tutorialslides.com', 'tutorialslides.com']
STATIC_URL = 'static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static/')
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
MEDIA_URL = 'media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
You should receive the default Django index page or your project page.
We have tested that Gunicorn can interact with our Django application, but we should implement a more robust way of starting and stopping the application server. To accomplish this, we’ll make systemd service and socket files.
The Gunicorn socket will be created at boot and will listen for connections. When a connection occurs, systemd will automatically start the Gunicorn process to handle the connection.
Start by creating and opening a systemd socket file for Gunicorn with sudo
privileges:
sudo nano /etc/systemd/system/gunicorn.socket
Inside, we will create a [Unit]
section to describe the socket, a [Socket]
section to define the socket location, and an [Install]
section to make sure the socket is created at the right time: and paste below code.
[Unit]
Description=gunicorn socket
[Socket]
ListenStream=/run/gunicorn.sock
[Install]
WantedBy=sockets.target
Save and close the file when you are finished.
Next, create and open a systemd service file for Gunicorn with sudo
privileges in your text editor. The service filename should match the socket filename with the exception of the extension:
sudo nano /etc/systemd/system/gunicorn.service
Save and close the file when you are finished.
Next, create and open a systemd service file for Gunicorn with sudo
privileges in your text editor. The service filename should match the socket filename with the exception of the extension:
Note: Replace user= tutorialslides with your site user id and replace tutorialslides.com with your domain
[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.target
[Service]
User=tutorialslides
Group=www-data
WorkingDirectory=/home/tutorialslides/htdocs/www.tutorialslides.org
ExecStart=/home/tutorialslides/htdocs/www.tutorialslides.org/env/bin/gunicorn --access-logfile - --timeout 300 --workers 3 --bind unix:/run/gunicorn.sock dashboard.wsgi:application
[Install]
WantedBy=multi-user.target
With that, our systemd service file is complete. Save and close it now.
We can now start and enable the Gunicorn socket. This will create the socket file at /run/gunicorn.sock
now and at boot. When a connection is made to that socket, systemd will automatically start the gunicorn.service
to handle it:
sudo systemctl start gunicorn.socket
sudo systemctl enable gunicorn.socket
Check the status of the process to find out whether it was able to start:
sudo systemctl status gunicorn.socket
You should receive an output like this:
Output
● gunicorn.socket - gunicorn socket
Loaded: loaded (/etc/systemd/system/gunicorn.socket; enabled; vendor prese>
Active: active (listening) since Fri 2020-06-26 17:53:10 UTC; 14s ago
Triggers: ● gunicorn.service
Listen: /run/gunicorn.sock (Stream)
Tasks: 0 (limit: 1137)
Memory: 0B
CGroup: /system.slice/gunicorn.socket
Go to your cloudpanel sites settings page > vhost
Replace with below code on vhost
server {
listen 80;
listen [::]:80;
listen 443 ssl http2;
listen [::]:443 ssl http2;
{{ssl_certificate_key}}
{{ssl_certificate}}
server_name www.tutorialslides.org;
{{root}}
{{nginx_access_log}}
{{nginx_error_log}}
if ($scheme != "https") {
rewrite ^ https://$host$uri permanent;
}
location ~ /.well-known {
auth_basic off;
allow all;
}
location = /favicon.ico { access_log off; log_not_found off; }
location /static/ {
root /home/tutorialslides/htdocs/www.tutorialslides.org;
}
location /media/ {
autoindex on;
autoindex_exact_size off;
root /home/tutorialslides/htdocs/www.tutorialslides.org;
}
{{settings}}
index index.html;
location / {
include proxy_params;
proxy_pass http://unix:/run/gunicorn.sock;
}
#location ~* ^.+\.(css|js|jpg|jpeg|gif|png|ico|gz|svg|svgz|ttf|otf|woff|woff2|eot|mp4|ogg|ogv|webm|webp|zip|swf)$ {
# add_header Access-Control-Allow-Origin "*";
# expires max;
# access_log on;
#}
if (-f $request_filename) {
break;
}
}
If no errors are reported, go ahead and restart Nginx by typing:
sudo systemctl restart nginx
sudo ufw delete allow 8000
sudo ufw allow 'Nginx Full'
sudo systemctl status nginx
#If problem exist
sudo systemctl start nginx
sudo systemctl status nginx
sudo nginx -t && sudo systemctl restart nginx
sudo systemctl daemon-reload
sudo systemctl restart gunicorn.socket gunicorn.service
Done. Now you can refresh your domain your site will be up and running.
Error handling
502 Bad Gateway caused by GUNICORN
sudo nano /etc/systemd/system/gunicorn.service
[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.target
[Service]
User=tutorialslides
Group=www-data
WorkingDirectory=/home/tutorialslides/htdocs/www.tutorialslides.org
ExecStart=/home/tutorialslides/htdocs/www.tutorialslides.org/env/bin/gunicorn --access-logfile - --timeout 300 --workers 3 --bind unix:/run/gunicorn.sock dashboard.wsgi:application
[Install]
WantedBy=multi-user.target
sudo systemctl start gunicorn
sudo systemctl enable gunicorn
sudo systemctl daemon-reload
sudo systemctl restart gunicorn
504 Bad Gateway caused by NGINX
sudo nano /etc/nginx/nginx.conf
Add those to http
client_body_timeout 999;
client_header_timeout 999;
keepalive_timeout 999;
fastcgi_buffers 8 16k;
fastcgi_buffer_size 32k;
fastcgi_connect_timeout 999;
fastcgi_send_timeout 999;
fastcgi_read_timeout 999;
Change this in events
worker_connections 1024;
service nginx reload
#or
sudo systemctl restart nginx
sudo systemctl status nginx
sudo systemctl start nginx
sudo systemctl status nginx