One place for hosting & domains

      Postgres

      How To Set Up an ASGI Django App with Postgres, Nginx, and Uvicorn on Ubuntu 20.04


      Introduction

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

      The traditional way to deploy a Django app is with a Web Server Gateway Interface (WSGI). However, with the advent of Python 3 and the support of asynchronous execution, you can now execute your Python apps via asynchronous callables with an Asynchronous Server Gateway Interface (ASGI). A successor to WSGI, the ASGI specification in Python is a superset of WSGI and can be a drop-in replacement for WSGI.

      Django allows for an “async outside, sync inside” mode that allows your code to be synchronous internally, while the ASGI server handles requests asynchronously. By allowing the webserver to have an asynchronous callable, it can handle multiple incoming and outgoing events for each application. The Django application is still synchronous internally to allow for backward compatibility and to avoid the complexity of parallel computing. This also means that your Django app requires no changes to switch from WSGI to ASGI.

      In this guide, you will install and configure some components on Ubuntu 20.04 to support and serve Django applications. You’ll set up a PostgreSQL database instead of using the default SQLite database. You will configure the Gunicorn application server paired with Uvicorn, an ASGI implementation, to interface with your applications asynchronously. You will then set up Nginx to reverse proxy to Gunicorn, giving you access to its security and performance features to serve your apps.

      Prerequisites

      To complete this tutorial, you will need:

      Step 1 — Installing the Packages from the Ubuntu Repositories

      To begin the process, you’ll download and install all of the items you need from the Ubuntu repositories. You will use the Python package manager pip to install additional components a bit later.

      First, you’ll need to update the local apt package index and then download and install the packages. The packages you install depend on which version of Python your project will use.

      Use the following command to install the necessary system packages:

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

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

      Step 2 — Creating the PostgreSQL Database and User

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

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

      During the Postgres installation, an operating system user named postgres was created to correspond to the postgres PostgreSQL administrative user. You’ll need to use this user to perform administrative tasks. You can use sudo and pass in the username with the -u option.

      Log into an interactive Postgres session by typing:

      You will be given a PostgreSQL prompt where you can set up requirements.

      First, create a database for your project:

      • CREATE DATABASE myproject;

      Note: Every Postgres statement must end with a semicolon. If you’re experiencing issues, make sure your commands end with a semicolon.

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

      • CREATE USER myprojectuser WITH PASSWORD 'password';

      Afterward, you’ll modify a few of the connection parameters for the user you just created. This will speed up database operations so that the correct values do not have to be queried and set each time a connection is established.

      You will set the default encoding to UTF-8, which Django expects. You’ll also set the default transaction isolation scheme to “read committed”, which blocks reads from uncommitted transactions. Lastly, you’ll set the timezone. By default, the Django project will be set to use UTC. These are all recommendations from 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';

      Now, you can give your new user access to administer your new database:

      • GRANT ALL PRIVILEGES ON DATABASE myproject TO myprojectuser;

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

      Postgres is now set up so that Django can connect to and manage its database information.

      Step 3 — Creating a Python Virtual Environment for your Project

      Now that you have a database, you can begin getting the rest of your project requirements ready. You will be installing your Python requirements within a virtual environment for easier management.

      First, create and move into a directory where you can keep your project files:

      • mkdir ~/myprojectdir
      • cd ~/myprojectdir

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

      • python3 -m venv myprojectenv

      This will create a directory called myprojectenv within your myprojectdir directory. Inside, it will install a local version of Python and a local version of pip. You can use this to install and configure an isolated Python environment for your project.

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

      • source myprojectenv/bin/activate

      Your prompt should change to indicate that you are now operating within a Python virtual environment. It will look something like this: (myprojectenv)user@host:~/myprojectdir$.

      You will install Django in the virtual environment. Installing Django into an environment specific to your project will allow your projects and their requirements to be handled separately. With your virtual environment active, install Django, Gunicorn, Uvicorn, and the psycopg2 PostgreSQL adaptor with the local instance of pip:

      Note: When the virtual environment is activated (when your prompt has (myprojectenv) preceding it), use pip instead of pip3, even if you are using Python 3. The virtual environment’s copy of the tool is always named pip, regardless of the Python version.

      • pip install django gunicorn uvicorn psycopg2-binary

      You should now have all of the software needed to start a Django project.

      Step 4 — Creating and Configuring a New Django Project

      With the Python components installed, you can create the actual Django project files.

      Creating the Django Project

      Since you already have a project directory, you can tell Django to install the files here. It will create a second-level directory with the actual code, which is normal, and place a management script in this directory. The key to this is that you are defining the directory explicitly instead of allowing Django to make decisions relative to your current directory:

      • django-admin startproject myproject ~/myprojectdir

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

      • ~/myprojectdir/manage.py: A Django project management script.
      • ~/myprojectdir/myproject/: The Django project package. This should contain the __init__.py, asgi.py, settings.py, urls.py, and wsgi.py files.
      • ~/myprojectdir/myprojectenv/: The virtual environment directory you created earlier.

      Adjusting the Project Settings

      After creating your project files, you’ll need to adjust some settings. Open the settings file in your text editor:

      • nano ~/myprojectdir/myproject/settings.py

      Start by locating the ALLOWED_HOSTS directive. This defines a list of the server’s addresses or domain names that may be used to connect to the Django instance. Any incoming requests with a Host header not in this list will raise an exception. Django requires that you set this to prevent a certain class of security vulnerability.

      In the square brackets, list the IP addresses or domain names associated with your Django server. List each item in quotations with entries separated by a comma. To allow an entire domain and any subdomains, prepend a period to the beginning of the entry. In the snippet below, there are a few commented out examples used to demonstrate how to do this:

      Note: Be sure to include localhost as one of the options since you will be proxying connections 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']
      

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

      Change the settings with your PostgreSQL database information. You’ll tell Django to use the psycopg2 adaptor you installed with pip. You need to give the database name, the database username, the database user’s password, and then specify that the database is located on the local computer. You can leave the PORT setting as an empty string:

      ~/myprojectdir/myproject/settings.py

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

      Next, move down to the bottom of the file and add a setting indicating where the static files should be placed. This is necessary so that Nginx can handle requests for these items. The following 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/')
      

      Save and close the file when you are finished.

      Completing Initial Project Setup

      Now, you can migrate the initial database schema to your PostgreSQL database using the management script:

      • ~/myprojectdir/manage.py makemigrations
      • ~/myprojectdir/manage.py migrate

      Create an administrative user for the project by typing:

      • ~/myprojectdir/manage.py createsuperuser

      You will have to select a username, provide an email address, and choose and confirm a password.

      You can collect all of the static content into the directory location you configured by typing:

      • ~/myprojectdir/manage.py collectstatic

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

      If you followed the initial server setup guide, you should have a UFW firewall protecting your server. To test the development server, you’ll have to allow access to the port you’ll be using.

      Create an exception for port 8000 by typing:

      Finally, you can test out your project by starting up the Django development server with this command:

      • ~/myprojectdir/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
      

      You should receive the default Django index page:

      Django index page

      If you append /admin to the end of the URL in the address bar, you will be prompted for the administrative username and password you created with the createsuperuser command:

      Django admin login

      After authenticating, you can access the default Django admin interface:

      Django admin interface

      When you are finished exploring, hit CTRL+C in the terminal window to shut down the development server.

      Testing Gunicorn’s Ability to Serve the Project

      In this tutorial, you will be using Gunicorn paired with Uvicorn to deploy the application. Although Gunicorn is traditionally used to deploy WSGI applications, it also provides a pluggable interface to provide ASGI deployment. It does this by allowing you to consume a worker class exposed by the ASGI server (uvicorn). Because Gunicorn is a more mature product and offers more configurations than Uvicorn, the Uvicorn maintainers recommend using gunicorn with the uvicorn worker class as a fully featured server and process manager.

      Before leaving the virtual environment, you’ll test Gunicorn to make sure that it can serve the application.

      To use uvicorn workers with the gunicorn server, enter your project directory and use the following gunicorn command to load the project’s ASGI module:

      • cd ~/myprojectdir
      • gunicorn --bind 0.0.0.0:8000 myproject.asgi -w 4 -k uvicorn.workers.UvicornWorker

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

      Note: It is not required to use Gunicorn to run your ASGI application. To use only uvicorn, you would use the following command:

      • uvicorn myproject.asgi:application --host 0.0.0.0 --port 8080

      Note: The admin interface will not have any styling applied since Gunicorn does not know how to find the static CSS content responsible for this.

      If the Django welcome page still appears after starting these commands, this is confirmation that gunicorn served the page and is working as intended. By using the gunicorn command, you passed Gunicorn a module by specifying the relative directory path to Django’s asgi.py file, which is the entry point to your application, using Python’s module syntax. Inside of this file, a function called application is defined, which is used to communicate with the application. To learn more about the ASGI specification, go to the official ASGI website.

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

      You’ve now finished configuring your Django application. You can back out of the virtual environment by typing:

      The virtual environment indicator in your prompt will be removed.

      Step 5 — Creating systemd Socket and Service Files for Gunicorn

      In the previous section, you tested that Gunicorn can interact with the Django application. In this step, you’ll implement a more robust way of starting and stopping the application server by making 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, you’ll 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:

      /etc/systemd/system/gunicorn.socket

      [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 exception for the extension:

      • sudo nano /etc/systemd/system/gunicorn.service

      Start with the [Unit] section, which is used to specify metadata and dependencies. You’ll put a description of your service here and tell the init system to start this only after the networking target has been reached. Because the service relies on the socket from the socket file, you’ll need to include a Requires directive to indicate that relationship:

      /etc/systemd/system/gunicorn.service

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

      Next, open up the [Service] section. You’ll specify the user and group that you want the process to run under. You will give your regular user account ownership of the process since it owns all relevant files. You’ll give group ownership to the www-data group so that Nginx can communicate easily with Gunicorn.

      You’ll then map out the working directory and specify the command to use to start the service. In this case, you’ll have to specify the full path to the Gunicorn executable, which is installed within the virtual environment. You will bind the process to the Unix socket you created within the /run directory so that the process can communicate with Nginx. You’ll log all data to standard output so that the journald process can collect the Gunicorn logs. You can also specify any optional Gunicorn tweaks here. Here’s an example of 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
      

      Finally, you’ll add an [Install] section. This will tell systemd what to link this service to if you enable it to start at boot. You’ll want this service to start when the regular multi-user system is up and running:

      /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
      

      With that, the systemd service file is complete. Save and close it now.

      You 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

      Now that you have made systemd service and socket files, you will confirm that the operation was successful by checking for the socket file.

      Step 6 — Checking for the Gunicorn Socket File

      In this step, you’ll check for the Gunicorn socket file. First, check the status of the process to find out whether it was able to start:

      • sudo systemctl status gunicorn.socket

      The output will look similar to 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

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

      Output

      /run/gunicorn.sock: socket

      If the systemctl status command indicated an error occurred or if you do not find the gunicorn.sock file in the directory, this indicates that the Gunicorn socket was not created correctly. Check the Gunicorn socket’s logs by typing:

      • sudo journalctl -u gunicorn.socket

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

      Step 7 — Testing Socket Activation

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

      • sudo systemctl status gunicorn

      Output

      ● gunicorn.service - gunicorn daemon Loaded: loaded (/etc/systemd/system/gunicorn.service; disabled; vendor preset: enabled) Active: inactive (dead)

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

      • curl --unix-socket /run/gunicorn.sock localhost

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

      • sudo systemctl status gunicorn

      Output

      ● gunicorn.service - gunicorn daemon Loaded: 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 --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 --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 --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.

      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 gunicorn

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

      • sudo systemctl daemon-reload
      • sudo systemctl restart gunicorn

      Make sure you troubleshoot the above issues before continuing.

      Step 8 — Configure Nginx to Proxy Pass to Gunicorn

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

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

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

      Inside, open up a new server block. You’ll start by specifying that this block should listen on the normal port 80 and that it 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;
      }
      

      Next, tell Nginx to ignore any problems with finding a favicon. You will also tell it where to find the static assets that you collected 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 those 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;
          }
      }
      

      Finally, create a location / {} block to match all other requests. Inside this location, you’ll include the standard proxy_params file included with the Nginx installation and then you’ll pass the 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;
          }
      }
      

      Save and close the file when you are finished. Now, you 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:

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

      • sudo systemctl restart nginx

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

      • sudo ufw delete allow 8000
      • sudo ufw allow 'Nginx Full'

      You should now be able to go to your server’s domain or IP address to view the Django welcome page with the rocket image displayed.

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

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

      Step 9 — Troubleshooting Nginx and Gunicorn

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

      Nginx Is Showing the Default Page Instead of the Django Application

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

      Nginx uses the server_name to determine which server block to use to respond to requests. If you receive the default Nginx page, it is a sign that Nginx wasn’t able to match the request to a sever block explicitly, so it’s falling back on the default block defined in /etc/nginx/sites-available/default.

      The server_name in your project’s server block must be more specific than the one in the default server block to be selected.

      Nginx Is Displaying a 502 Bad Gateway Error Instead of the Django Application

      A 502 error indicates that Nginx is unable to successfully proxy the request. A wide range of configuration problems express themselves with a 502 error, so more information is required to troubleshoot properly.

      The primary place to look for more information is in Nginx’s error logs. Generally, this will tell you what conditions caused problems during the proxying event. Follow the Nginx error logs by typing:

      • sudo tail -F /var/log/nginx/error.log

      Now, make another request in your browser to generate a fresh error (try refreshing the page). You should receive a new error message written to the log. If you look at the message, it should help you narrow down the problem.

      You might receive the following message:

      “`[secondary_label Output]
      connect() to unix:/run/gunicorn.sock failed (2: No such file or directory)

      Output

      This 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)

      This indicates that Nginx was unable to connect to the Gunicorn socket because of permissions problems. This can happen when the procedure uses the root user instead of a sudo user. While systemd is able to create the Gunicorn socket file, Nginx is 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 review the permissions and ownership values of the 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

      Output

      f: /run/gunicorn.sock drwxr-xr-x root root / drwxr-xr-x root root run srw-rw-rw- root root gunicorn.sock

      The output displays the permissions of each of the directory components. By looking at the permissions (first column), owner (second column), and group owner (third column), you can figure out what type of access is allowed to the socket file.

      In the above example, the socket file and each of the directories leading up to the socket file have world read and execute permissions (the permissions column for the directories end with r-x instead of ---). The Nginx process should be able to access the socket successfully.

      If any of the directories leading up to the socket do not have world read and execute permission, Nginx will not be able to access the socket without allowing world read and execute permissions or making sure group ownership is given to a group that Nginx is a part of.

      Django Is Displaying: "could not connect to server: Connection refused”

      One message that you may receive from Django when attempting to access parts of the application in the web browser is:

      “`[secondary_label Output]
      OperationalError at /admin/login/
      could not connect to server: Connection refused
      Is the server running on host "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
      

      If it is not, you can start it and enable it to start automatically at boot (if it is not already configured to do so) by typing:

      • sudo systemctl start postgresql
      • sudo systemctl enable postgresql

      If you are still having issues, make sure the database settings defined in the ~/myprojectdir/myproject/settings.py file are correct.

      Further Troubleshooting

      For additional troubleshooting, the logs can help narrow down root causes. Check each of them in turn and look for messages indicating problem areas.

      The following logs may be helpful:

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

      As you update your configuration or application, you will likely need to restart the processes to adjust to your changes.

      If you update your Django application, you can restart the Gunicorn process to pick up the changes by typing:

      • sudo systemctl restart gunicorn

      If you change Gunicorn socket or service files, reload the daemon and restart the process by typing:

      • sudo systemctl daemon-reload
      • sudo systemctl restart gunicorn.socket gunicorn.service

      If you change the Nginx server block configuration, test the configuration and then Nginx by typing:

      • sudo nginx -t && sudo systemctl restart nginx

      These commands are helpful for picking up changes as you adjust your configuration.

      Conclusion

      In this guide, you’ve set up an ASGI Django project in its own virtual environment. You’ve configured Gunicorn and Uvicorn to translate client requests asynchronously so that Django can handle them. Afterward, you set up Nginx to act as a reverse proxy to handle client connections and serve the correct project depending on the client request.

      Django streamlines the process of creating projects and applications by providing many of the common pieces, allowing you to focus on the unique elements. By leveraging the general tool chain described in this article, you can serve the applications you create from a single server.



      Source link

      Einrichten von Django mit Postgres, Nginx und Gunicorn unter Ubuntu 20.04


      Einführung

      Django ist ein leistungsfähiges Web-Framework, das Ihnen dabei helfen kann, Ihre Python-Anwendung oder Website bereitzustellen. Django umfasst einen vereinfachten Entwicklungsserver zum lokalen Testen Ihres Codes; für alles, was auch nur ansatzweise mit der Produktion zu tun hat, wird ein sicherer und leistungsfähiger Webserver benötigt.

      In diesem Leitfaden zeigen wir, wie sich bestimmte Komponenten zum Unterstützen und Bereitstellen von Django-Anwendungen in Ubuntu 20.04 installieren und konfigurieren lassen. Wir werden anstelle der standardmäßigen SQLite-Datenbank eine PostgreSQL-Datenbank einrichten. Wir werden den Gunicorn-Anwendungsserver als Schnittstelle zu unseren Anwendungen konfigurieren. Dann werden wir Nginx als Reverseproxy für Gunicorn einrichten, damit wir beim Bereitstellen unserer Anwendungen auf dessen Sicherheits- und Leistungsmerkmale zugreifen können.

      Voraussetzungen und Ziele

      Um diesen Leitfaden erfolgreich zu absolvieren, sollten Sie eine neue Ubuntu 20.04-Serverinstanz mit einer einfachen Firewall und einem Nicht-root-Benutzer mit sudo-Berechtigungen konfiguriert haben. In unserem Leitfaden zur Ersteinrichtung des Servers erfahren Sie, wie Sie die Einrichtung vornehmen.

      Wir werden Django in einer virtuellen Umgebung installieren. Wenn Sie Django in einer für Ihr Projekt spezifischen Umgebung installieren, können Sie Ihre Projekte und deren Anforderungen separat verwalten.

      Sobald wir über unsere Datenbank verfügen und die Anwendung ausgeführt wird, installieren und konfigurieren wir den Gunicorn-Anwendungsserver. Dieser wird als Schnittstelle zu unserer Anwendung dienen und Clientanfragen aus HTTP in Python-Aufrufe übersetzen, die unsere Anwendung verarbeiten kann. Dann richten wir Nginx vor Gunicorn ein, um dessen leistungsfähige Verbindungsverwaltungsmechanismen und einfach zu implementierenden Sicherheitsfunktionen nutzen zu können.

      Fangen wir an.

      Installieren der Pakete aus den Ubuntu-Repositorys

      Zu Beginn laden wir alle Elemente, die wir benötigen, aus den Ubuntu-Repositorys herunter und installieren sie. Ein wenig später werden wir mit dem Python-Paketmanager pip zusätzliche Komponenten installieren.

      Wir müssen zuerst den lokalen Paketindex apt aktualisieren und dann die Pakete herunterladen und installieren: Die installierten Pakete hängen davon ab, welche Version von Python Sie für Ihr Projekt verwenden werden.

      Wenn Sie Django mit Python 3 nutzen, geben Sie Folgendes ein:

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

      Django 1.11 ist die letzte Version von Django, die Python 2 unterstützt. Wenn Sie neue Projekte starten, wird dringend empfohlen, Python 3 zu wählen. Wenn Sie Python 2 weiter verwenden müssen, geben Sie Folgendes ein:

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

      Dadurch werden pip, die Python-Entwicklungsdateien, die zum späteren Erstellen von Gunicorn benötigt werden, das Postgres-Datenbankysystem, die zum Interagieren damit erforderlichen Bibliotheken sowie der Nginx-Webserver installiert.

      Erstellen der PostgreSQL-Datenbank und des Benutzers

      Wir legen sofort los und erstellen für unsere Django-Anwendung eine Datenbank und einen Datenbankbenutzer.

      Standardmäßig nutzt Postgres ein Authentifizierungschema namens „Peer Authentication“ für lokale Verbindungen. Im Grunde bedeutet dies, dass sich der Benutzer ohne weitere Authentifizierung anmelden kann, wenn der Benutzername des Benutzers im Betriebssystem mit einem gültigen Postgres-Benutzernamen übereinstimmt.

      Während der Postgres-Installation wurde ein Betriebssystembenutzer namens postgres erstellt, der dem administrativen PostgreSQL-Benutzer postgres entspricht. Wir benötigen diesen Benutzer zur Erledigung administrativer Aufgaben. Wir können sudo verwenden und den Benutzernamen mit der Option -u übergeben.

      Melden Sie sich in einer interaktiven Postgres-Sitzung an, indem Sie Folgendes eingeben:

      Ihnen wird eine PostgreSQL-Eingabeaufforderung angezeigt, in der Sie Ihre Anforderungen einrichten können.

      Erstellen Sie zunächst eine Datenbank für Ihr Projekt:

      • CREATE DATABASE myproject;

      Anmerkung: Jede Postgres-Anweisung muss mit einem Semikolon enden; stellen Sie sicher, dass Ihr Befehl auf ein Semikolon endet, falls Probleme auftreten.

      Erstellen Sie als Nächstes einen Datenbankbenutzer für das Projekt. Wählen Sie unbedingt ein sicheres Passwort:

      • CREATE USER myprojectuser WITH PASSWORD 'password';

      Anschließend ändern wir einige der Verbindungsparameter für den gerade erstellten Benutzer. Dadurch werden Datenbankoperationen beschleunigt, sodass die richtigen Werte nicht jedes Mal abgefragt und festgelegt werden müssen, wenn eine Verbindung hergestellt wird.

      Wir legen die Standardkodierung auf UTF-8 fest, was Django erwartet. Außerdem legen wir das standardmäßige Transaktionsisolierungsschema auf „read committed“ fest, um das Lesen von Blöcken aus Transaktionen ohne Commit zu blockieren. Schließlich legen wir die Zeitzone fest. Standardmäßig werden unsere Django-Projekte die Zeitzone UTC verwenden. Dies sind alles Empfehlungen aus dem Django-Projekt selbst:

      • 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';

      Jetzt können wir unserem neuen Benutzer Zugriff zum Verwalten unserer neuen Datenbank gewähren:

      • GRANT ALL PRIVILEGES ON DATABASE myproject TO myprojectuser;

      Wenn Sie damit fertig sind, beenden Sie die PostgreSQL-Eingabeaufforderung durch folgende Eingabe:

      Postgres ist nun so eingerichtet, dass Django eine Verbindung herstellen und dessen Datenbankinformationen verwalten kann.

      Erstellen einer virtuellen Python-Umgebung für Ihr Projekt

      Nachdem wir unsere Datenbank erstellt haben, können wir nun damit beginnen, die restlichen Projektanforderungen zu erfüllen. Wir werden unsere Python-Anforderungen zur einfacheren Verwaltung in einer virtuellen Umgebung installieren.

      Dazu benötigen wir zunächst Zugriff auf den Befehl virtualenv. Wir können ihn mit pip installieren.

      Wenn Sie Python 3 verwenden, aktualisieren Sie pip und installieren Sie das Paket durch folgende Eingabe:

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

      Wenn Sie Python 2 verwenden, aktualisieren Sie pip und installieren Sie das Paket durch folgende Eingabe:

      • sudo -H pip install --upgrade pip
      • sudo -H pip install virtualenv

      Nach der Installation von virtualenv können wir mit der Gestaltung unseres Projekts beginnen. Erstellen und wechseln Sie in ein Verzeichnis, in dem wir unsere Projektdateien speichern können.

      • mkdir ~/myprojectdir
      • cd ~/myprojectdir

      Erstellen Sie im Projektverzeichnis durch folgende Eingabe eine virtuelle Python-Umgebung:

      Auf diese Weise wird ein Verzeichnis mit dem Namen myprojectenv in Ihrem Verzeichnis myprojectdir erstellt. Darin wird eine lokale Version von Python und eine lokale Version von pip installiert. Mit ihrer Hilfe können wir für unser Projekt eine isolierte Python-Umgebung installieren und konfigurieren.

      Bevor wir die Python-Anforderungen unseres Projekts installieren, müssen wir die virtuelle Umgebung aktivieren. Geben Sie hierzu Folgendes ein:

      • source myprojectenv/bin/activate

      Ihre Eingabeaufforderung ändert sich und zeigt an, dass Sie jetzt innerhalb einer virtuellen Python-Umgebung arbeiten. Sie sieht etwa wie folgt aus: (myprojectenv)user@host:~/myprojectdir$.

      Bei aktivierter virtueller Umgebung installieren Sie Django, Gunicorn und den PostgreSQL-Adapter psycopg2 mit der lokalen Instanz von pip:

      Anmerkung: Wenn die virtuelle Umgebung aktiviert ist (wenn Ihrer Eingabeaufforderung (myprojectenv) voransteht), verwenden Sie pip anstelle von pip3, selbst wenn Sie Python 3 verwenden. Die Kopie des Tools der virtuellen Umgebung heißt immer pip – unabhängig von der Python-Version.

      • pip install django gunicorn psycopg2-binary

      Sie sollten nun die gesamte für den Start eines Django-Projekts erforderliche Software haben.

      Erstellen und Konfigurieren eines neuen Django-Projekts

      Nach der Installation unserer Python-Komponenten können wir die eigentlichen Django-Projektdateien erstellen.

      Erstellen des Django-Projekts

      Da wir bereits über ein Projektverzeichnis verfügen, werden wir Django anweisen, die Dateien dort zu installieren. Es wird ein Verzeichnis der zweiten Ebene mit dem tatsächlichen Code erstellt, was normal ist, und ein Managementskript in diesem Verzeichnis platziert. Der Schlüssel dazu besteht darin, dass wir das Verzeichnis explizit definieren, anstatt Django Entscheidungen in Bezug auf unser aktuelles Verzeichnis zu ermöglichen:

      • django-admin.py startproject myproject ~/myprojectdir

      An diesem Punkt sollte Ihr Projektverzeichnis (in unserem Fall ~/myprojectdir) folgenden Inhalt haben:

      • ~/myprojectdir/manage.py: Ein Django-Projektmanagement-Skript.
      • ~/myprojectdir/myproject/: Das Django-Projektpaket. Dieses sollte die Dateien __init__.py, settings.py, urls.py, asgi.py und wsgi.py enthalten.
      • ~/myprojectdir/myprojectenv/: Das Verzeichnis der virtuellen Umgebung, die wir zuvor erstellt haben.

      Anpassen der Projekteinstellungen

      Das Erste, was wir mit unseren neu erstellten Projektdateien tun sollten, ist das Anpassen der Einstellungen. Öffnen Sie die Einstellungsdatei in Ihrem Texteditor:

      • nano ~/myprojectdir/myproject/settings.py

      Suchen Sie zunächst nach der Direktive ALLOWED_HOSTS. Dadurch wird eine Liste der Adressen oder Domänennamen des Servers definiert, die zum Herstellen einer Verbindung mit der Django-Instanz genutzt werden können. Alle eingehenden Anfragen mit einem Host, der sich nicht in dieser Liste befindet, werden eine Ausnahme auslösen. Django verlangt, dass Sie dies so festlegen, um eine bestimmte Art von Sicherheitslücke zu verhindern.

      In den quadratischen Klammern listen Sie die IP-Adressen oder Domänennamen auf, die mit Ihrem Django-Projekt verknüpft sind. Jedes Element sollte in Anführungszeichen aufgelistet werden, wobei Einträge durch ein Komma getrennt werden. Wenn Sie Anfragen für eine ganze Domäne und Subdomänen wünschen, stellen Sie dem Anfang des Eintrags einen Punkt voran. Im folgenden Snippet befinden sich einige auskommentierte Beispiele:

      Anmerkung: Stellen Sie sicher, dass localhost als eine der Optionen eingeschlossen ist, da wir Verbindungen über eine lokale Nginx-Instanz vermitteln werden.

      ~/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']
      

      Als Nächstes suchen Sie nach dem Bereich, der Datenbankzugriff konfiguriert. Er beginnt mit DATABASES. Die Konfiguration in der Datei dient für eine SQLite-Datenbank. Wir haben für unser Projekt bereits eine PostgreSQL-Datenbank erstellt; daher müssen wir die Einstellungen anpassen.

      Ändern Sie die Einstellungen mit Ihren PostgreSQL-Datenbankinformationen. Wir weisen Django an, den mit pip installierten psycopg2-Adapter zu verwenden. Wir müssen den Datenbanknamen, den Namen des Datenbankbenutzers und das Passwort des Datenbankbenutzers angeben. Dann geben wir an, dass sich die Datenbank auf dem lokalen Computer befindet. Sie können die PORT-Einstellung als leere Zeichenfolge belassen:

      ~/myprojectdir/myproject/settings.py

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

      Als Nächstes bewegen Sie sich nach unten zum Ende der Datei und fügen eine Einstellung hinzu, die angibt, wo die statischen Dateien platziert werden sollen. Das ist notwendig, damit Nginx Anfragen für diese Elemente verwalten kann. In der folgenden Zeile wird Django angewiesen, sie im grundlegenden Projektverzeichnis in einem Verzeichnis mit dem Namen static zu platzieren:

      ~/myprojectdir/myproject/settings.py

      . . .
      
      STATIC_URL = '/static/'
      STATIC_ROOT = os.path.join(BASE_DIR, 'static/')
      

      Wenn Sie dies abgeschlossen haben, speichern und schließen Sie die Datei.

      Abschließen der anfänglichen Projekteinrichtung

      Jetzt können wir das erste Datenbankschema mit dem Managementskript in unsere PostgreSQL-Datenbank migrieren:

      • ~/myprojectdir/manage.py makemigrations
      • ~/myprojectdir/manage.py migrate

      Erstellen Sie durch folgende Eingabe einen administrativen Benutzer für das Projekt:

      • ~/myprojectdir/manage.py createsuperuser

      Sie müssen einen Benutzernamen auswählen, eine E-Mail-Adresse angeben und ein Passwort bestätigen.

      Wir können alle statischen Inhalte am von uns konfigurierten Verzeichnisort sammeln, indem wir Folgendes eingeben:

      • ~/myprojectdir/manage.py collectstatic

      Sie müssen die Operation bestätigen. Die statischen Dateien werden dann in Ihrem Projektverzeichnis in einem Verzeichnis mit dem Namen static platziert.

      Wenn Sie den Leitfaden zur Ersteinrichtung des Servers befolgt haben, sollte Ihre UFW-Firewall Ihren Server schützen. Um den Entwicklungsserver zu testen, müssen wir Zugriff auf den Port gewähren, den wir dazu verwenden möchten.

      Erstellen Sie durch folgende Eingabe eine Ausnahme für Port 8000:

      Schließlich können Sie Ihr Projekt durch Starten des Django-Entwicklungsservers mit diesem Befehl testen:

      • ~/myprojectdir/manage.py runserver 0.0.0.0:8000

      Rufen Sie in Ihrem Webbrowser den Domänennamen oder die IP-Adresse Ihres Servers auf, gefolgt von :8000:

      http://server_domain_or_IP:8000
      

      Sie sollten nun die Indexseite von Django erhalten:

      Django-Indexseite

      Wenn Sie am Ende der URL in der Adressleiste /admin anfügen, werden Sie zur Eingabe des administrativen Benutzernamens und Passworts aufgefordert, die Sie mit dem Befehl createsuperuser erstellt haben:

      Django-Admin-Anmeldung

      Nach der Authentifizierung können Sie auf die standardmäßige Admin-Schnittstelle von Django zugreifen:

      Django-Admin-Schnittstelle

      Wenn Sie mit der Erkundung fertig sind, klicken Sie im Terminalfenster auf Strg+C, um den Entwicklungsserver herunterzufahren.

      Testen der Fähigkeit von Gunicorn zum Bereitstellen des Projekts

      Das Letzte, was wir tun möchten, bevor wir unsere virtuelle Umgebung verlassen, ist Gunicorn zu testen. Dadurch wollen wir sicherstellen, dass die Anwendung bereitgestellt werden kann. Wir geben dazu unser Projektverzeichnis ein und verwenden gunicorn zum Laden des WSGI-Moduls des Projekts:

      • cd ~/myprojectdir
      • gunicorn --bind 0.0.0.0:8000 myproject.wsgi

      Dadurch wird Gunicorn an der gleichen Schnittstelle gestartet, an der auch der Django-Server ausgeführt wurde. Sie können zurückgehen und die Anwendung erneut testen.

      Anmerkung: Die Admin-Schnittstelle wird keinen der verwendeten Stile verwenden, da Gunicorn nicht weiß, wo der dafür zuständige statische CSS-Inhalt zu finden ist.

      Wir haben Gunicorn einem Modul übergeben, indem wir mithilfe der Modulsyntax von Python den relativen Verzeichnispfad zur Datei wsgi.py von Django angegeben haben. Diese ist der Einstiegspunkt für unsere Anwendung. In dieser Datei ist eine Funktion namens application definiert, die zur Kommunikation mit der Anwendung dient. Um mehr über die WSGI-Spezifikation zu erfahren, klicken Sie hier.

      Wenn Sie mit dem Testen fertig sind, drücken Sie im Terminalfenster auf Strg+C, um Gunicorn anzuhalten.

      Wir sind nun fertig mit der Konfiguration unserer Django-Anwendung. Wir können unsere virtuelle Umgebung durch folgende Eingabe verlassen:

      Der Indikator für die virtuelle Umgebung in Ihrer Eingabeaufforderung wird entfernt.

      Erstellen von systemd-Socket- und Service-Dateien für Gunicorn

      Wir haben getestet, ob Gunicorn mit unserer Django-Anwendung interagieren kann. Wir sollten jedoch eine effektivere Methode zum Starten und Anhalten des Anwendungsservers implementieren. Dazu erstellen wir systemd-Service- und Socket-Dateien.

      Das Gunicorn-Socket wird beim Booten erstellt und nach Verbindungen lauschen. Wenn eine Verbindung hergestellt wird, startet systemd automatisch den Gunicorn-Prozess, um die Verbindung zu verwalten.

      Erstellen und öffnen Sie zunächst eine systemd-Socket-Datei für Gunicorn mit sudo-Berechtigungen:

      • sudo nano /etc/systemd/system/gunicorn.socket

      Darin erstellen wir einen Abschnitt [Unit], um das Socket zu beschreiben, einen Abschnitt [Socket], um den Ort des Sockets zu definieren, und einen Abschnitt [Install], um sicherzustellen, dass das Socket zum richtigen Zeitpunkt erstellt wird:

      /etc/systemd/system/gunicorn.socket

      [Unit]
      Description=gunicorn socket
      
      [Socket]
      ListenStream=/run/gunicorn.sock
      
      [Install]
      WantedBy=sockets.target
      

      Wenn Sie dies abgeschlossen haben, speichern und schließen Sie die Datei.

      Erstellen und öffnen Sie in Ihrem Texteditor als Nächstes eine systemd-Service-Datei für Gunicorn mit sudo-Berechtigungen. Der Name der Service-Datei sollte mit Ausnahme der Erweiterung mit dem Namen der Socket-Datei übereinstimmen:

      • sudo nano /etc/systemd/system/gunicorn.service

      Beginnen Sie mit dem Abschnitt [Unit], mit dem Metadaten und Abhängigkeiten angegeben werden. Wir werden hier eine Beschreibung unseres Diensts eingeben und das Init-System anweisen, ihn erst zu starten, nachdem das Netzwerkziel erreicht wurde. Da sich unser Dienst auf das Socket aus der Socket-Datei bezieht, müssen wir eine Requires-Direktive einschließen, um diese Beziehung anzugeben:

      /etc/systemd/system/gunicorn.service

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

      Als Nächstes werden wir den Abschnitt [Service] öffnen. Wir werden den Benutzer und die Gruppe angeben, unter denen wir den Prozess ausführen möchten. Wir wollen unserem regulären Benutzerkonto die Prozessverantwortung übergeben, da es alle relevanten Dateien besitzt. Wir werden der Gruppe www-data die Gruppenverantwortung übergeben, damit Nginx einfach mit Gunicorn kommunizieren kann.

      Dann werden wir das Arbeitsverzeichnis zuordnen und den Befehl zum Starten des Diensts angeben. In diesem Fall müssen wir den vollständigen Pfad zur ausführbaren Gunicorn-Datei angeben, die in unserer virtuellen Umgebung installiert ist. Wir werden den Prozess mit dem im Verzeichnis /run erstellten Unix-Socket verknüpfen, damit der Prozess mit Nginx kommunizieren kann. Wir protokollieren alle Daten in der Standardausgabe, damit der journald-Prozess die Gunicorn-Protokolle erfassen kann. Außerdem können wir hier optionale Gunicorn-Optimierungen angeben. Beispielsweise haben wir in diesem Fall drei Workerprozesse angegeben:

      /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 - 
                --workers 3 
                --bind unix:/run/gunicorn.sock 
                myproject.wsgi:application
      

      Schließlich werden wir einen Abschnitt [Install] hinzufügen. Dies teilt systemd mit, womit dieser Dienst verknüpft werden soll, wenn wir festlegen, dass er während des Startvorgangs starten soll. Wir wollen, dass dieser Dienst startet, wenn das normale Mehrbenutzersystem arbeitet.

      /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 - 
                --workers 3 
                --bind unix:/run/gunicorn.sock 
                myproject.wsgi:application
      
      [Install]
      WantedBy=multi-user.target
      

      Damit ist unsere systemd-Dienstdatei fertiggestellt. Speichern und schließen Sie diese jetzt.

      Wir können nun starten und das Gunicorn-Socket aktivieren. Dadurch wird die Socket-Datei nun unter /run/gunicorn.sock und beim Booten erstellt. Wenn eine Verbindung zu diesem Socket hergestellt wird, startet systemd automatisch den gunicorn.service, um die Verbindung zu verwalten:

      • sudo systemctl start gunicorn.socket
      • sudo systemctl enable gunicorn.socket

      Wir können uns vergewissern, dass der Vorgang erfolgreich war, indem wir nach der Socket-Datei suchen.

      Suchen nach der Gunicorn-Socket-Datei

      Überprüfen Sie den Status des Prozesses, um herauszufinden, ob er gestartet werden konnte:

      • sudo systemctl status gunicorn.socket

      Sie sollten eine Ausgabe wie diese erhalten:

      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

      Überprüfen Sie als Nächstes, ob die Datei gunicorn.sock im Verzeichnis /run vorhanden ist:

      Output

      /run/gunicorn.sock: socket

      Wenn der Befehl systemctl status angegeben hat, dass ein Fehler aufgetreten ist, oder Sie die Datei gunicorn.sock im Verzeichnis nicht finden können, ist dies ein Hinweis darauf, dass das Gunicorn-Socket nicht richtig erstellt wurde. Überprüfen Sie die Protokolle des Gunicorn-Sockets durch folgende Eingabe:

      • sudo journalctl -u gunicorn.socket

      Werfen Sie einen erneuten Blick auf Ihre Datei /etc/systemd/system/gunicorn.socket, um alle vorhandenen Probleme zu beheben, bevor Sie fortfahren.

      Testen der Socket-Aktivierung

      Wenn Sie derzeit nur die Einheit gunicorn.socket gestartet haben, wird der gunicorn.service aktuell noch nicht aktiv sein, da das Socket noch keine Verbindungen erhalten hat. Geben Sie zum Überprüfen Folgendes ein:

      • sudo systemctl status gunicorn

      Output

      ● gunicorn.service - gunicorn daemon Loaded: loaded (/etc/systemd/system/gunicorn.service; disabled; vendor preset: enabled) Active: inactive (dead)

      Zum Testen des Socket-Aktivierungsverfahrens können wir über curl eine Verbindung an das Socket senden, indem wir Folgendes eingeben:

      • curl --unix-socket /run/gunicorn.sock localhost

      Sie sollten die HTML-Ausgabe von Ihrer Anwendung im Terminal erhalten. Das bedeutet, dass Gunicorn gestartet wurde und Ihre Django-Anwendung bereitstellen konnte. Sie können überprüfen, ob der Gunicorn-Service ausgeführt wird, indem Sie Folgendes eingeben:

      • sudo systemctl status gunicorn

      Output

      ● gunicorn.service - gunicorn daemon Loaded: loaded (/etc/systemd/system/gunicorn.service; disabled; vendor preset: enabled) Active: active (running) since Fri 2020-06-26 18:52:21 UTC; 2s ago TriggeredBy: ● gunicorn.socket Main PID: 22914 (gunicorn) Tasks: 4 (limit: 1137) Memory: 89.1M CGroup: /system.slice/gunicorn.service ├─22914 /home/sammy/myprojectdir/myprojectenv/bin/python /home/sammy/myprojectdir/myprojectenv/bin/gunicorn --access-logfile - --workers 3 --bind unix:/run/gunico> ├─22927 /home/sammy/myprojectdir/myprojectenv/bin/python /home/sammy/myprojectdir/myprojectenv/bin/gunicorn --access-logfile - --workers 3 --bind unix:/run/gunico> ├─22928 /home/sammy/myprojectdir/myprojectenv/bin/python /home/sammy/myprojectdir/myprojectenv/bin/gunicorn --access-logfile - --workers 3 --bind unix:/run/gunico> └─22929 /home/sammy/myprojectdir/myprojectenv/bin/python /home/sammy/myprojectdir/myprojectenv/bin/gunicorn --access-logfile - --workers 3 --bind unix:/run/gunico> Jun 26 18:52:21 django-tutorial systemd[1]: Started gunicorn daemon. Jun 26 18:52:21 django-tutorial gunicorn[22914]: [2020-06-26 18:52:21 +0000] [22914] [INFO] Starting gunicorn 20.0.4 Jun 26 18:52:21 django-tutorial gunicorn[22914]: [2020-06-26 18:52:21 +0000] [22914] [INFO] Listening at: unix:/run/gunicorn.sock (22914) Jun 26 18:52:21 django-tutorial gunicorn[22914]: [2020-06-26 18:52:21 +0000] [22914] [INFO] Using worker: sync Jun 26 18:52:21 django-tutorial gunicorn[22927]: [2020-06-26 18:52:21 +0000] [22927] [INFO] Booting worker with pid: 22927 Jun 26 18:52:21 django-tutorial gunicorn[22928]: [2020-06-26 18:52:21 +0000] [22928] [INFO] Booting worker with pid: 22928 Jun 26 18:52:21 django-tutorial gunicorn[22929]: [2020-06-26 18:52:21 +0000] [22929] [INFO] Booting worker with pid: 22929

      Wenn die Ausgabe von curl oder die Ausgabe von systemctl status anzeigt, dass ein Problem aufgetreten ist, prüfen Sie die Protokolle auf weitere Details:

      • sudo journalctl -u gunicorn

      Überprüfen Sie Ihre Datei /etc/systemd/system/gunicorn.service auf Probleme. Wenn Sie Änderungen an der Datei /etc/systemd/system/gunicorn.service vornehmen, laden Sie das Daemon neu, um die Dienstdefinition neu zu lesen, und starten Sie den Gunicorn-Prozess neu, indem Sie Folgendes eingeben:

      • sudo systemctl daemon-reload
      • sudo systemctl restart gunicorn

      Sorgen Sie dafür, dass die oben genannten Probleme behoben werden, bevor Sie fortfahren.

      Konfigurieren von Nginx zur Proxy-Übergabe an Gunicorn

      Nachdem Gunicorn eingerichtet ist, müssen wir nun Nginx so konfigurieren, dass Datenverkehr an den Prozess übergeben wird.

      Erstellen und öffnen Sie zunächst einen neuen Serverblock im Verzeichnis sites-available von Nginx:

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

      Öffnen Sie darin einen neuen Serverblock. Wir geben zunächst an, dass dieser Block am normalen Port 80 lauschen und auf den Domänennamen oder die IP-Adresse unseres Servers reagieren soll:

      /etc/nginx/sites-available/myproject

      server {
          listen 80;
          server_name server_domain_or_IP;
      }
      

      Als Nächstes weisen wir Nginx an, alle Probleme bei der Suche nach einem Favicon zu ignorieren. Außerdem teilen wir Nginx mit, wo die statischen Assets zu finden sind, die wir in unserem Verzeichnis ~/myprojectdir/static gesammelt haben. Alle diese Dateien verfügen über das Standard-URI-Präfix “/static”; daher können wir einen Ortsblock erstellen, um diese Anfragen abzugleichen:

      /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;
          }
      }
      

      Schließlich erstellen wir einen location / {}-Block zum Abgleichen aller anderen Anforderungen. In diesen Block werden wir die standardmäßige Datei proxy_params einschließen, die in der Nginx-Installation enthalten ist, und dann den Datenverkehr direkt an das Gunicorn-Socket übergeben.

      /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;
          }
      }
      

      Wenn Sie dies abgeschlossen haben, speichern und schließen Sie die Datei. Jetzt können wir die Datei aktivieren, indem wir sie mit dem Verzeichnis sites-enabled verknüpfen:

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

      Prüfen Sie Ihre Nginx-Konfiguration durch folgende Eingabe auf Syntaxfehler:

      Wenn keine Fehler gemeldet werden, fahren Sie fort und starten Sie Nginx neu, indem Sie Folgendes eingeben:

      • sudo systemctl restart nginx

      Schließlich müssen wir unsere Firewall an Port 80 für normalen Datenverkehr öffnen. Da wir keinen Zugriff mehr auf den Entwicklungsserver benötigen, können wir außerdem die Regel zum Öffnen von Port 8000 entfernen:

      • sudo ufw delete allow 8000
      • sudo ufw allow 'Nginx Full'

      Sie sollten nun in der Lage sein, die Domäne oder IP-Adresse Ihres Servers aufzurufen, um Ihre Anwendung anzuzeigen.

      Anmerkung: Nach der Konfiguration von Nginx sollte der nächste Schritt aus dem Sichern des Datenverkehrs zum Server mit SSL/TLS bestehen. Das ist äußerst wichtig, da ohne SSL/TLS alle Informationen, einschließlich Passwörter, in Klartext über das Netzwerk gesendet werden.

      Wenn Sie einen Domänennamen haben, ist Let’s Encrypt der einfachste Weg, um sich ein SSL-Zertifikat zum Sichern Ihres Datenverkehrs zu verschaffen. Folgen Sie diesem Leitfaden zum Einrichten von Let’s Encrypt mit Nginx unter Ubuntu 20.04. Befolgen Sie das Verfahren mit dem Nginx-Serverblock, den wir in diesem Leitfaden erstellt haben.

      Fehlerbehebung bei Nginx und Gunicorn

      Wenn Ihre Anwendung in diesem letzten Schritt nicht angezeigt wird, müssen Sie Probleme mit Ihrer Installation beheben.

      Nginx zeigt anstelle der Django-Anwendung die Standardseite an

      Wenn Nginx die Standardseite und nicht einen Proxy zu Ihrer Anwendung anzeigt, bedeutet das in der Regel, dass Sie den server_name in der Datei /etc/nginx/sites-available/myproject so ändern müssen, dass er auf die IP-Adresse oder den Domänennamen Ihres Servers verweist.

      Nginx verwendet den server_name, um zu bestimmen, welcher Serverblock für Antworten auf Anfragen verwendet werden soll. Wenn Sie die Nginx-Standardseite erhalten, ist das ein Zeichen dafür, dass Nginx die Anfrage nicht explizit mit einem Serverblock abgleichen konnte. Darum greift Nginx auf den Standardblock zurück, der in /etc/nginx/sites-available/default definiert ist.

      Der server_name im Serverblock Ihres Projekts muss spezifischer sein als der im auszuwählenden standardmäßigen Serverblock.

      Nginx zeigt anstelle der Django-Anwendung einen 502-Fehler (Ungültiges Gateway) an

      Ein 502-Fehler zeigt, dass Nginx die Anfrage per Proxy nicht erfolgreich vermitteln kann. Eine Vielzahl von Konfigurationsproblemen äußern sich in einem 502-Fehler; für eine angemessene Fehlerbehebung sind also weitere Informationen erforderlich.

      Der primäre Ort zur Suche nach weiteren Informationen sind die Fehlerprotokolle von Nginx. Generell werden sie Ihnen mitteilen, welche Bedingungen während des Proxying-Ereignisses Probleme verursacht haben. Folgen Sie den Nginx-Fehlerprotokollen, indem Sie Folgendes eingeben:

      • sudo tail -F /var/log/nginx/error.log

      Erstellen Sie nun in Ihrem Browser eine weitere Anfrage zur Generierung eines neuen Fehlers (versuchen Sie, die Seite zu aktualisieren). Sie sollten eine neue Fehlermeldung erhalten, die in das Protokoll geschrieben wird. Wenn Sie sich die Nachricht ansehen, sollten Sie das Problem eingrenzen können.

      Sie erhalten möglicherweise die folgende Meldung:

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

      Das bedeutet, dass Nginx die Datei gunicorn.sock am angegebenen Ort nicht finden konnte. Sie sollten den proxy_pass-Ort, der in der Datei /etc/nginx/sites-available/myproject definiert ist, mit dem tatsächlichen Ort der Datei gunicorn.sock vergleichen, die von der Datei gunicorn.socket generiert wurde.

      Wenn Sie keine gunicorn.sock-Datei im Verzeichnis /run finden können, bedeutet das im Allgemeinen, dass die systemd-Socket-Datei sie nicht erstellen konnte. Kehren Sie zurück zum Abschnitt zum Suchen nach der Gunicorn-Socket-Datei, um die Schritte zur Fehlerbehebung für Gunicorn zu durchlaufen.

      connect() to unix:/run/gunicorn.sock failed (13: Permission denied)

      Das bedeutet, dass Nginx aufgrund von Berechtigungsproblemen keine Verbindung zum Gunicorn-Socket herstellen konnte. Dies kann geschehen, wenn das Verfahren mit dem root user anstelle eines sudo-Benutzers ausgeführt wird. Zwar kann systemd die Gunicorn-Socket-Datei erstellen, doch kann Nginx nicht darauf zugreifen.

      Dies kann geschehen, wenn es an einem beliebigen Punkt zwischen dem root-Verzeichnis (/) der Datei gunicorn.sock begrenzte Berechtigungen gibt. Wir können die Berechtigungen und Verantwortungswerte der Socket-Datei und jedes der übergeordneten Verzeichnisse überprüfen, indem wir den absoluten Pfad zu unserer Socket-Datei dem Befehl namei übergeben:

      • namei -l /run/gunicorn.sock

      Output

      f: /run/gunicorn.sock drwxr-xr-x root root / drwxr-xr-x root root run srw-rw-rw- root root gunicorn.sock

      Die Ausgabe zeigt die Berechtigungen der einzelnen Verzeichniskomponenten an. Indem wir uns die Berechtigungen (erste Spalte), den Besitzer (zweite Spalte) und den Gruppenbesitzer (dritte Spalte) ansehen, können wir ermitteln, welche Art des Zugriffs auf die Socket-Datei erlaubt ist.

      Im obigen Beispiel haben die Socket-Datei und die einzelnen Verzeichnisse, die zur Socket-Datei führen, globale Lese- und Ausführungsberechtigungen (die Berechtigungsspalte für die Verzeichnisse endet mit r-x anstelle von ---). Der Nginx-Prozess sollte erfolgreich auf das Socket zugreifen können.

      Wenn eines der Verzeichnisse, das zum Socket führt, keine globale Lese- und Ausführungsberechtigung aufweist, kann Nginx nicht auf das Socket zugreifen, ohne globale Lese- und Ausführungsberechtigungen zuzulassen oder sicherzustellen, dass die Gruppenverantwortung einer Gruppe erteilt wird, zu der Nginx gehört.

      Django zeigt an: “could not connect to server: Connection refused”

      Eine Meldung, die Sie bei dem Versuch, im Webbrowser auf Teile der Anwendung zuzugreifen, von Django erhalten können, lautet:

      OperationalError at /admin/login/
      could not connect to server: Connection refused
          Is the server running on host "localhost" (127.0.0.1) and accepting
          TCP/IP connections on port 5432?
      

      Das bedeutet, dass Django keine Verbindung zur Postgres-Datenbank herstellen kann. Vergewissern Sie sich durch folgende Eingabe, dass die Postgres-Instanz ausgeführt wird:

      • sudo systemctl status postgresql

      Wenn nicht, können Sie sie starten und so aktivieren, dass sie beim Booten automatisch gestartet wird (wenn sie nicht bereits entsprechend konfiguriert ist); geben Sie dazu Folgendes ein:

      • sudo systemctl start postgresql
      • sudo systemctl enable postgresql

      Wenn Sie weiter Probleme haben, stellen Sie sicher, dass die in der Datei ~/myprojectdir/myproject/settings.py definierten Datenbankeinstellungen korrekt sind.

      Weitere Fehlerbehebung

      Bei der weiteren Fehlerbehebung können die Protokolle dazu beitragen, mögliche Ursachen einzugrenzen. Prüfen Sie sie nacheinander und suchen Sie nach Meldungen, die auf Problembereiche hinweisen.

      Folgende Protokolle können hilfreich sein:

      • Prüfen Sie die Nginx-Prozessprotokolle, indem Sie Folgendes eingeben: sudo journalctl -u nginx
      • Prüfen Sie die Nginx-Zugangsprotokolle, indem Sie Folgendes eingeben: sudo less /var/log/nginx/access.log
      • Prüfen Sie die Nginx-Fehlerprotokolle, indem Sie Folgendes eingeben: sudo less /var/log/nginx/error.log
      • Prüfen Sie die Gunicorn-Anwendungsprotokolle, indem Sie Folgendes eingeben: sudo journalctl -u gunicorn
      • Prüfen Sie die Gunicorn-Socket-Protokolle, indem Sie Folgendes eingeben: sudo journalctl -u gunicorn.socket

      Wenn Sie Ihre Konfiguration oder Anwendung aktualisieren, müssen Sie die Prozesse wahrscheinlich neu starten, damit Ihre Änderungen aktiv werden.

      Wenn Sie Ihre Django-Anwendung aktualisieren, können Sie den Gunicorn-Prozess durch folgende Eingabe neu starten, um die Änderungen zu erfassen:

      • sudo systemctl restart gunicorn

      Wenn Sie Gunicorn-Socket- oder Service-Dateien ändern, laden Sie das Daemon neu und starten Sie den Prozess neu, indem Sie Folgendes eingeben:

      • sudo systemctl daemon-reload
      • sudo systemctl restart gunicorn.socket gunicorn.service

      Wenn Sie die Konfiguration des Nginx-Serverblocks ändern, testen Sie die Konfiguration und dann Nginx, indem Sie Folgendes eingeben:

      • sudo nginx -t && sudo systemctl restart nginx

      Diese Befehle sind hilfreich, um Änderungen zu erfassen, während Sie Ihre Konfiguration anpassen.

      Zusammenfassung

      In diesem Leitfaden haben wir ein Django-Projekt in seiner eigenen virtuellen Umgebung eingerichtet. Wir haben Gunicorn so konfiguriert, dass Clientanfragen übersetzt werden, damit Django sie verwalten kann. Anschließend haben wir Nginx als Reverseproxy eingerichtet, um Clientverbindungen zu verwalten und je nach Clientanfrage das richtige Projekt bereitzustellen.

      Django macht die Erstellung von Projekten und Anwendungen durch Bereitstellung vieler der gängigen Elemente besonders einfach; so können Sie sich ganz auf die individuellen Elemente konzentrieren. Durch Nutzung der in diesem Artikel beschriebenen allgemeinen Tool Chain können Sie die erstellten Anwendungen bequem über einen einzelnen Server bereitstellen.



      Source link

      Cómo configurar Django con Postgres, Nginx y Gunicorn en Ubuntu 20.04


      Introducción

      Django es un poderoso framework que puede ayudarle a poner en marcha su aplicación o sitio web con Python. Incluye un servidor de desarrollo simplificado para probar su código a nivel local. Sin embargo, para cualquier cosa que esté incluso apenas relacionada con la producción se requiere un servidor web más seguro y potente.

      En esta guía, demostraremos la forma de instalar y configurar algunos componentes en Ubuntu 20.04 para que sean compatibles con aplicaciones de Django y permitan su funcionamiento. Configuraremos una base de datos de PostgreSQL en lugar de usar la base de datos predeterminada de SQLite. Configuraremos el servidor de aplicaciones de Gunicorn para que interactúe con nuestras aplicaciones. Luego, configuraremos Nginx para que invierta el proxy de Gunicorn, lo que nos dará acceso a sus funciones de seguridad y rendimiento para nuestras aplicaciones.

      Requisitos previos y objetivos

      Para completar esta guía, debe disponer de una instancia de servidor de Ubuntu 20.04 nueva con un firewall básico y un usuario no root con privilegios sudo configurados. Puede aprender a configurarlo con nuestra guía de configuración inicial para servidores.

      Instalaremos Django en un entorno virtual. Instalar Django en un entorno específico para nuestro proyecto permitirá que sus proyectos y los requisitos de estos se administren por separado.

      Una vez que tengamos nuestra base de datos y la aplicación en funcionamiento, instalaremos y configuraremos el servidor de aplicaciones de Gunicorn. Esto servirá como interfaz para nuestra aplicación, al traducir las solicitudes de los clientes de HTTP a llamadas Python que nuestra aplicación puede procesar. Luego, instalaremos Nginx frente a Gunicorn para aprovechar sus mecanismos de administración de conexiones de alto rendimiento y sus características de seguridad fáciles de implementar.

      Comencemos.

      Instalar los paquetes desde los repositorios de Ubuntu

      Para iniciar este proceso, descargaremos e instalaremos todos los elementos necesarios desde los repositorios de Ubuntu. Usaremos el administrador de paquetes de Python pip para instalar componentes adicionales más tarde.

      Tendremos que actualizar el índice de paquetes apt local y, luego, descargar e instalar los paquetes. Los paquetes que instalemos dependen de la versión de Python que use en su proyecto.

      Si usa Django con Python 3, escriba lo siguiente:

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

      Django 1.11 es la última versión que será compatible con Python 2. Si va a iniciar proyectos nuevos, le recomendamos enfáticamente seleccionar Python 3. Si necesita seguir usando Python 2, escriba lo siguiente:

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

      Con esto, se instalarán pip, los archivos de desarrollo de Python necesarios para compilar Gunicorn posteriormente, el sistema de base de datos de Postgres junto con las bibliotecas necesarias para interactuar con él y el servidor web Nginx.

      Crear la base de datos y el usuario de PostgreSQL

      Crearemos una base de datos y un usuario de base de datos para nuestra aplicación de Django.

      Por defecto, Postgres usa un esquema de autenticación llamado “autenticación por pares” para las conexiones locales. Básicamente, esto significa que si el nombre de usuario del sistema operativo del usuario coincide con un nombre de usuario de Postgres válido, ese usuario puede iniciar sesión sin autenticaciones adicionales.

      Durante la instalación de Postgres, se creó un usuario del sistema operativo llamado postgres para que se corresponda con el usuario administrativo postgres de PostgreSQL. Necesitamos usar este usuario para realizar tareas administrativas. Podemos usar sudo y pasar el nombre de usuario con la opción -u.

      Inicie una sesión interactiva de Postgres escribiendo lo siguiente:

      Recibirá un mensaje de PostgreSQL en el que se pueden configurar los requisitos.

      Primero, cree una base de datos para su proyecto:

      • CREATE DATABASE myproject;

      Nota: Cada instrucción de Postgres debe terminar con punto y coma. Por eso, si presenta problemas, debe asegurarse de que su comando tenga esta terminación.

      A continuación, cree un usuario de base de datos para nuestro proyecto. Asegúrese de elegir una contraseña segura.

      • CREATE USER myprojectuser WITH PASSWORD 'password';

      Más adelante, modificaremos algunos de los parámetros de conexión para el usuario que acabamos de crear. Esto acelerará las operaciones de la base de datos para que no sea necesario consultar y fijar los valores correctos cada vez que se establezca una conexión.

      Fijaremos el código predeterminado en UTF-8, que es lo que Django espera. También fijaremos el esquema predeterminado de aislamiento de transacciones en “read committed”, que bloquea las lecturas de transacciones no comprometidas. Por último, configuraremos la zona horaria. Por defecto, nuestros proyectos de Django se configurarán para usar la opción UTC. Estas son todas las recomendaciones del propio proyecto de Django:

      • 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';

      Ahora, podemos brindar a nuestro nuevo usuario acceso para administrar nuestra nueva base de datos:

      • GRANT ALL PRIVILEGES ON DATABASE myproject TO myprojectuser;

      Cuando termine, cierre la línea de comandos de PostgreSQL escribiendo lo siguiente:

      Postgres quedará, así, configurado para que Django pueda conectarse y administrar la información de su base de datos.

      Crear un entorno virtual de Python para su proyecto

      Ahora que tenemos nuestra base de datos, podemos empezar a cumplir con el resto de los requisitos de nuestro proyecto. Instalaremos los componentes de Python requeridos en un entorno virtual para facilitar la administración.

      Para hacerlo, primero necesitamos acceso al comando virtualenv. Podemos instalarlo con pip.

      Si usa Python 3, actualice pip e instale el paquete escribiendo lo siguiente:

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

      Si usa Python 2, actualice pip e instale el paquete escribiendo lo siguiente:

      • sudo -H pip install --upgrade pip
      • sudo -H pip install virtualenv

      Con virtualenv instalado, podemos comenzar a dar forma a nuestro proyecto. Cree y un directorio en el que podamos guardar los archivos de nuestro proyecto y posiciónese en él:

      • mkdir ~/myprojectdir
      • cd ~/myprojectdir

      En el directorio del proyecto, cree un entorno virtual de Python escribiendo lo siguiente:

      Con esto, se creará un directorio llamado myprojectenv en su directorio myprojectdir. Dentro de este, se instalarán una versión local de Python y una versión local de pip. Podemos usar esto para instalar y configurar un entorno aislado de Python para nuestro proyecto.

      Antes de instalar los componentes de Python requeridos para nuestro proyecto, debemos activar el entorno virtual. Puede hacerlo escribiendo lo siguiente:

      • source myprojectenv/bin/activate

      Su línea de comandos cambiará para indicar que ahora realiza operaciones en un entorno virtual de Python. Tendrá este aspecto: (myprojectenv)user@host:~/myprojectdir$.

      Con su entorno virtual activo, instale Django, Gunicorn y el adaptador psycopg2 de PostgreSQL con la instancia local de pip:

      Nota: Cuando se active el entorno virtual (cuando (myprojectenv) se encuentre al inicio de su línea de comandos), use pip en lugar de pip3, incluso si emplea Python 3. La copia del entorno virtual de la herramienta siempre se llama pip, independientemente de la versión de Python.

      • pip install django gunicorn psycopg2-binary

      Con esto, debería contar con todo el software necesario para iniciar un proyecto en Django.

      Crear y configurar un nuevo proyecto de Django

      Una vez instalados nuestros componentes de Python, podemos crear los archivos reales del proyecto en Django.

      Crear el proyecto de Django

      Debido a que ya disponemos de un directorio de proyectos, le indicaremos a Django que instale los archivos en él. Se creará un directorio de segundo nivel con el código real, lo cual es normal, y se dispondrá una secuencia de comandos de administración en este directorio. La clave para esto es que definiremos el directorio de forma explícita en lugar de permitir que Django tome decisiones vinculadas con nuestro directorio actual:

      • django-admin.py startproject myproject ~/myprojectdir

      En este punto, el directorio de su proyecto (~/myprojectdir en nuestro caso) debe tener el siguiente contenido:

      • ~/myprojectdir/manage.py: una secuencia de comandos de administración del proyecto de Django.
      • ~/myprojectdir/myproject/: el paquete de proyectos de Django. Este debe contener los archivos __init__.py, settings.py, urls.py, asgi.py y wsgi.py.
      • ~/myprojectdir/myprojectenv/: el directorio del entorno virtual que creamos anteriormente.

      Ajustar la configuración del proyecto

      Lo primero que debemos hacer con los archivos del proyecto recientemente creado es ajustar la configuración. Abra el archivo de configuración en su editor de texto:

      • nano ~/myprojectdir/myproject/settings.py

      Comience por localizar la directiva ALLOWED_HOSTS. Con esto, se define una lista de las direcciones de los servidores o los nombres de dominio que pueden usarse para establecer una conexión con la instancia en Django. Cualquier solicitud entrante con un encabezado de Host que no figure en esta lista generará una excepción. Django necesita que configure esto para evitar una clase de vulnerabilidad de seguridad determinada.

      En los corchetes, enumere las direcciones IP o los nombres de dominio que están asociados con su servidor Django. Cada elemento debe listarse entre comillas y las entradas deben ir separadas por una coma. Si desea solicitudes para un dominio completo y cualquier subdominio, anteponga un punto al comienzo de la entrada. En el fragmento inferior, hay algunos ejemplos comentados que se usan para demostrar lo siguiente:

      Nota: Asegúrese de incluir localhost como una de las opciones, ya que autorizaremos conexiones a través de una instancia local de Nginx.

      ~/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']
      

      A continuación, busque la sección que configura el acceso a la base de datos. Se iniciará con DATABASES. La configuración del archivo es para una base de datos de SQLite. Ya creamos una base de datos de PostgreSQL para nuestro proyecto. Ahora debemos ajustar las configuraciones.

      Cambie las configuraciones por la información de su base de datos de PostgreSQL. Indicaremos a Django que use el adaptador psycopg2 que instalamos con pip. Debemos proporcionar el nombre de la base de datos, el nombre de usuario y la contraseña del usuario, y luego especificar que la base de datos se encuentra en una computadora local. Puede dejar la configuración de PORT como una secuencia de comandos vacía:

      ~/myprojectdir/myproject/settings.py

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

      A continuación, diríjase hasta la parte inferior del archivo y agregue una configuración que indique dónde deben disponerse los archivos estáticos. Esto es necesario para que Nginx pueda manejar las solicitudes de estos elementos. La siguiente línea indica a Django que los disponga en un directorio llamado static en el directorio de proyectos de base:

      ~/myprojectdir/myproject/settings.py

      . . .
      
      STATIC_URL = '/static/'
      STATIC_ROOT = os.path.join(BASE_DIR, 'static/')
      

      Guarde y cierre el archivo cuando termine.

      Completar la configuración inicial del proyecto

      Ahora, podemos migrar el esquema inicial de la base de datos a nuestra base de datos de PostgreSQL usando la secuencia de comandos de administración:

      • ~/myprojectdir/manage.py makemigrations
      • ~/myprojectdir/manage.py migrate

      Cree un usuario administrativo para el proyecto escribiendo lo siguiente:

      • ~/myprojectdir/manage.py createsuperuser

      Deberá seleccionar el nombre de usuario, proporcionar una dirección de correo electrónico y elegir y confirmar una contraseña.

      Podemos recolectar todo el contenido estático en la ubicación del directorio que configuramos escribiendo lo siguiente:

      • ~/myprojectdir/manage.py collectstatic

      Deberá confirmar la operación. Luego, los archivos estáticos se ubicarán en un directorio llamado static, dentro del directorio de su proyecto.

      Si siguió la guía de configuración inicial para servidores, debería proteger su servidor con un firewall UFW. Para probar el servidor de desarrollo, tendremos que permitir el acceso al puerto que usaremos.

      Cree una excepción para el puerto 8000 escribiendo lo siguiente:

      Por último, puede probar su proyecto iniciando el servidor de desarrollo de Django con este comando:

      • ~/myprojectdir/manage.py runserver 0.0.0.0:8000

      En su buscador web, agregue :8000 al final del nombre del dominio o de la dirección IP de su servidor y visítelos:

      http://server_domain_or_IP:8000
      

      Debe obtener como resultado la página de índice predeterminada de Django:

      Página de índice de Django

      Si agrega /admin al final de la URL en la barra de direcciones, se le solicitará el nombre de usuario administrativo y la contraseña que creó con el comando createsuperuser:

      Inicio de sesión de administrador en Django

      Después de la autenticación, puede acceder a la interfaz administrativa predeterminada de Django:

      Interfaz de administración de Django

      Cuando finalice la exploración, presione CTRL-C en la ventana de la terminal para desactivar el servidor de desarrollo.

      Poner a prueba la capacidad de Gunicorn para presentar el proyecto

      Lo último que nos convendrá hacer antes de cerrar nuestro entorno virtual será probar Gunicorn para asegurarnos de que pueda hacer funcionar la aplicación. Podemos hacerlo ingresando a nuestro directorio de proyectos y usando gunicorn para cargar el módulo WSGI del proyecto:

      • cd ~/myprojectdir
      • gunicorn --bind 0.0.0.0:8000 myproject.wsgi

      Con esto se iniciará Gunicorn en la misma interfaz en la que se encontraba en ejecución el servidor de desarrollo en Django. Puede volver y probar la aplicación de nuevo.

      Nota: No se aplicará ninguno de los estilos a la interfaz de administrador, ya que Gunicorn no sabe cómo encontrar el contenido estático de CSS responsable de esto.

      Pasamos un módulo a Gunicorn especificando la ruta relativa del directorio al archivo wsgi.py de Django, que es el punto de entrada a nuestra aplicación, usando la sintaxis del módulo de Python. Dentro de este archivo, se define una función llamada application, que se usa para establecer conexión con la aplicación. Para obtener más información sobre la especificación WSGI, haga clic aquí.

      Cuando termine de realizar las pruebas, presione CTRL-C en la ventana de la terminal para detener Gunicorn.

      Con esto habremos terminado de configurar nuestra aplicación en Django. Podemos cerrar nuestro entorno virtual escribiendo lo siguiente:

      Se eliminará el indicador del entorno virtual en su línea de comandos.

      Crear archivos de socket y servicio de systemd para Gunicorn

      Comprobamos que Gunicorn puede interactuar con nuestra aplicación en Django, pero debemos implementar un mejor método para iniciar y detener el servidor de la aplicación. Para lograr esto, crearemos archivos de servicio y socket systemd.

      El socket Gunicorn se creará en el inicio y escuchará las conexiones. Cuando se establezca una conexión, systemd iniciará de forma automática el proceso de Gunicorn para manejarla conexión.

      Comience por crear y abrir un archivo de socket de systemd para Gunicorn con privilegios sudo:

      • sudo nano /etc/systemd/system/gunicorn.socket

      En su interior, crearemos una sección [Unit] para describir el socket, una sección [Socket] para definir la ubicación del socket y una sección [Install] para asegurarnos de que el socket se cree en el momento adecuado:

      /etc/systemd/system/gunicorn.socket

      [Unit]
      Description=gunicorn socket
      
      [Socket]
      ListenStream=/run/gunicorn.sock
      
      [Install]
      WantedBy=sockets.target
      

      Guarde y cierre el archivo cuando termine.

      A continuación, cree y abra un archivo de servicio systemd para Gunicorn con privilegios sudo en su editor de texto. El nombre del archivo de servicio debe coincidir con el de socket, salvo en la extensión:

      • sudo nano /etc/systemd/system/gunicorn.service

      Empiece por la sección [Unit], que se usa para especificar metadatos y dependencias. Aquí introduciremos una descripción de nuestro servicio e indicaremos al sistema init que lo inicie solo tras haber alcanzado el objetivo de red: Debido a que nuestro servicio se basa en el socket del archivo de sockets, necesitamos incluir una directiva Requires para indicar esta relación:

      /etc/systemd/system/gunicorn.service

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

      A continuación, abriremos la sección [Service]. Especificaremos el usuario y el grupo con los cuales deseamos que se ejecute el proceso. Otorgaremos la propiedad del proceso a nuestra cuenta de usuario normal, ya que tiene la propiedad de todos los archivos pertinentes. Otorgaremos la propiedad del grupo al grupo www-data para que Nginx pueda comunicarse fácilmente con Gunicorn.

      Luego, mapearemos el directorio de trabajo y especificaremos el comando que se usará para iniciar el servicio. En este caso, tendremos que especificar la ruta completa al ejecutable de Gunicorn, que está instalado en nuestro entorno virtual. Vincularemos el proceso con el socket de Unix que creamos en el directorio /run para que el proceso pueda comunicarse con Nginx. Registramos todos los datos a la salida estándar para que el proceso journald pueda recopilar los registros de Gunicorn. También podemos especificar cualquier ajuste opcional de Gunicorn aquí. Por ejemplo, especificamos 3 procesos de trabajadores en este caso:

      /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 - 
                --workers 3 
                --bind unix:/run/gunicorn.sock 
                myproject.wsgi:application
      

      Por último, agregaremos una sección [Install]. Esto indicará a systemd a qué deberá vincular este servicio si lo habilitamos para que se cargue en el inicio. Queremos que este servicio se inicie cuando el sistema multiusuario normal esté en funcionamiento:

      /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 - 
                --workers 3 
                --bind unix:/run/gunicorn.sock 
                myproject.wsgi:application
      
      [Install]
      WantedBy=multi-user.target
      

      Con eso, nuestro archivo de servicio systemd quedará completo. Guárdelo y ciérrelo ahora.

      Ahora podemos iniciar y habilitar el socket de Gunicorn. Con esto, ahora, se creará el archivo de socket en /run/gunicorn.sock y en el inicio. Cuando se establezca una conexión con ese socket, systemd iniciará gunicorn.service de forma automática para gestionarla:

      • sudo systemctl start gunicorn.socket
      • sudo systemctl enable gunicorn.socket

      Podemos confirmar que la operación se haya completado con éxito revisando el archivo de sockets.

      Verificar el archivo de socket de Gunicorn

      Compruebe el estado del proceso para saber si pudo iniciar lo siguiente:

      • sudo systemctl status gunicorn.socket

      Debería obtener un resultado como este:

      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

      A continuación, compruebe la existencia del archivo gunicorn.sock en el directorio /run:

      Output

      /run/gunicorn.sock: socket

      Si el comando systemctl status indica que se produjo un error o si no encuentra el archivo gunicorn.sock en el directorio, significa que no se pudo crear de forma correcta el socket de Gunicorn. Verifique los registros del socket de Gunicorn escribiendo lo siguiente:

      • sudo journalctl -u gunicorn.socket

      Vuelva a revisar su archivo /etc/systemd/system/gunicorn.socket para solucionar cualquier problema antes de continuar.

      Poner a prueba la activación de sockets

      En este punto, si solo inició la unidad gunicorn.socket, gunicorn.service aún no estará activo, ya que el socket aún no habrá recibido conexiones. Puede comprobarlo escribiendo lo siguiente:

      • sudo systemctl status gunicorn

      Output

      ● gunicorn.service - gunicorn daemon Loaded: loaded (/etc/systemd/system/gunicorn.service; disabled; vendor preset: enabled) Active: inactive (dead)

      Para probar el mecanismo de activación de sockets, podemos enviar una conexión al socket a través de curl escribiendo lo siguiente:

      • curl --unix-socket /run/gunicorn.sock localhost

      Debería recibir el resultado HTML de su aplicación en la terminal. Esto indica que Gunicorn se inició y pudo presentar su aplicación de Django. Puede verificar que el servicio de Gunicorn funcione escribiendo lo siguiente:

      • sudo systemctl status gunicorn

      Output

      ● gunicorn.service - gunicorn daemon Loaded: loaded (/etc/systemd/system/gunicorn.service; disabled; vendor preset: enabled) Active: active (running) since Fri 2020-06-26 18:52:21 UTC; 2s ago TriggeredBy: ● gunicorn.socket Main PID: 22914 (gunicorn) Tasks: 4 (limit: 1137) Memory: 89.1M CGroup: /system.slice/gunicorn.service ├─22914 /home/sammy/myprojectdir/myprojectenv/bin/python /home/sammy/myprojectdir/myprojectenv/bin/gunicorn --access-logfile - --workers 3 --bind unix:/run/gunico> ├─22927 /home/sammy/myprojectdir/myprojectenv/bin/python /home/sammy/myprojectdir/myprojectenv/bin/gunicorn --access-logfile - --workers 3 --bind unix:/run/gunico> ├─22928 /home/sammy/myprojectdir/myprojectenv/bin/python /home/sammy/myprojectdir/myprojectenv/bin/gunicorn --access-logfile - --workers 3 --bind unix:/run/gunico> └─22929 /home/sammy/myprojectdir/myprojectenv/bin/python /home/sammy/myprojectdir/myprojectenv/bin/gunicorn --access-logfile - --workers 3 --bind unix:/run/gunico> Jun 26 18:52:21 django-tutorial systemd[1]: Started gunicorn daemon. Jun 26 18:52:21 django-tutorial gunicorn[22914]: [2020-06-26 18:52:21 +0000] [22914] [INFO] Starting gunicorn 20.0.4 Jun 26 18:52:21 django-tutorial gunicorn[22914]: [2020-06-26 18:52:21 +0000] [22914] [INFO] Listening at: unix:/run/gunicorn.sock (22914) Jun 26 18:52:21 django-tutorial gunicorn[22914]: [2020-06-26 18:52:21 +0000] [22914] [INFO] Using worker: sync Jun 26 18:52:21 django-tutorial gunicorn[22927]: [2020-06-26 18:52:21 +0000] [22927] [INFO] Booting worker with pid: 22927 Jun 26 18:52:21 django-tutorial gunicorn[22928]: [2020-06-26 18:52:21 +0000] [22928] [INFO] Booting worker with pid: 22928 Jun 26 18:52:21 django-tutorial gunicorn[22929]: [2020-06-26 18:52:21 +0000] [22929] [INFO] Booting worker with pid: 22929

      Si el resultado de curl o systemctl status indica que se produjo un problema, verifique los registros para obtener información adicional:

      • sudo journalctl -u gunicorn

      Verifique su archivo /etc/systemd/system/gunicorn.service en busca de problemas. Si realiza cambios en el archivo /etc/systemd/system/gunicorn.service, vuelva a cargar el demonio para volver a leer la definición de servicio y reiniciar el proceso de Gunicorn escribiendo lo siguiente:

      • sudo systemctl daemon-reload
      • sudo systemctl restart gunicorn

      Asegúrese de resolver los problemas mencionados previamente antes de continuar.

      Configurar Nginx para un pase de autorización a Gunicorn

      Ahora que Gunicorn está configurado, debemos configurar Nginx para transferir tráfico al proceso.

      Comience por crear y abrir un nuevo bloque de servidor en el directorio sites-available de Nginx:

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

      Dentro de este, abra un nuevo bloque de servidor. Comenzaremos especificando que este bloque debe escuchar en el puerto normal 80 y responder al nombre de dominio o a la dirección IP de nuestro servidor:

      /etc/nginx/sites-available/myproject

      server {
          listen 80;
          server_name server_domain_or_IP;
      }
      

      A continuación, indicaremos a Nginx que ignore cualquier problema para encontrar un favicon. También le indicaremos dónde encontrar los activos estáticos que recolectamos en nuestro directorio ~/myprojectdir/static. Todos estos archivos tienen un prefijo URI de “/static”, para que podamos crear un bloque de ubicación que coincida con estas solicitudes:

      /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;
          }
      }
      

      Por último, crearemos un bloque location / {} para que coincida con todas las demás solicitudes. Dentro de esta ubicación, agregaremos el archivo proxy_params estándar incluido con la instalación de Nginx y, luego, transferiremos el tráfico directamente al socket de Gunicorn:

      /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;
          }
      }
      

      Guarde y cierre el archivo cuando termine. Ahora, podemos habilitar el archivo vinculándolo al directorio sites-enabled:

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

      Pruebe su configuración de Nginx para descartar errores de sintaxis escribiendo lo siguiente:

      Si no se notifican errores, reinicie Nginx escribiendo lo siguiente:

      • sudo systemctl restart nginx

      Por último, debemos abrir nuestro firewall al tráfico normal en el puerto 80. Como ya no necesitamos acceso al servidor de desarrollo, podemos eliminar la regla para abrir también el puerto 8000:

      • sudo ufw delete allow 8000
      • sudo ufw allow 'Nginx Full'

      Ahora debería poder acceder al dominio o a la dirección IP de su servidor para ver su aplicación.

      Nota: Después de configurar Nginx, el siguiente paso debería ser proteger el tráfico hacia el servidor usando SSL/TLS. Esto es importante porque, si no se aplica, toda la información, incluidas las contraseñas, se envía a través de la red en texto simple.

      Si tiene un nombre de dominio, la alternativa más sencilla para obtener un certificado SSL para proteger su tráfico es usar Let’s Encrypt. Siga esta guía para configurar Let’s Encrypt con Nginx en Ubuntu 20.04. Siga el procedimiento usando el bloque de servidor de Nginx que creamos en esta guía.

      Resolver problemas en Nginx y Gunicorn

      Si con este último paso no se muestra su aplicación, deberá resolver problemas en su instalación.

      Nginx muestra la página predeterminada en lugar de la aplicación de Django

      Si Nginx muestra la página predeterminada en lugar de actualizar su aplicación, normalmente significa que deberá ajustar server_name dentro del archivo /etc/nginx/sites-available/myproject para apuntar a la dirección IP o al nombre de dominio de su servidor.

      Nginx usa el server_name para determinar el bloque de servidor que usará para responder a solicitudes. Si ve la página predeterminada de Nginx, significa que Nginx no pudo hacer coincidir la solicitud con un bloque de servidor de forma explícita, por lo cual sigue recurriendo al bloque por defecto definido en /etc/nginx/sites-available/default.

      El server_name del bloque de servidor de su proyecto debe ser más específico que el del bloque de servidor predeterminado que se seleccionará.

      Nginx muestra un error de puerta de enlace 502 en lugar de la aplicación de Django

      Un error 502 indica que Nginx no puede autorizar con éxito la solicitud. Con el error 502 se transmite una amplia variedad de problemas de configuración, por lo que se necesita más información para resolver los problemas de forma adecuada.

      Los registros de errores de Nginx son el recurso principal para buscar más información. Generalmente, esto le indicará las condiciones que ocasionaron problemas durante el evento de autorización. Siga los registros de errores de Nginx escribiendo lo siguiente:

      • sudo tail -F /var/log/nginx/error.log

      Ahora, realice otra solicitud en su navegador para generar un nuevo error (intente actualizar la página). Debería recibir un mensaje de error nuevo en el registro. Leer el mensaje lo ayudará a determinar el problema.

      Es probable que reciba el siguiente mensaje:

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

      Esto indica que Nginx no pudo encontrar el archivo gunicorn.sock en la ubicación en cuestión. Debería comparar la ubicación de proxy_pass definida en el archivo /etc/nginx/sites-available/myproject con la ubicación actual del archivo gunicorn.sock generado por la unidad de systemd gunicorn.sock.

      Si no puede encontrar un archivo gunicorn.sock en el directorio /run, por lo general significa que el archivo de socket de systemd no pudo crearlo. Regrese a la sección de verificación del archivo de socket de Gunicorn para seguir los pasos de resolución de problemas de Gunicorn.

      connect() to unix:/run/gunicorn.sock failed (13: Permission denied)

      Esto indica que Nginx no pudo conectarse al socket de Gunicorn debido a problemas de permisos. Esto puede ocurrir cuando se sigue el procedimiento con un usuario root en lugar de un usuario sudo. Aunque systemd puede crear el archivo de socket de Gunicorn, Nginx no puede acceder a él.

      Esto puede ocurrir si hay permisos limitados en cualquier punto entre el directorio root (/) y el archivo gunicorn.sock. Podemos revisar los permisos y los valores de propiedad del archivo de socket y cada uno de sus directorios principales pasando la ruta absoluta a nuestro archivo de socket al comando namei:

      • namei -l /run/gunicorn.sock

      Output

      f: /run/gunicorn.sock drwxr-xr-x root root / drwxr-xr-x root root run srw-rw-rw- root root gunicorn.sock

      En el resultado se muestran los permisos de cada uno de los componentes del directorio. Al mirar los permisos (primera columna), el propietario (segunda columna) y el propietario del grupo (tercera columna), podemos averiguar el tipo de acceso permitido para el archivo de socket.

      En el ejemplo anterior, el archivo de sockets y cada directorio que conduce a este tienen permisos mundiales de lectura y ejecución (la columna de permisos para los directorios termina en r-x en lugar de ---). El proceso de Nginx debería poder acceder al socket de forma correcta.

      Si algunos directorios que conducen al socket no tienen permiso mundial de lectura y ejecución, Nginx no podrá acceder al socket sin otorgar permisos mundiales de lectura y ejecución ni asegurarse de que se otorgue propiedad del grupo a un grupo del que forme parte Nginx.

      Django muestra el mensaje “could not connect to server: Connection refused”

      Este es uno de los mensajes que puede recibir de Django al intentar acceder a ciertas partes de la aplicación en el navegador web:

      OperationalError at /admin/login/
      could not connect to server: Connection refused
          Is the server running on host "localhost" (127.0.0.1) and accepting
          TCP/IP connections on port 5432?
      

      Esto indica que Django no puede conectarse a la base de datos de Postgres. Asegúrese de que la instancia de Postgres esté en ejecución escribiendo lo siguiente:

      • sudo systemctl status postgresql

      Si esto no sucede, puede iniciarla y activarla para que se cargue automáticamente en el inicio (si aún no está cargada la configuración para ello) escribiendo lo siguiente:

      • sudo systemctl start postgresql
      • sudo systemctl enable postgresql

      Si todavía experimenta problemas, asegúrese de que los ajustes de la base de datos definidos en el archivo ~/myprojectdir/myproject/settings.py sean correctos.

      Solución de problemas adicionales

      Para resolver problemas adicionales, los registros pueden servir para reducir las causas raíces. Verifique cada uno de ellos por separado y busque mensajes que indiquen las áreas problemáticas.

      Los siguientes registros pueden ser útiles:

      • Verifique los registros de proceso de Nginx escribiendo lo siguiente: sudo journalctl -u nginx.
      • Verifique los registros de acceso de Nginx escribiendo lo siguiente: sudo less /var/log/nginx/access.log
      • Verifique los registros de errores de Nginx escribiendo lo siguiente: sudo less /var/log/nginx/error.log.
      • Verifique los registros de la aplicación de Gunicorn escribiendo lo siguiente: sudo journalctl -u gunicorn.
      • Verifique los registros de sockets de Gunicorn escribiendo lo siguiente: sudo journalctl -u gunicorn.socket.

      Cuando actualice su configuración o aplicación, es probable que necesite reiniciar los procesos para que asimilen sus cambios.

      Si actualiza su aplicación de Django, puede reiniciar el proceso de Gunicorn para que incorpore los cambios escribiendo lo siguiente:

      • sudo systemctl restart gunicorn

      Si cambia los archivos de socket y servicio de Gunicorn, vuelva a cargar el demonio y reinicie el proceso escribiendo lo siguiente:

      • sudo systemctl daemon-reload
      • sudo systemctl restart gunicorn.socket gunicorn.service

      Si cambia la configuración de bloque del servidor de Nginx, pruébela y luego verifique Nginx escribiendo lo siguiente:

      • sudo nginx -t && sudo systemctl restart nginx

      Estos comandos son útiles para incorporar cambios cuando ajusta su configuración.

      Conclusión

      En esta guía, creamos un proyecto de Django en su propio entorno virtual. Configuramos Gunicorn para que traduzca las solicitudes de los clientes a fin de que Django pueda manejarlas. Posteriormente, configuramos Nginx para que actúe como proxy inverso a fin de manejar las conexiones de los clientes y presentar el proyecto correcto según la solicitud del cliente.

      Django simplifica la creación de proyectos y aplicaciones proporcionando muchas de las piezas comunes, lo que le permite centrarse en los elementos únicos. Al aprovechar la cadena general de herramientas descrita en este artículo, puede ofrecer fácilmente las aplicaciones que cree desde un servidor único.



      Source link