How To Set Up Django with Postgres, Nginx, and Daphne (Django Channels) on Ubuntu 20.04

In this tutorial you will learn how to deploy your django (django channels) web app with daphne, postgresql and nginx on VPS


We will use these technologies together to deploy our async Django web app.


ssh root@your_server_ip

Once you are logged in as root, we’re prepared to add the new user account. In the future, we’ll log in with this new account instead of root.
This example creates a new user called sammy, but you should replace that with a username that you like:

adduser sammy

Now, we have a new user account with regular account privileges. However, we may sometimes need to do administrative tasks.
To avoid having to log out of our normal user and log back in as the root account, we can set up what is known as superuser or root privileges for our normal account. This will allow our normal user to run commands with administrative privileges by putting the word sudo before each command.
As root, run this command to add your new user to the sudo group (substitute the highlighted username with your new user):

usermod -aG sudo sammy

Initialize Ubuntu packages

We need to update the local apt package index and then download and install the packages. The packages we install depend on which version of Python your project will use.

sudo apt update
sudo apt install python3-pip python3-dev libpq-dev postgresql postgresql-contrib nginx curl

Creating the PostgreSQL Database

sudo -u postgres psql

First, create a database for your project:


Next, create a database user for our project. Make sure to select a secure password:

CREATE USER myprojectuser WITH PASSWORD ‘password’;

We are setting the default encoding to UTF-8, which Django expects. We are also setting the default transaction isolation scheme to “read committed”, which blocks reads from uncommitted transactions. Lastly, we are setting the timezone. By default, our Django projects will be set to use UTC

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, we can give our new user access to administer our new database:

GRANT ALL PRIVILEGES ON DATABASE myproject TO myprojectuser;

When you are finished, exit out of the PostgreSQL prompt by typing:


Initialize Django Project


‘default’: {

‘ENGINE’: ‘django.db.backends.postgresql_psycopg2’,

‘NAME’: ‘myproject’,

‘USER’: ‘myprojectuser’,

‘PASSWORD’: ‘password’,

‘HOST’: ‘localhost’,

‘PORT’: ‘’,



Checkout Deployment checklist in Django documentation:

Then commit your changes and push them to your Github repository.

Creating a Python Virtual Environment

sudo -H pip3 install — upgrade pip
sudo -H pip3 install virtualenv

With virtualenv installed, we can start forming our project. Create and move into a directory where we can keep our project files:

mkdir ~/myprojectdir
cd ~/myprojectdir

Within the project directory, create a Python virtual environment by typing:

virtualenv myprojectenv

Before we install our project’s Python requirements, we need to activate the virtual environment. You can do that by typing:

source myprojectenv/bin/activate

With your virtual environment active, install Daphne, and the psycopg2 PostgreSQL adaptor with the local instance of pip:

pip install daphne psycopg2-binary

Initialize Django Project

git clone <github_repo_url>
cd django_project_dir

Install dependencies from requirements.txt using pip

pip install -r requirements.txt

Then makemigrations then migrate and don’t forget to collectstatic because now we are in production, then create a superuser to access to the admin panel.

python makemigrations
python migrate
python collectstatic
python createsuperuser

In order to test the 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:

python runserver

In your web browser, visit your server’s domain name or IP address followed by :8000:


The last thing we want to do before leaving our virtual environment is test Daphne to make sure that it can serve the application. We can do this by entering our project directory and using daphne to load the project’s ASGI module:

daphne -p 8000 -b myproject.asgi:application

When you are finished testing, hit CTRL-C in the terminal window to stop Daphne.

We’re now finished configuring our Django application. We can back out of our virtual environment by typing:


Creating systemd Socket and Service Files for Daphne

sudo nano /etc/systemd/system/daphne.socket

file content is:

Description=daphne socket



Next, create and open a systemd service file for Daphne 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/daphne.service

file content is:

Description=daphne daemon

ExecStart=/home/sammy/myprojectdir/myprojectenv/bin/daphne -b -p 8000 source.asgi:application


We can now start and enable the daphne socket. This will create the socket file at /run/daphne.sock now and at boot. When a connection is made to that socket, systemd will automatically start the daphne.service to handle it:

sudo systemctl start daphne.socket
sudo systemctl enable daphne.socket

Check the status of the process to find out whether it was able to start:

sudo systemctl status daphne.socket

Next, check for the existence of the daphne.sock file within the /run directory:

file /run/daphne.sock

If the systemctl status command indicated that an error occurred or if you do not find the daphne.sock file in the directory, it’s an indication that the Daphne socket was not able to be created correctly. Check the Daphne socket’s logs by typing:

sudo journalctl -u daphne.socket

Take another look at your /etc/systemd/system/daphne.socket file to fix any problems before continuing.

Currently, if you’ve only started the daphne.socket unit, the daphne.service will not be active yet since the socket has not yet received any connections. You can check this by typing:

sudo systemctl status daphne

To test the socket activation mechanism, we can send a connection to the socket through curl by typing:

curl — unix-socket /run/daphne.sock localhost

You should receive the HTML output from your application in the terminal. This indicates that Daphne was started and was able to serve your Django application. You can verify that the Daphne service is running by typing:

sudo systemctl status daphne

If the output from curl or the output of systemctl status indicates that a problem occurred, check the logs for additional details:

sudo journalctl -u daphne

Check your /etc/systemd/system/daphne.service file for problems. If you make changes to the /etc/systemd/system/daphne.service file, reload the daemon to reread the service definition and restart the Daphne process by typing:

sudo systemctl daemon-reload
sudo systemctl restart daphne

Make sure you troubleshoot the above issues before continuing.

Configure Nginx to Proxy Pass to Daphne

Start by creating and opening a new server block in Nginx’s sites-available directory:

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

file content is:

upstream channels-backend {

server localhost:8000;


server {

listen 80;

server_name server_domain_or_IP;

location = /favicon.ico { access_log off; log_not_found off; }

location /static/ {

root /home/sammy/myprojectdir/django_project_dir;


location /media/ {

root /home/sammy/myprojectdir/django_project_dir;


location / {

proxy_pass http://channels-backend;

proxy_http_version 1.1;

proxy_set_header Upgrade $http_upgrade;

proxy_set_header Connection “Upgrade”;

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

proxy_set_header Host $http_host;

proxy_redirect off;



We can enable the file by linking it to the sites-enabled directory:

sudo ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled

Test your Nginx configuration for syntax errors by typing:

sudo nginx -t

If no errors are reported, go ahead and restart Nginx by typing:

sudo systemctl restart nginx

Finally, we need to open up our firewall to normal traffic on port 80. Since we no longer need access to the development server, we can remove the rule to open port 8000 as well:

sudo ufw delete allow 8000
sudo ufw allow ‘Nginx Full’


If you make any edits in nginx configuration file, use this command:

sudo systemctl restart nginx

If you make any edits in your django project, use these command:

sudo systemctl daemon-reload
sudo systemctl restart daphne

This article is extended from this article: