Introduction to the

Django is a powerful web framework to help get your Python application or website off the ground. Django includes a simplified development server for testing your code locally, but for anything production-related, you need a more secure and powerful Web server.

The traditional way to deploy Django applications is to use the Web Server Gateway Interface (WSGI). However, with the advent of Python 3 and support for asynchronous execution, you can now execute your Python applications through asynchronous callables for the Asynchronous Server Gateway Interface (ASGI). As a successor to WSGI, the ASGI specification in Python is a superset of WSGI and can be used as a replacement for WSGI.

Django allows an “external asynchronous, internal synchronous” mode, allowing your code to be synchronized internally while the ASGI server processes requests asynchronously. By allowing webServer to have an asynchronous callability, it can handle multiple incoming and outgoing events for each application. Django applications are still synchronized internally to allow backward compatibility and avoid the complexities of parallel computation. This also means that your Django application can switch from WSGI to ASGI without changing.

In this tutorial, you’ll install and configure components on Ubuntu 20.04 to support and service Django applications. Instead of using the default SQLite database, you will be setting up a PostgreSQL database. You will configure the Gunicorn application Server with Uvicorn, an ASGI implementation, to connect to your application asynchronously. You will then set up Nginx as a reverse proxy for Gunicorn, enabling you to use its security and performance features to service your application.

The premise condition

To complete this tutorial, you will need.

  • A in accordance with theUbuntu 20.04 Initial Server Setup GuideSetup for Ubuntu 20.04 server, including one withsudoNon-root user with permission.

Step 1 – Install packages from the Ubuntu repository

To start the process, you’ll download and install all the projects you need from the Ubuntu library. Later you will use the Python package manager PIP to install the other components.

First, you need to update your local APT package index, then download and install the package. The package you install depends on which version of Python your project will use.

Use the following commands to install the necessary system packages.

sudo apt update
sudo apt install python3-venv libpq-dev postgresql postgresql-contrib nginx curl
Copy the code

This command will install the Python library to set up the virtual environment, the Postgres database system and the libraries needed to interact with it, and the Nginx web server. Next, you’ll create a PostgreSQL database and users for your Django application.

Step 2 – Create the PostgreSQL database and users

In this step, you will create a database and a database user for your Django application.

By default, Postgres uses an authentication scheme called peer authentication for local connections. This means that if a user’s operating system username matches a valid Postgres username, the user can log in without further authentication.

During the installation of Postgres, an operating system user named Postgres is created corresponding to the Postgres PostgreSQL administrator user. You will need this user to perform administrative tasks. You can use sudo and enter the username with the -u option.

Log in to an interactive Postgres session by typing.

sudo -u postgres psql
Copy the code

You’ll get a PostgreSQL prompt where you can set requirements.

First, create a database for your project.

CREATE DATABASE myproject;
Copy the code

** Note: ** Each Postgres statement must end with a semicolon. If you run into problems, make sure your commands end with a semicolon.

Next, create a database user for the project. Make sure you choose a secure password.

CREATE USER myprojectuser WITH PASSWORD 'password';
Copy the code

After that, you need to modify some connection parameters for the user you just created. This speeds up the operation of the database so that you don’t have to query and set the correct values every time a connection is established.

You’ll set the default encoding to UTF-8, which is what Django expects. You will also set the default transaction isolation scheme to “Read Committed”, which prevents reading data from uncommitted transactions. Finally, you need to set the time zone. By default, Django projects are set to use UTC. These are suggestions for the Django project itself.

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';
Copy the code

Now, you can give your new user permission to manage the new database.

GRANT ALL PRIVILEGES ON DATABASE myproject TO myprojectuser;
Copy the code

When you’re done, exit the PostgreSQL prompt by typing.

\q
Copy the code

Now that Postgres is set up, Django can connect and manage its database information.

Step 3 – Create a Python virtual environment for your project

Now that you have a database, you can start preparing other requirements for your project. You will install your Python requirements in a virtual environment for easy administration.

First, create and move to a directory where you can save the project files.

mkdir ~/myprojectdir
cd ~/myprojectdir
Copy the code

Then use Python’s built-in virtual environment tools to create a new virtual environment.

python3 -m venv myprojectenv
Copy the code

This will create a name called MyProjectenv in your myProjectdir directory. Inside, it will install a native version of Python and a native version of PIP. You can use it to install and configure an isolated Python environment for your project.

You need to activate the virtual environment before installing the Python requirements for your project. You can do this by typing the following.

source myprojectenv/bin/activate
Copy the code

Your prompt should be changed to indicate that you are now operating in a Python virtual environment. It’s going to look something like this. (myprojectenv)user@host:~/myprojectdir$.

Youll install Django in a virtual environment. Installing Django in an environment specific to your project will allow your projects and their requirements to be handled separately. After your virtual environment is active, install Django, Gunicorn, Uvicorn, and Psycopg2 PostgreSQL adapters using a local instance of PIP.

** Note :** When the virtual environment is active (when preceded by your prompt (myProjectenv)), use PIP instead of PIp3, even if you are using Python 3. A copy of the tool in a virtual environment is always named PIP, regardless of the Python version.

pip install django gunicorn uvicorn psycopg2-binary
Copy the code

You should now have all the software you need to start your Django project.

Step 4 – Create and configure a new Django project

After installing Python components, you can create actual Django project files.

Creating a Django project

Since you already have a project directory, you can tell Django to install the files there. It creates a secondary directory containing the actual code, as is normal, and places an administrative script in this directory. The key here is that you define the directory explicitly, rather than letting Django make decisions relative to your current directory.

django-admin startproject myproject ~/myprojectdir
Copy the code

At this point, your project directory (~/myprojectdir in this tutorial) should have the following.

  • ~/myprojectdir/manage.py: a Django project management script.
  • ~/myprojectdir/myproject/: Django project package. This should include__init__.py.asgi.py, settings.py ,urls.py, andwsgi.pyFile.
  • ~/myprojectdir/myprojectenv/: virtual environment directory you created earlier.

Adjust project Settings

After creating the project file, you need to adjust some Settings. Open the Settings file in your text editor.

nano ~/myprojectdir/myproject/settings.py
Copy the code

First find the ALLOWED_HOSTS directive. This defines a list of server addresses or domain names that can be used to connect to Django instances. Any incoming request with a Host header that is not in this list throws an exception. Django requires you to do this to prevent certain types of security vulnerabilities.

In square brackets, list the IP addresses or domain names associated with your Django server. List each item in quotation marks, separated by commas. To allow the entire domain and any subdomains, put a period at the beginning of the entry. In the following snippet, there are several annotated examples to show how to do this.

** Note: ** Be sure to include localhost as one of the options, as you will be brokering the connection through a local Nginx instance.

~/myprojectdir/myproject/settings.py

.# The simplest case: just add the domain name(s) and IP addresses of your Django server
# ALLOWED_HOSTS = ['example.com', '203.0.113.5']
# To respond to 'example.com' and any subdomains, start the domain with a dot
# ALLOWED_HOSTS = ['.example.com', '203.0.113.5']
ALLOWED_HOSTS = ['your_server_domain_or_IP'.'second_domain_or_IP'.'localhost']
Copy the code

Next, find the section that configures database access. It will start with DATABASES. The configuration in this file is for SQLite databases. You have already created a PostgreSQL database for your project, so you will need to adjust these Settings.

Use your PostgreSQL database to change Settings. You’ll tell Django to use the Psycopg2 adapter you installed with PIP. You need to give the database name, the database user name, the password of the database user, and then specify that the database is on the local computer. You can set PORT to an empty string.

~/myprojectdir/myproject/settings.py

. . .

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2'.'NAME': 'myproject'.'USER': 'myprojectuser'.'PASSWORD': 'password'.'HOST': 'localhost'.'PORT': ' ',}}..Copy the code

Next, move to the bottom of the file and add a setting that indicates where the static file should be placed. This is necessary so that Nginx can handle requests to these items. The next line tells Django to place them in a directory called static in the base project directory.

~/myprojectdir/myproject/settings.py

. . .

STATIC_URL = '/static/'
import os
STATIC_ROOT = os.path.join(BASE_DIR, 'static/')
Copy the code

When finished, save and close the file.

Complete the initial project setup

You can now use administrative scripts to migrate the initial database schema to your PostgreSQL database.

~/myprojectdir/manage.py makemigrations
~/myprojectdir/manage.py migrate
Copy the code

Create an administrative user for the project by typing.

~/myprojectdir/manage.py createsuperuser
Copy the code

You must select a username, provide an email address, and select and confirm a password.

You can type all static content to the directory location you configured.

~/myprojectdir/manage.py collectstatic
Copy the code

You will have to confirm the operation. The static files will then be placed under your project directory in a directory called static.

If you follow the initial server setup guidelines, you should have a UFW firewall to protect your server. To test the development server, you must allow access to the port you will be using.

Create an exception for port 8000 by typing.

sudo ufw allow 8000
Copy the code

Finally, you can use this command to start the Django development server to test your project.

~ / myprojectdir/manage. Py runserver then executes 0.0.0.0:8000Copy the code

In your web browser, access your server’s domain name or IP address and type :8000.

http://server_domain_or_IP:8000
Copy the code

You should receive the default Django index page.

If you add /admin to the end of the URL in the address bar, you will be prompted for the admin user name and password that you created with the createsuperuser command.

After authentication, you can access the default Django admin interface.

When you are finished exploring, press CTRL+C in the terminal window to close the development server.

Test Gunicorn’s service ability to the project

In this tutorial, you will use Gunicorn with Uvicorn to deploy applications. While Gunicorn has traditionally been used to deploy WSGI applications, it also provides a pluggable interface to provide ASGI deployment. It does this by allowing you to consume worker classes exposed by the ASGI server (Uvicorn). Because Gunicorn is a more mature product offering more configurations than Uvicorn, Uvicorn maintainers recommended using Gunicorn and using the Uvicorn Worker class as a full-featured server and process manager.

Before leaving the virtual environment, you should test Gunicorn to make sure it works for your application.

To use the Uvicorn worker and Gunicorn server, go to your project directory and use the gunicorn command below to load the ASGI module for your project.

cd ~/myprojectdir
gunicorn --bind0.0.0.0:8000 myproject. Asgi - w 4 - k uvicorn. Workers. UvicornWorkerCopy the code

This will start Gunicorn on the same interface that the Django development server runs. You can go back and test the application again.

** Note: ** You do not need to use Gunicorn to run your ASGI application. If you only use Uvicorn, you can use the following command.

Uvicorn myproject. Asgi: application, host 0.0.0.0 -- port 8080Copy the code

** Note: The ** admin interface does not apply any styles because Gunicorn does not know how to find the responsible static CSS content.

If the Django welcome page still appears after you start these commands, it confirms that Gunicorn is serving the page and working as expected. By using the gunicorn command, you pass A module to Gunicorn by specifying the relative directory path of Django’s asgi.py file, which is the entry to your application using Python’s module syntax. In this file, you define a function called Application, which is used to communicate with the application. To learn more about the ASGI specification, visit the ASGI website.

When you have finished testing, click CTRL+C in the terminal window to stop Gunicorn.

You have now finished configuring your Django application. You can exit the virtual environment by typing.

deactivate
Copy the code

The virtual environment indicator in your prompt will be removed.

Step 5 – Create the Systemd Socket and service file for Gunicorn

In the previous section, you tested Gunicorn’s ability to interact with a Django application. In this step, you will implement a more powerful way to start and stop application servers by creating systemd services and socket files.

The Gunicorn socket will be created at startup and will listen for connections. When a connection occurs, Systemd automatically starts the Gunicorn process to handle the connection.

First, create and open a Systemd socket file for Gunicorn with sudo permissions.

sudo nano /etc/systemd/system/gunicorn.socket
Copy the code

In the file, you will create a [Unit] section to describe the Socket, a [Socket] section to define the Socket location, and a [Install] section to ensure that the Socket is created at the correct time.

/etc/systemd/system/gunicorn.socket

[Unit]
Description=gunicorn socket

[Socket]
ListenStream=/run/gunicorn.sock

[Install]
WantedBy=sockets.target
Copy the code

When finished, save and close the file.

Next, create and open a Systemd service file for Gunicorn with sudo permissions in the text editor. The name of the service file should be the same as the socket file name for the extension.

sudo nano /etc/systemd/system/gunicorn.service
Copy the code

Start with the [Unit] section, which specifies metadata and dependencies. You write a description of your service here and tell the init system not to start the service until the networking goal is reached. Because the service depends on the socket in the socket file, you need to add a Requires directive to show this relationship.

/etc/systemd/system/gunicorn.service

[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.target
Copy the code

Next, open the [Service] section. You will specify users and groups for the process. You will give ownership of the process to your regular user account because it owns all the related files. You will give the group ownership to the www-data group so that Nginx can easily communicate with Gunicorn.

You will then draw the working directory and specify the command to start the service. In this case, you must specify the full path to the Gunicorn executable, which is installed in the virtual environment. You will bind the process to the Unix socket you created in the /run directory so that the process can communicate with Nginx. You will record all the data to standard output so that the Journald process can collect the Gunicorn logs. You can also specify any optional Gunicorn adjustments here. Here is an example specifying three worker processes.

/etc/systemd/system/gunicorn.service

[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.target

[Service]
User=sammy
Group=www-data
WorkingDirectory=/home/sammy/myprojectdir
ExecStart=/home/sammy/myprojectdir/myprojectenv/bin/gunicorn \
          --access-logfile - \
          -k uvicorn.workers.UvicornWorker \
          --workers 3 \
          --bind unix:/run/gunicorn.sock \
          myproject.asgi:application
Copy the code

Finally, you need to add a [Install] section. This will tell Systemd where to link the service if you want it to start at boot time. You would want this service to start on a normal multi-user system.

/etc/systemd/system/gunicorn.service

[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.target

[Service]
User=sammy
Group=www-data
WorkingDirectory=/home/sammy/myprojectdir
ExecStart=/home/sammy/myprojectdir/myprojectenv/bin/gunicorn \
          --access-logfile - \
          -k uvicorn.workers.UvicornWorker \
          --workers 3 \
          --bind unix:/run/gunicorn.sock \
          myproject.asgi:application

[Install]
WantedBy=multi-user.target
Copy the code

At this point, the Systemd service file is complete. Now save and close it.

Now you can start and enable the Gunicorn socket. This will be done in /run/gunicorn.sock and will create a socket file at boot time. When a connection enters the socket, Systemd automatically starts gunicorn.service to handle it.

sudo systemctl start gunicorn.socket
sudo systemctl enable gunicorn.socket
Copy the code

Now that you have set up the Systemd service and socket file, you will verify that the operation was successful by checking the socket file.

Step 6 – Check for the presence of the Gunicorn socket file

In this step, you will check the condition of the Gunicorn socket file. First, check the status of the process to see if it can start.

sudo systemctl status gunicorn.socket
Copy the code

The output will be similar.

The Output low gunicorn. Socket - gunicorn socket the Loaded: the Loaded (/ etc/systemd/system/gunicorn. The 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.socketCopy the code

Next, check whether the gunicorn.sock file in the /run directory exists.

file /run/gunicorn.sock
Copy the code
Output/run/gunicorn.sock: socket
Copy the code

If the systemctl status command indicates that an error occurred, or if the gunicorn.sock file is not found in the directory, this indicates that the Gunicorn socket was not created correctly. Check the log of the Gunicorn socket by typing.

sudo journalctl -u gunicorn.socket
Copy the code

To have a look at your/etc/systemd/system/gunicorn. The socket file, before proceeding to solve any problems.

Step 7 – Test socket activation

In this step, you will test socket activation. Currently, if you only start the gunicorn.socket unit, gunicorn.service is not activated because the socket has not received any connections. You can check this by typing.

sudo systemctl status gunicorn
Copy the code
The Output low gunicorn. Service - daemon the Loaded gunicorn: the Loaded (/ etc/systemd/system/gunicorn. Service; disabled; vendor preset: enabled) Active: inactive (dead)Copy the code

To test the socket’s activation mechanism, you can send a connection to the socket by typing curl.

curl --unix-socket /run/gunicorn.sock localhost
Copy the code

You should receive HTML output from your application in the terminal. This indicates that Gunicorn is up and ready to serve your Django application. You can verify that the Gunicorn service is running by typing:.

sudo systemctl status gunicorn
Copy the code
The Output low gunicorn. Service - daemon the Loaded gunicorn: the Loaded (/ etc/systemd/system/gunicorn. Service; disabled; vendor preset: enabled) Active: active (running) since Thu 2021-06-10 21:03:29 UTC; 13s ago TriggeredBy: ● Gunicorn. Socket Main PID: 11682 (Gunicorn) Tasks: 4 (LIMIT: 4682) Memory: 98.5m CGroup: / system. Slice/gunicorn service ├ ─ 11682 / home/Sammy myprojectdir/myprojectenv/bin/python3 /home/sammy/myprojectdir/myprojectenv/bin/gunicorn --access-logfile - --workers 3 -k uvicorn.workers.UvicornWorker -- the bind Unix/run/gunicorn sock myproject. Asgi: application ├ ─ 11705 / home/Sammy myprojectdir/myprojectenv/bin/python3 /home/sammy/myprojectdir/myprojectenv/bin/gunicorn --access-logfile - --workers 3 -k uvicorn.workers.UvicornWorker -- the bind Unix/run/gunicorn sock myproject. Asgi: application ├ ─ 11707 / home/Sammy myprojectdir/myprojectenv/bin/python3 /home/sammy/myprojectdir/myprojectenv/bin/gunicorn --access-logfile - --workers 3 -k uvicorn.workers.UvicornWorker -- the bind Unix/run/gunicorn sock myproject. Asgi: application └ ─ 11708 / home/Sammy myprojectdir/myprojectenv/bin/python3 /home/sammy/myprojectdir/myprojectenv/bin/gunicorn --access-logfile - --workers 3 -k uvicorn.workers.UvicornWorker --bind unix:/run/gunicorn.sock myproject.asgi:application Jun 10 21:03:29 django gunicorn[11705]: [2021-06-10 21:03:29 +0000] [11705] [INFO] ASGI 'lifespan' protocol appears unsupported. Jun 10 21:03:29 django gunicorn[11705]: [2021-06-10 21:03:29 +0000] [11705] [INFO] Application startup complete. Jun 10 21:03:30 django gunicorn[11707]: [2021-06-10 21:03:30 +0000] [11707] [INFO] Started server process [11707] Jun 10 21:03:30 django gunicorn[11707]: [2021-06-10 21:03:30 +0000] [11707] [INFO] Waiting for application startup. Jun 10 21:03:30 django gunicorn[11707]: [2021-06-10 21:03:30 +0000] [11707] [INFO] ASGI 'lifespan' protocol appears unsupported. Jun 10 21:03:30 django gunicorn[11707]: [2021-06-10 21:03:30 +0000] [11707] [INFO] Application startup complete. Jun 10 21:03:30 django gunicorn[11708]: [2021-06-10 21:03:30 +0000] [11708] [INFO] Started server process [11708] Jun 10 21:03:30 django gunicorn[11708]: [2021-06-10 21:03:30 +0000] [11708] [INFO] Waiting for application startup. Jun 10 21:03:30 django gunicorn[11708]: [2021-06-10 21:03:30 +0000] [11708] [INFO] ASGI 'lifespan' protocol appears unsupported. Jun 10 21:03:30 django gunicorn[11708]: [2021-06-10 21:03:30 +0000] [11708] [INFO] Application startup complete.Copy the code

If the output from curl or systemctl status indicates that a problem occurred, check the log for more details.

sudo journalctl -u gunicorn
Copy the code

Check your/etc/systemd/system/gunicorn. Service file if there is a problem. If you are in the/etc/systemd/system/gunicorn. The modified service files, please reload the daemon to re-read the service definition, and by typing reboot gunicorn process.

sudo systemctl daemon-reload
sudo systemctl restart gunicorn
Copy the code

Make sure you troubleshoot the above problem before proceeding.

Step 8 – Configure Nginx to broker to Gunicorn

Now that Gunicorn is set up, you need to configure Nginx to pass traffic to the process. In this step, you’ll set up Nginx in front of Gunicorn to take advantage of its high-performance connection handling mechanism and easy-to-implement security features.

First, create and open a new server block in the Site-available directory of Nginx.

sudo nano /etc/nginx/sites-available/myproject
Copy the code

Inside, open a new server block. You will first specify that the block should listen on normal port 80 and should respond to the server’s domain name or IP address.

/etc/nginx/sites-available/myproject

server {
    listen 80;
    server_name server_domain_or_IP;
}
Copy the code

Next, tell Nginx to ignore any questions about finding favicon. You should also tell it where to find your static assets in the ~/myprojectdir/static directory. All of these files have a standard URI prefix of “/static”, so you can create a location block to match these requests.

/etc/nginx/sites-available/myproject

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; }}Copy the code

Finally, create a location / {} block to match all other requests. In this location, you will include the standard proxy_params file included with the Nginx installation, and then you will pass traffic directly to the Gunicorn socket.

/etc/nginx/sites-available/myproject

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; } location / { include proxy_params; proxy_pass http://unix:/run/gunicorn.sock; }}Copy the code

When finished, save and close the file. You can now enable this file by linking it to the site-enabled directory.

sudo ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled
Copy the code

Type the following code to test the Nginx configuration for syntax errors.

sudo nginx -t
Copy the code

If no errors are reported, continue typing and restart Nginx.

sudo systemctl restart nginx
Copy the code

Finally, you need to turn on the firewall so that port 80 traffic is normal. Since you no longer need access to the development server, you can remove the rule that opens port 8000.

sudo ufw delete allow 8000
sudo ufw allow 'Nginx Full'
Copy the code

You should now be able to go to your server’s domain name or IP address and view the Django welcome page that displays the rocket picture.

** Note: ** After configuring Nginx, the next step should be to use SSL/TLS to secure server traffic. This is important because without it, all messages, including passwords, are sent over the network in plain text.

If you have a domain name, the easiest way is to use Let’s Encrypt to get an SSL certificate to guarantee your traffic. Follow this guide to set up Let’s Encrypt with Nginx on Ubuntu 20.04. Follow these steps using the Nginx server block created in this tutorial.

Step 9 – Troubleshoot Nginx and Gunicorn

If the last step does not show your application, you will need to troubleshoot your installation.

Nginx displays the default page instead of a Django application

If Nginx displays the default page instead of proxy to your application, this usually means you need to adjust the /etc/nginx/sites-available/myproject file within server_name to point to your server’s IP address or domain name.

Nginx uses server_name to determine which server block to use to respond to a request. If you receive the default page for Nginx, this indicates that Nginx cannot explicitly match the request to a server block, so it goes back to the default block defined in /etc/nginx/sites-available/default.

The server block in your project, server_name, must be more specific than the default server block in order to be selected.

Nginx shows 502 bad gateway error, not Django application

Error 502 indicates that Nginx could not successfully broker the request. Many configuration problems have error 502, so you need more information to troubleshoot correctly.

The main place to look for more information is the Nginx error log. In general, this will tell you which conditions are causing problems in proxy events. Enter according to the Nginx error log.

sudo tail -F /var/log/nginx/error.log
Copy the code

Now, make another request in the browser, generating a new error (trying to refresh the page). You should receive a new error message and write it to the log. If you take a look at this information, it should help you narrow down the problem.

You may receive the following message.

“`[secondary_label Output]

connect() to unix:/run/gunicorn.sock failed (2: No such file or directory)

OutputThis indicates that Nginx could not find the `gunicorn.sock` file at the given location. You should compare the `proxy_pass` location defined within `/etc/nginx/sites-available/myproject` file to the actual location of the `gunicorn.sock` file generated by the `gunicorn.socket` systemd unit.

If you cannot find a `gunicorn.sock` file within the `/run` directory, it generally means that the systemd socket file was unable to create it. Go back to the [section on checking for the Gunicorn socket file](#checking-for-the-gunicorn-socket-file) to step through the troubleshooting steps for Gunicorn.

```
connect() to unix:/run/gunicorn.sock failed (13: Permission denied)
Copy the code

This indicates that Nginx was unable to connect to the Gunicorn socket because of permission issues. This can happen when the program uses the root user instead of the sudo user. While Systemd was able to create the Gunicorn socket file, Nginx was unable to access it.

This can happen if there are limited permissions at any point between the root directory (/) and the gunicorn.sock file. You can view the permission and ownership values of a socket file and each of its parent directories by passing the absolute path to the socket file to the namei command.

namei -l /run/gunicorn.sock
Copy the code
Outputf: /run/gunicorn.sock
drwxr-xr-x root root /
drwxr-xr-x root root run
srw-rw-rw- root root gunicorn.sock
Copy the code

The output shows the permissions for each directory component. You can figure out what types of access to socket files are allowed by looking at permissions (first column), owners (second column), and group owners (third column).

In the above example, the socket file and each directory leading to the socket file have world read and execute permissions (the directory’s permission bar ends with r-x, not –). The Nginx process should be able to access this socket successfully.

If any directory to the socket does not have world read and execute permissions, Nginx will not be able to access the socket unless it allows world read and execute permissions, or ensures that group ownership is granted to the group to which Nginx belongs.

Django says: “Could not connect to server: connection denied”

When you try to access parts of your application in a Web browser, you may receive a message from Django.

“‘ [secondary_label Output] OperationalError at /admin/login/ could not connect to server: Whether the rejected server is on the host Running on “localhost” (127.0.0.1) and accepting TCP/IP connections on port 5432?


This indicates that Django is unable to connect to the Postgres database.  Make sure that the Postgres instance is running by typing:

```command
sudo systemctl status postgresql
Copy the code

If not, you can start it and type it to start automatically when it starts (if it hasn’t already been configured to do so).

sudo systemctl start postgresql
sudo systemctl enable postgresql
Copy the code

If you still have problems, make sure your ~ / myprojectdir/myproject/Settings. Py file defined in the database Settings are correct.

Further troubleshooting

For additional troubleshooting, logging can help narrow down the root cause. Examine each of them in turn for information indicating the problem area.

The following log may be helpful.

  • Check the Nginx process log by typing.sudo journalctl -u nginx
  • Check the Nginx access log by typing.sudo less /var/log/nginx/access.log
  • Check the Nginx error log by typing.sudo less /var/log/nginx/error.log
  • Check the log of the Gunicorn application by typing.sudo journalctl -u gunicorn
  • Check the log of the Gunicorn socket by typing.sudo journalctl -u gunicorn.socket

When you update your configuration or application, you may need to restart these processes to accommodate your changes.

If you update your Django application, you can type to restart the Gunicorn process to receive the changes.

sudo systemctl restart gunicorn
Copy the code

If you change the Gunicorn socket or service file, reload the daemon and type to restart the process.

sudo systemctl daemon-reload
sudo systemctl restart gunicorn.socket gunicorn.service
Copy the code

If you change the configuration of the Nginx server block, test the configuration and then type Nginx.

sudo nginx -t && sudo systemctl restart nginx
Copy the code

These commands help catch changes as you adjust your configuration.

conclusion

In this tutorial, you’ve set up an ASGI Django project in your virtual environment. You configured Gunicorn and Uvicorn to translate client requests asynchronously so that Django can handle them. After that, you set up Nginx to act as a reverse proxy to handle client connections and provide the correct items based on client requests.

Django simplifies the process of creating projects and applications, providing many common sections that allow you to focus on unique elements. By using the general toolchain described in this article, you can serve your application from a server.