One place for hosting & domains

      Gunicorn

      How To Serve Flask Applications with Gunicorn and Nginx on Ubuntu 20.04


      In this guide, you will build a Python application using the Flask microframework on Ubuntu 20.04. The majority of this tutorial is about how to set up the Gunicorn application server to run the application and how to configure Nginx to act as a front-end reverse proxy.

      Introduction

      In this guide, you will build a Python application using the Flask microframework on Ubuntu 20.04. The bulk of this article will be about how to set up the Gunicorn application server and how to launch the application and configure Nginx to act as a front-end reverse proxy.

      Prerequisites

      Before starting this guide, you should have:

      • A server with Ubuntu 20.04 installed and a non-root user with sudo privileges. Follow our initial server setup guide for guidance.
      • Nginx installed, following Steps 1 and 2 of How To Install Nginx on Ubuntu 20.04.
      • A domain name configured to point to your server. You can purchase one on Namecheap or get one for free on Freenom. You can learn how to point domains to DigitalOcean by following the relevant documentation on domains and DNS. Be sure to create the following DNS records:

        • An A record with your_domain pointing to your server’s public IP address.
        • An A record with www.your_domain pointing to your server’s public IP address.
      • Familiarity with the WSGI specification, which the Gunicorn server will use to communicate with your Flask application. This discussion covers WSGI in more detail.

      Step 1 — Installing the Components from the Ubuntu Repositories

      Our first step will be to install all of the pieces we need from the Ubuntu repositories. This includes pip, the Python package manager, which will manage our Python components. We will also get the Python development files necessary to build some of the Gunicorn components.

      First, let’s update the local package index and install the packages that will allow us to build our Python environment. These will include python3-pip, along with a few more packages and development tools necessary for a robust programming environment:

      • sudo apt update
      • sudo apt install python3-pip python3-dev build-essential libssl-dev libffi-dev python3-setuptools

      With these packages in place, let’s move on to creating a virtual environment for our project.

      Step 2 — Creating a Python Virtual Environment

      Next, we’ll set up a virtual environment in order to isolate our Flask application from the other Python files on the system.

      Start by installing the python3-venv package, which will install the venv module:

      • sudo apt install python3-venv

      Next, let’s make a parent directory for our Flask project. Move into the directory after you create it:

      • mkdir ~/myproject
      • cd ~/myproject

      Create a virtual environment to store your Flask project’s Python requirements by typing:

      • python3 -m venv myprojectenv

      This will install a local copy of Python and pip into a directory called myprojectenv within your project directory.

      Before installing applications within the virtual environment, you need to activate it. Do so by typing:

      • source myprojectenv/bin/activate

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

      Step 3 — Setting Up a Flask Application

      Now that you are in your virtual environment, you can install Flask and Gunicorn and get started on designing your application.

      First, let’s install wheel with the local instance of pip to ensure that our packages will install even if they are missing wheel archives:

      Note


      Regardless of which version of Python you are using, when the virtual environment is activated, you should use the pip command (not pip3).

      Next, let’s install Flask and Gunicorn:

      • pip install gunicorn flask

      Creating a Sample App

      Now that you have Flask available, you can create a simple application. Flask is a microframework. It does not include many of the tools that more full-featured frameworks might, and exists mainly as a module that you can import into your projects to assist you in initializing a web application.

      While your application might be more complex, we’ll create our Flask app in a single file, called myproject.py:

      • nano ~/myproject/myproject.py

      The application code will live in this file. It will import Flask and instantiate a Flask object. You can use this to define the functions that should be run when a specific route is requested:

      ~/myproject/myproject.py

      from flask import Flask
      app = Flask(__name__)
      
      @app.route("/")
      def hello():
          return "<h1 style="color:blue">Hello There!</h1>"
      
      if __name__ == "__main__":
          app.run(host="0.0.0.0")
      

      This basically defines what content to present when the root domain is accessed. Save and close the file when you’re finished.

      If you followed the initial server setup guide, you should have a UFW firewall enabled. To test the application, you need to allow access to port 5000:

      Now you can test your Flask app by typing:

      You will see output like the following, including a helpful warning reminding you not to use this server setup in production:

      Output

      * Serving Flask app "myproject" (lazy loading) * Environment: production WARNING: Do not use the development server in a production environment. Use a production WSGI server instead. * Debug mode: off * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)

      Visit your server’s IP address followed by :5000 in your web browser:

      http://your_server_ip:5000
      

      You should see something like this:

      Flask sample app

      When you are finished, hit CTRL-C in your terminal window to stop the Flask development server.

      Creating the WSGI Entry Point

      Next, let’s create a file that will serve as the entry point for our application. This will tell our Gunicorn server how to interact with the application.

      Let’s call the file wsgi.py:

      In this file, let’s import the Flask instance from our application and then run it:

      ~/myproject/wsgi.py

      from myproject import app
      
      if __name__ == "__main__":
          app.run()
      

      Save and close the file when you are finished.

      Step 4 — Configuring Gunicorn

      Your application is now written with an entry point established. We can now move on to configuring Gunicorn.

      Before moving on, we should check that Gunicorn can serve the application correctly.

      We can do this by simply passing it the name of our entry point. This is constructed as the name of the module (minus the .py extension), plus the name of the callable within the application. In our case, this is wsgi:app.

      We’ll also specify the interface and port to bind to so that the application will be started on a publicly available interface:

      • cd ~/myproject
      • gunicorn --bind 0.0.0.0:5000 wsgi:app

      You should see output like the following:

      Output

      [2020-05-20 14:13:00 +0000] [46419] [INFO] Starting gunicorn 20.0.4 [2020-05-20 14:13:00 +0000] [46419] [INFO] Listening at: http://0.0.0.0:5000 (46419) [2020-05-20 14:13:00 +0000] [46419] [INFO] Using worker: sync [2020-05-20 14:13:00 +0000] [46421] [INFO] Booting worker with pid: 46421

      Visit your server’s IP address with :5000 appended to the end in your web browser again:

      http://your_server_ip:5000
      

      You should see your application’s output:

      Flask sample app

      When you have confirmed that it’s functioning properly, press CTRL-C in your terminal window.

      We’re now done with our virtual environment, so we can deactivate it:

      Any Python commands will now use the system’s Python environment again.

      Next, let’s create the systemd service unit file. Creating a systemd unit file will allow Ubuntu’s init system to automatically start Gunicorn and serve the Flask application whenever the server boots.

      Create a unit file ending in .service within the /etc/systemd/system directory to begin:

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

      Inside, we’ll start with the [Unit] section, which is used to specify metadata and dependencies. Let’s put a description of our service here and tell the init system to only start this after the networking target has been reached:

      /etc/systemd/system/myproject.service

      [Unit]
      Description=Gunicorn instance to serve myproject
      After=network.target
      

      Next, let’s open up the [Service] section. This will specify the user and group that we want the process to run under. Let’s give our regular user account ownership of the process since it owns all of the relevant files. Let’s also give group ownership to the www-data group so that Nginx can communicate easily with the Gunicorn processes. Remember to replace the username here with your username:

      /etc/systemd/system/myproject.service

      [Unit]
      Description=Gunicorn instance to serve myproject
      After=network.target
      
      [Service]
      User=sammy
      Group=www-data
      

      Next, let’s map out the working directory and set the PATH environmental variable so that the init system knows that the executables for the process are located within our virtual environment. Let’s also specify the command to start the service. This command will do the following:

      • Start 3 worker processes (though you should adjust this as necessary)
      • Create and bind to a Unix socket file, myproject.sock, within our project directory. We’ll set an umask value of 007 so that the socket file is created giving access to the owner and group, while restricting other access
      • Specify the WSGI entry point file name, along with the Python callable within that file (wsgi:app)

      Systemd requires that we give the full path to the Gunicorn executable, which is installed within our virtual environment.

      Remember to replace the username and project paths with your own information:

      /etc/systemd/system/myproject.service

      [Unit]
      Description=Gunicorn instance to serve myproject
      After=network.target
      
      [Service]
      User=sammy
      Group=www-data
      WorkingDirectory=/home/sammy/myproject
      Environment="PATH=/home/sammy/myproject/myprojectenv/bin"
      ExecStart=/home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app
      

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

      /etc/systemd/system/myproject.service

      [Unit]
      Description=Gunicorn instance to serve myproject
      After=network.target
      
      [Service]
      User=sammy
      Group=www-data
      WorkingDirectory=/home/sammy/myproject
      Environment="PATH=/home/sammy/myproject/myprojectenv/bin"
      ExecStart=/home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app
      
      [Install]
      WantedBy=multi-user.target
      

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

      We can now start the Gunicorn service we created and enable it so that it starts at boot:

      • sudo systemctl start myproject
      • sudo systemctl enable myproject

      Let’s check the status:

      • sudo systemctl status myproject

      You should see output like this:

      Output

      ● myproject.service - Gunicorn instance to serve myproject Loaded: loaded (/etc/systemd/system/myproject.service; enabled; vendor preset: enabled) Active: active (running) since Wed 2020-05-20 14:15:18 UTC; 1s ago Main PID: 46430 (gunicorn) Tasks: 4 (limit: 2344) Memory: 51.3M CGroup: /system.slice/myproject.service ├─46430 /home/sammy/myproject/myprojectenv/bin/python3 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app ├─46449 /home/sammy/myproject/myprojectenv/bin/python3 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app ├─46450 /home/sammy/myproject/myprojectenv/bin/python3 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app └─46451 /home/sammy/myproject/myprojectenv/bin/python3 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app

      If you see any errors, be sure to resolve them before continuing with the tutorial.

      Step 5 — Configuring Nginx to Proxy Requests

      Our Gunicorn application server should now be up and running, waiting for requests on the socket file in the project directory. Let’s now configure Nginx to pass web requests to that socket by making some small additions to its configuration file.

      Begin by creating a new server block configuration file in Nginx’s sites-available directory. Let’s call this myproject to keep in line with the rest of the guide:

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

      Open up a server block and tell Nginx to listen on the default port 80. Let’s also tell it to use this block for requests for our server’s domain name:

      /etc/nginx/sites-available/myproject

      server {
          listen 80;
          server_name your_domain www.your_domain;
      }
      

      Next, let’s add a location block that matches every request. Within this block, we’ll include the proxy_params file that specifies some general proxying parameters that need to be set. We’ll then pass the requests to the socket we defined using the proxy_pass directive:

      /etc/nginx/sites-available/myproject

      server {
          listen 80;
          server_name your_domain www.your_domain;
      
          location / {
              include proxy_params;
              proxy_pass http://unix:/home/sammy/myproject/myproject.sock;
          }
      }
      

      Save and close the file when you’re finished.

      To enable the Nginx server block configuration you’ve just created, link the file to the sites-enabled directory:

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

      With the file in that directory, you can test for syntax errors:

      If this returns without indicating any issues, restart the Nginx process to read the new configuration:

      • sudo systemctl restart nginx

      Finally, let’s adjust the firewall again. We no longer need access through port 5000, so we can remove that rule. We can then allow full access to the Nginx server:

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

      You should now be able to navigate to your server’s domain name in your web browser:

      http://your_domain
      

      You should see your application’s output:

      Flask sample app

      If you encounter any errors, trying checking the following:

      • sudo less /var/log/nginx/error.log: checks the Nginx error logs.
      • sudo less /var/log/nginx/access.log: checks the Nginx access logs.
      • sudo journalctl -u nginx: checks the Nginx process logs.
      • sudo journalctl -u myproject: checks your Flask app’s Gunicorn logs.

      Step 6 — Securing the Application

      To ensure that traffic to your server remains secure, let’s get an SSL certificate for your domain. There are multiple ways to do this, including getting a free certificate from Let’s Encrypt, generating a self-signed certificate, or buying one from another provider and configuring Nginx to use it by following Steps 2 through 6 of How to Create a Self-signed SSL Certificate for Nginx in Ubuntu 20.04. We will go with option one for the sake of expediency.

      Install Certbot’s Nginx package with apt:

      • sudo apt install python3-certbot-nginx

      Certbot provides a variety of ways to obtain SSL certificates through plugins. The Nginx plugin will take care of reconfiguring Nginx and reloading the config whenever necessary. To use this plugin, type the following:

      • sudo certbot --nginx -d your_domain -d www.your_domain

      This runs certbot with the --nginx plugin, using -d to specify the names we’d like the certificate to be valid for.

      If this is your first time running certbot, you will be prompted to enter an email address and agree to the terms of service. After doing so, certbot will communicate with the Let’s Encrypt server, then run a challenge to verify that you control the domain you’re requesting a certificate for.

      If that’s successful, certbot will ask how you’d like to configure your HTTPS settings:

      Output

      Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access. ------------------------------------------------------------------------------- 1: No redirect - Make no further changes to the webserver configuration. 2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for new sites, or if you're confident your site works on HTTPS. You can undo this change by editing your web server's configuration. ------------------------------------------------------------------------------- Select the appropriate number [1-2] then [enter] (press 'c' to cancel):

      Select your choice then hit ENTER. The configuration will be updated, and Nginx will reload to pick up the new settings. certbot will wrap up with a message telling you the process was successful and where your certificates are stored:

      Output

      IMPORTANT NOTES: - Congratulations! Your certificate and chain have been saved at: /etc/letsencrypt/live/your_domain/fullchain.pem Your key file has been saved at: /etc/letsencrypt/live/your_domain/privkey.pem Your cert will expire on 2020-08-18. To obtain a new or tweaked version of this certificate in the future, simply run certbot again with the "certonly" option. To non-interactively renew *all* of your certificates, run "certbot renew" - Your account credentials have been saved in your Certbot configuration directory at /etc/letsencrypt. You should make a secure backup of this folder now. This configuration directory will also contain certificates and private keys obtained by Certbot so making regular backups of this folder is ideal. - If you like Certbot, please consider supporting our work by: Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate Donating to EFF: https://eff.org/donate-le

      If you followed the Nginx installation instructions in the prerequisites, you will no longer need the redundant HTTP profile allowance:

      • sudo ufw delete allow 'Nginx HTTP'

      To verify the configuration, navigate once again to your domain, using https://:

      https://your_domain
      

      You should see your application output once again, along with your browser’s security indicator, which should indicate that the site is secured.

      Conclusion

      In this guide, you created and secured a simple Flask application within a Python virtual environment. You created a WSGI entry point so that any WSGI-capable application server can interface with it, and then configured the Gunicorn app server to provide this function. Afterwards, you created a systemd service file to automatically launch the application server on boot. You also created an Nginx server block that passes web client traffic to the application server, relaying external requests, and secured traffic to your server with Let’s Encrypt.

      Flask is a very simple, but extremely flexible framework meant to provide your applications with functionality without being too restrictive about structure and design. You can use the general stack described in this guide to serve the flask applications that you design.



      Source link

      Обслуживание приложений Flask с Gunicorn и Nginx в Ubuntu 18.04


      Введение

      В этом обучающем модуле вы создадите приложение Python с использованием микроструктуры Flask в Ubuntu 18.04. Основная часть этой статьи посвящена настройке сервера приложений Gunicorn, запуску приложения и настройке Nginx для работы в режиме обратного прокси-сервера фронтенда.

      Предварительные требования

      Перед началом прохождения этого обучающего модуля вам потребуется следующее:

      • Сервер с установленной операционной системой Ubuntu 18.04 и пользователь без привилегий root и с привилегиями sudo. Следуйте указаниям нашего руководства по начальной настройке сервера.
      • Веб-сервер Nginx, установленный в соответствии с шагами 1 и 2 модуля Установка Nginx в Ubuntu 18.04.
      • Доменное имя, настроенное так, чтобы указывать на ваш сервер. Вы можете приобрести его на Namecheap или получить бесплатно на Freenom. Вы можете узнать, как указывать домены на DigitalOcean, из соответствующей документации по доменам и DNS. Обязательно создайте следующие записи DNS:

        • Запись A, где your_domain указывает на публичный IP-адрес вашего сервера.
        • Запись A, где www.your_domain указывает на публичный IP-адрес вашего сервера.
      • Знакомство со спецификацией WSGI, которую сервер Gunicorn будет использовать для взаимодействия с вашими приложениями Flask. В этом обсуждении более подробно рассказывается о WSGI.

      Шаг 1 — Установка компонентов из хранилищ Ubuntu

      Первым шагом будет установка всех необходимых нам элементов из хранилищ Ubuntu. Она включает установку pip, диспетчера пакетов Python, который будет управлять нашими компонентами Python. Также мы получим файлы разработки Python, необходимые для создания некоторых компонентов Gunicorn.

      Вначале обновим локальный индекс пакетов и установим пакеты, которые позволят нам создать нашу среду Python. Мы установим пакет python3-pip, а также еще несколько пакетов и средств разработки, необходимых для создания надежной среды программирования:

      • sudo apt update
      • sudo apt install python3-pip python3-dev build-essential libssl-dev libffi-dev python3-setuptools

      С этими пакетами мы перейдем к созданию виртуальной среды для нашего проекта.

      Шаг 2 — Создание виртуальной среды Python

      Теперь мы настроим виртуальную среду, чтобы изолировать наше приложение Flask от других файлов Python в системе.

      Для начала установим пакет python3-venv, который установит модуль venv:

      • sudo apt install python3-venv

      Затем создадим родительский каталог для нашего проекта Flask. Перейдите в каталог после его создания:

      • mkdir ~/myproject
      • cd ~/myproject

      Создайте виртуальную среду для хранения требований Python для вашего проекта Flask, введя следующую команду:

      • python3.6 -m venv myprojectenv

      Локальные копии Python и pip будут установлены в каталог myprojectenv в каталоге вашего проекта.

      Прежде чем устанавливать приложения в виртуальной среде, ее нужно активировать. Для этого нужно ввести следующую команду:

      • source myprojectenv/bin/activate

      Командная строка изменится, показывая, что теперь вы работаете в виртуальной среде. Она будет выглядеть примерно так: (myprojectenv)user@host:~/myproject$.

      Шаг 3 — Настройка приложения Flask

      Находясь в виртуальной среде, вы можете установить Flask и Gunicorn и начать работу над созданием вашего приложения.

      Вначале мы установим wheel с локальным экземпляром pip, чтобы убедиться, что наши пакеты будут устанавливаться даже при отсутствии архивов wheel:

      Примечание. Если виртуальная среда активна, то вне зависимости от того, какую версию Python вы используете, вы должны использовать команду pip (а не pip3).

      Затем установим Flask и Gunicorn:

      • pip install gunicorn flask

      Создание образца приложения

      Теперь вы можете использовать Flask для создания простого приложения. Flask представляет собой микроструктуру. В ней отсутствуют многие инструменты, входящие в полноценные инфраструктуры программирования, и она существует в основном в виде модуля, который вы можете импортировать в проекты для инициализации веб-приложения.

      Хотя ваше приложение может быть более сложным, мы создадим наше приложение Flask в одном файле с именем myproject.py:

      • nano ~/myproject/myproject.py

      Код приложения будет находиться в этом файле. Он импортирует Flask и создаст экземпляр объекта Flask. Вы можете использовать его для определения функций, которые запускаться при запросе конкретного маршрута:

      ~/myproject/myproject.py

      from flask import Flask
      app = Flask(__name__)
      
      @app.route("/")
      def hello():
          return "<h1 style='color:blue'>Hello There!</h1>"
      
      if __name__ == "__main__":
          app.run(host='0.0.0.0')
      

      Здесь определяется, какой контент должен выводиться при доступе к корневому домену. Сохраните файл и закройте его после завершения.

      Если вы следовали указаниям модуля по начальной настройке сервера, у вас должен быть включен брандмауэр UFW. Чтобы протестировать приложение, вам нужно разрешить доступ к порту 5000:

      Теперь вы можете протестировать приложение Flask с помощью следующей команды:

      Вы увидите следующий результат, в том числе полезное предупреждение, напоминающее не использовать эти настройки сервера в реальной работе:

      Output

      * Serving Flask app "myproject" (lazy loading) * Environment: production WARNING: Do not use the development server in a production environment. Use a production WSGI server instead. * Debug mode: off * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)

      Откройте в браузере IP-адрес вашего сервера с суффиксом :5000:

      http://your_server_ip:5000
      

      Вы увидите примерно следующее:

      Образец приложения Flask

      Когда вы закончите, нажмите CTRL+C в окне терминала, чтобы остановить сервер разработки CTRL+C

      Создание точки входа WSGI

      Теперь создадим файл, который будет служить точкой входа в наше приложение. Это покажет серверу Gunicorn, как взаимодействовать с приложением.

      Мы назовем этот файл wsgi.py:

      Сейчас мы импортируем экземпляр Flask из нашего приложения в этот файл и запустим его:

      ~/myproject/wsgi.py

      from myproject import app
      
      if __name__ == "__main__":
          app.run()
      

      Сохраните файл и закройте его после завершения.

      Шаг 4 — Настройка Gunicorn

      Ваше приложение написано, и для него создана точка входа. Теперь мы можем перейти к настройке Gunicorn.

      Прежде чем продолжить, нужно убедиться, что Gunicorn может правильно обслуживать приложение.

      Для этого нужно просто передать имя нашей точки входа. Оно составляется из имени модуля (без расширения .py) и имени вызываемого элемента приложения. В нашем случае это wsgi:app.

      Также мы укажем интерфейс и порт для привязки, чтобы приложение запускалось через общедоступный интерфейс:

      • cd ~/myproject
      • gunicorn --bind 0.0.0.0:5000 wsgi:app

      Результат будет выглядеть следующим образом:

      Output

      [2018-07-13 19:35:13 +0000] [28217] [INFO] Starting gunicorn 19.9.0 [2018-07-13 19:35:13 +0000] [28217] [INFO] Listening at: http://0.0.0.0:5000 (28217) [2018-07-13 19:35:13 +0000] [28217] [INFO] Using worker: sync [2018-07-13 19:35:13 +0000] [28220] [INFO] Booting worker with pid: 28220

      Откройте в браузере IP-адрес вашего сервера с суффиксом :5000.

      http://your_server_ip:5000
      

      Вы увидите результат выполнения вашего приложения:

      Образец приложения Flask

      Убедившись в его нормальной работе, нажмите CTRL+C в окне терминала.

      Мы закончили работу с виртуальной средой, и теперь можем отключить ее:

      Теперь любые команды Python снова будут использовать системную среду Python.

      Далее мы созадим файл служебных элементов systemd. Создание файла элементов systemd позволит системе инициализации Ubuntu автоматически запускать Gunicorn и обслуживать приложение Flask при загрузке сервера.

      Для начала создайте файл элементов с расширением .service в каталоге /etc/systemd/system:

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

      Мы начнем с раздела [Unit] этого файла, где указываются метаданные и зависимости. Здесь мы разместим описание службы и предпишем системе инициализации запускать ее только после достижения сетевой цели:

      /etc/systemd/system/myproject.service

      [Unit]
      Description=Gunicorn instance to serve myproject
      After=network.target
      

      Теперь откроем раздел [Service]. Здесь указывается пользователь и группа, от имени которых мы хотим запустить данный процесс. Сделаем владельцем процесса учетную запись обычного пользователя, поскольку этот пользователь является владельцем всех соответствующих файлов. Также назначим владельцем группу www-data, чтобы упростить коммуникацию Nginx с процессом Gunicorn. Не забудьте заменить приведенное имя пользователя своим именем пользователя:

      /etc/systemd/system/myproject.service

      [Unit]
      Description=Gunicorn instance to serve myproject
      After=network.target
      
      [Service]
      User=sammy
      Group=www-data
      

      Теперь составим карту рабочего каталога и зададим переменную среды PATH, чтобы система инициализации знала, что исполняемые файлы этого процесса находятся в нашей виртуальной среде. Также укажем команду для запуска службы. Эта команда будет выполнять следующее:

      • Запуск 3 рабочих процессов (хотя вы можете изменить это при необходимости)
      • Создание и привязвка к файлу сокетов Unix myproject.sock в каталоге нашего проекта. Мы зададим значение umask 007, чтобы при создании файла сокета предоставлялся доступ для владельца и для группы, а любой другой доступ ограничивался
      • Укажите имя файла точки входа WSGI, а также вызываемый элемент Python в этом файле (wsgi:app)

      Systemd требует, чтобы мы указывали полный путь исполняемого файла Gunicorn, установленного в нашей виртуальной среде.

      Не забудьте заменить имя пользователя и пути проекта собственными данными:

      /etc/systemd/system/myproject.service

      [Unit]
      Description=Gunicorn instance to serve myproject
      After=network.target
      
      [Service]
      User=sammy
      Group=www-data
      WorkingDirectory=/home/sammy/myproject
      Environment="PATH=/home/sammy/myproject/myprojectenv/bin"
      ExecStart=/home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app
      

      Наконец, добавим раздел [Install]. Это покажет systemd, куда привязывать эту службу, если мы активируем ее запуск при загрузке. Нам нужно, чтобы эта служба запускалась во время работы обычной многопользовательской системы:

      /etc/systemd/system/myproject.service

      [Unit]
      Description=Gunicorn instance to serve myproject
      After=network.target
      
      [Service]
      User=sammy
      Group=www-data
      WorkingDirectory=/home/sammy/myproject
      Environment="PATH=/home/sammy/myproject/myprojectenv/bin"
      ExecStart=/home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app
      
      [Install]
      WantedBy=multi-user.target
      

      Теперь служебный файл systemd готов. Сохраните и закройте его.

      Теперь мы запустим созданную службу Gunicorn, и активируем ее запуск при загрузке системы:

      • sudo systemctl start myproject
      • sudo systemctl enable myproject

      Теперь проверим состояние:

      • sudo systemctl status myproject

      Результат должен выглядеть следующим образом:

      Output

      ● myproject.service - Gunicorn instance to serve myproject Loaded: loaded (/etc/systemd/system/myproject.service; enabled; vendor preset: enabled) Active: active (running) since Fri 2018-07-13 14:28:39 UTC; 46s ago Main PID: 28232 (gunicorn) Tasks: 4 (limit: 1153) CGroup: /system.slice/myproject.service ├─28232 /home/sammy/myproject/myprojectenv/bin/python3.6 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 ├─28250 /home/sammy/myproject/myprojectenv/bin/python3.6 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 ├─28251 /home/sammy/myproject/myprojectenv/bin/python3.6 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 └─28252 /home/sammy/myproject/myprojectenv/bin/python3.6 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007

      Если вы увидите какие-либо ошибки, устраните их, прежде чем продолжить выполнение этого обучающего модуля.

      Шаг 5 — Настройка Nginx для работы с запросами прокси-сервера

      Сервер приложений Gunicorn должен быть запущен и ожидать запросы файла сокета в каталоге проекта. Теперь мы настроим Nginx для передачи веб-запросов на этот сокет. Для этого мы сделаем небольшие добавления в его файл конфигурации.

      Вначале мы создадим новый файл конфигурации серверных блоков в каталоге Nginx sites-available. Назовем его myproject для соответствия остальным именам в этом модуле:

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

      Откройте серверный блок и укажите Nginx прослушивать порт по умолчанию 80. Также укажите использовать этот блок для запросов доменного имени нашего сервера:

      /etc/nginx/sites-available/myproject

      server {
          listen 80;
          server_name your_domain www.your_domain;
      }
      

      Затем добавим блок расположения, соответствующий каждому запросу. В этот блок мы добавим файл proxy_params, определяющий некоторые общие параметры прокси, которые необходимо настроить. После этого запросы будут переданы на сокет, который мы определили с помощью директивы proxy_pass:

      /etc/nginx/sites-available/myproject

      server {
          listen 80;
          server_name your_domain www.your_domain;
      
          location / {
              include proxy_params;
              proxy_pass http://unix:/home/sammy/myproject/myproject.sock;
          }
      }
      

      Сохраните файл и закройте его после завершения.

      Чтобы активировать созданную конфигурацию серверных блоков Nginx, необходимо привязать файл к каталогу sites-enabled:

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

      Когда файл будет находиться в этом каталоге, можно провести проверку на ошибки синтаксиса:

      Если ошибок обнаружено не будет, перезапустите процесс Nginx для чтения новой конфигурации:

      • sudo systemctl restart nginx

      В заключение снова изменим настройки брандмауэра. Нам больше не потребуется доступ через порт 5000, и мы можем удалить это правило. Затем мы сможем разрешить полный доступ к серверу Nginx:

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

      Теперь у вас должна быть возможность открыть доменное имя вашего сервера в браузере:

      http://your_domain
      

      Вы увидите результат выполнения вашего приложения:

      Образец приложения Flask

      Если будут обнаружены любые ошибки, проверьте следующее:

      • sudo less /var/log/nginx/error.log: проверяет журналы ошибок Nginx.
      • sudo less /var/log/nginx/access.log: проверяет журналы доступа Nginx.
      • sudo journalctl -u nginx: проверяет журналы процессов Nginx.
      • sudo journalctl -u myproject: проверяет журналы Gunicorn вашего приложения Flask.

      Шаг 6 — Защита приложения

      Чтобы обеспечить защиту трафика вашего сервера, необходимо получить сертификат SSL для вашего домена. Этого можно добиться несколькими способами, в том числе получить бесплатный сертификат от Let’s Encrypt, сгенерировать сертификат с собственной подписью или приобрести сертификат у другого поставщика и настроить Nginx для его использования, для чего потребуется выполнить шаги с 2 по 6 обучающего модуля Создание сертификата SSL с собственной подписью для Nginx в Ubuntu 18.04. Для удобства мы выберем первый вариант.

      Вначале добавьте хранилище Certbot Ubuntu:

      • sudo add-apt-repository ppa:certbot/certbot

      Вам нужно будет нажать ENTER для подтверждения.

      Установите пакет Certbot Nginx с apt:

      • sudo apt install python-certbot-nginx

      Certbot предоставляет широкий выбор способов получения сертификатов SSL с помощью плагинов: Плагин Nginx изменит конфигурацию Nginx и перезагрузит ее, когда это потребуется. Для использования этого плагина введите следующую команду:

      • sudo certbot --nginx -d your_domain -d www.your_domain

      Эта команда запускает certbot с плагином --nginx, используя опцию -d to для указания имен, для которых должен действовать сертификат.

      Если это первый запуск certbot, вам будет предложено указать адрес эл. почты и принять условия обслуживания. После этого certbot свяжется с сервером Let’s Encrypt и отправит запрос с целью подтвердить, что вы контролируете домен, для которого запрашиваете сертификат.

      Если это будет подтверждено, certbot запросит у вас предпочитаемый вариант настройки HTTPS:

      Output

      Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access. ------------------------------------------------------------------------------- 1: No redirect - Make no further changes to the webserver configuration. 2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for new sites, or if you're confident your site works on HTTPS. You can undo this change by editing your web server's configuration. ------------------------------------------------------------------------------- Select the appropriate number [1-2] then [enter] (press 'c' to cancel):

      Выберите желаемый вариант, после чего нажмите ENTER. Конфигурация будет обновлена, а Nginx перезагрузится для получения новых настроек. Затем certbot завершит работу и выведет сообщение, подтверждающее завершение процесса и указывающее место хранения ваших сертификатов:

      Output

      IMPORTANT NOTES: - Congratulations! Your certificate and chain have been saved at: /etc/letsencrypt/live/your_domain/fullchain.pem Your key file has been saved at: /etc/letsencrypt/live/your_domain/privkey.pem Your cert will expire on 2018-07-23. To obtain a new or tweaked version of this certificate in the future, simply run certbot again with the "certonly" option. To non-interactively renew *all* of your certificates, run "certbot renew" - Your account credentials have been saved in your Certbot configuration directory at /etc/letsencrypt. You should make a secure backup of this folder now. This configuration directory will also contain certificates and private keys obtained by Certbot so making regular backups of this folder is ideal. - If you like Certbot, please consider supporting our work by: Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate Donating to EFF: https://eff.org/donate-le

      Если вы следовали инструкциям по установке Nginx из предварительных требований, вам больше не потребуется разрешать профиль HTTP лишний раз:

      • sudo ufw delete allow 'Nginx HTTP'

      Чтобы подтвердить конфигурацию, снова перейдите в свой домен, используя префикс адреса https://:

      https://your_domain
      

      Вы снова должны увидеть результат выполнения приложения, а также значок замка в браузере, подтверждающий, что сайт защищен.

      Заключение

      В этом обучающем модуле вы научились создавать и защищать простое приложение Flask в виртуальной среде Python. Вы создали точку входа WSGI, с которой может взаимодействовать любой сервер приложений с поддержкой WSGI, а затем настроили сервер приложения Gunicorn для обеспечения этой функции. После этого вы создали служебный файл systemd, который автоматически запускает сервер приложений при загрузке. Также вы создали серверный блок Nginx, который передает трафик веб-клиента на сервер приложений, перенаправляет внешние запросы и защищает трафик вашего сервера с помощью сертификата Let’s Encrypt.

      Flask — простая, но очень гибкая инфраструктура приложения, обеспечивающая работу приложений без значительных структурных ограничений. Вы можете использовать описанный в этом обучающем модуле комплекс для обслуживания разрабатываемых вами приложений flask.



      Source link

      Настройка Django с Postgres, Nginx и Gunicorn в Ubuntu 18.04


      Введение

      Django — это мощная веб-система, помогающая создать приложение или сайт Python с нуля. Django включает упрощенный сервер разработки для локального тестирования кода, однако для серьезных производственных задач требуется более защищенный и мощный веб-сервер.

      В этом руководстве мы покажем, как установить и настроить определенные компоненты Ubuntu 18.04 для поддержки и обслуживания приложений Django. Вначале мы создадим базу данных PostgreSQL вместо того, чтобы использовать базу данных по умолчанию SQLite. Мы настроим сервер приложений Gunicorn для взаимодействия с нашими приложениями. Затем мы настроим Nginx для работы в качестве обратного прокси-сервера Gunicorn, что даст нам доступ к функциям безопасности и повышения производительности для обслуживания наших приложений.

      Предварительные требования и цели

      Для прохождения этого обучающего модуля вам потребуется новый экземпляр сервера Ubuntu 18.04 с базовым брандмауэром и пользователем с привилегиями sudo и без привилегий root. Чтобы узнать, как настроить такой сервер, воспользуйтесь нашим модулем Руководство по начальной настройке сервера.

      Мы будем устанавливать Django в виртуальной среде. Установка Django в отдельную среду проекта позволит отдельно обрабатывать проекты и их требования.

      Когда база данных будет работать, мы выполним установку и настройку сервера приложений Gunicorn. Он послужит интерфейсом нашего приложения и будет обеспечивать преобразование запросов клиентов по протоколу HTTP в вызовы Python, которые наше приложение сможет обрабатывать. Затем мы настроим Nginx в качестве обратного прокси-сервера для Gunicorn, чтобы воспользоваться высокоэффективными механизмами обработки соединений и удобными функциями безопасности.

      Давайте приступим.

      Установка пакетов из хранилищ Ubuntu

      Чтобы начать данную процедуру нужно загрузить и установить все необходимые нам элементы из хранилищ Ubuntu. Для установки дополнительных компонентов мы немного позднее используем диспетчер пакетов Python pip.

      Нам нужно обновить локальный индекс пакетов apt, а затем загрузить и установить пакеты. Конкретный состав устанавливаемых пакетов зависит от того, какая версия Python будет использоваться в вашем проекте.

      Если вы используете Django с Python 3, введите:

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

      Версия Django 1.11 — последняя версия Django с поддержкой Python 2. Если вы создаете новый проект, мы настоятельно рекомендуем использовать Python 3. Если вам необходимо использовать Python 2, введите:

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

      Эта команда устанавливает pip, файлы разработки Python для последующего построения сервера Gunicorn, СУБД Postgres и необходимые для взаимодействия с ней библиотеки, а также веб-сервер Nginx.

      Создание базы данных и пользователя PostgreSQL

      Вначале мы создадим базу данных и пользователя базы данных для нашего приложения Django.

      По умолчанию Postgres использует для локальных соединений схему аутентификации «peer authentication». Это означает, что если имя пользователя операционной системы совпадает с действительным именем пользователя Postgres, этот пользователь может войти без дополнительной аутентификации.

      Во время установки Postgres был создан пользователь операционной системы с именем postgres, соответствующий пользователю postgres базы данных PostgreSQL, имеющему права администратора. Этот пользователь нам потребуется для выполнения административных задач. Мы можем использовать sudo и передать это имя пользователя с опцией -u.

      Выполните вход в интерактивный сеанс Postgres, введя следующую команду:

      Вы увидите диалог PostgreSQL, где можно будет задать наши требования.

      Вначале создайте базу данных для своего проекта:

      • CREATE DATABASE myproject;

      Примечание. Каждое выражение Postgres должно заканчиваться точкой с запятой. Если с вашей командой возникнут проблемы, проверьте это.

      Затем создайте пользователя базы данных для нашего проекта. Обязательно выберите безопасный пароль:

      • CREATE USER myprojectuser WITH PASSWORD 'password';

      Затем мы изменим несколько параметров подключения для только что созданного нами пользователя. Это ускорит работу базы данных, поскольку теперь при каждом подключении не нужно будет запрашивать и устанавливать корректные значения.

      Мы зададим кодировку по умолчанию UTF-8, чего и ожидает Django. Также мы зададим схему изоляции транзакций по умолчанию «read committed», которая будет блокировать чтение со стороны неподтвержденных транзакций. В заключение мы зададим часовой пояс. По умолчанию наши проекты Django настроены на использование времени по Гринвичу (UTC). Все эти рекомендации взяты из проекта 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';

      Теперь мы предоставим созданному пользователю доступ для администрирования новой базы данных:

      • GRANT ALL PRIVILEGES ON DATABASE myproject TO myprojectuser;

      Завершив настройку, закройте диалог PostgreSQL с помощью следующей команды:

      Теперь настройка Postgres завершена, и Django может подключаться к базе данных и управлять своей информацией в базе данных.

      Создание виртуальной среды Python для вашего проекта

      Мы создали базу данных, и теперь можем перейти к остальным требованиям нашего проекта. Для удобства управления мы установим наши требования Python в виртуальной среде.

      Для этого нам потребуется доступ к команде virtualenv. Для установки мы можем использовать pip.

      Если вы используете Python 3, обновите pip и установите пакет с помощью следующей команды:

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

      Если вы используете Python 2, обновите pip и установите пакет с помощью следующей команды:

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

      После установки virtualenv мы можем начать формирование нашего проекта. Создайте каталог для файлов нашего проекта и перейдите в этот каталог:

      • mkdir ~/myprojectdir
      • cd ~/myprojectdir

      Создайте в каталоге проекта виртуальную среду Python с помощью следующей команды:

      Эта команда создаст каталог myprojectenv в каталоге myprojectdir. В этот каталог будут установлены локальная версия Python и локальная версия pip. Мы можем использовать эту команду для установки и настройки изолированной среды Python для нашего проекта.

      Прежде чем установить требования Python для нашего проекта, необходимо активировать виртуальную среду. Для этого можно использовать следующую команду:

      • source myprojectenv/bin/activate

      Командная строка изменится, показывая, что теперь вы работаете в виртуальной среде Python. Она будет выглядеть примерно следующим образом: (myprojectenv)user@host:~/myprojectdir$.

      После запуска виртуальной среды установите Django, Gunicorn и адаптер psycopg2 PostgreSQL с помощью локального экземпляра pip:

      Примечание. Если виртуальная среда активна (когда перед командной строкой стоит (myprojectenv)), необходимо использовать pip вместо pip3, даже если вы используете Python 3. Копия инструмента в виртуальной среде всегда имеет имя pip вне зависимости от версии Python.

      • pip install django gunicorn psycopg2-binary

      Теперь у вас должно быть установлено все программное обеспечение, необходимое для запуска проекта Django.

      Создание и настройка нового проекта Django

      Установив компоненты Python, мы можем создать реальные файлы проекта Django.

      Создание проекта Django

      Поскольку у нас уже есть каталог проекта, мы укажем Django установить файлы в него. В этом каталоге будет создан каталог второго уровня с фактическим кодом (это нормально) и размещен скрипт управления. Здесь мы явно определяем каталог, а не даем Django принимать решения относительно текущего каталога:

      • django-admin.py startproject myproject ~/myprojectdir

      Сейчас каталог вашего проекта (в нашем случае ~/myprojectdir) должен содержать следующее:

      • ~/myprojectdir/manage.py: скрипт управления проектами Django.
      • ~/myprojectdir/myproject/: пакет проекта Django. В нем должны содержаться файлы __init__.py, settings.py, urls.py и wsgi.py.
      • ~/myprojectdir/myprojectenv/: виртуальный каталог, которы мы создали до этого.

      Изменение настроек проекта

      Прежде всего, необходимо изменить настройки созданных файлов проекта. Откройте файл настроек в текстовом редакторе:

      • nano ~/myprojectdir/myproject/settings.py

      Найдите директиву ALLOWED_HOSTS. Она определяет список адресов сервера или доменных имен, которые можно использовать для подключения к экземпляру Django. Любой входящий запрос с заголовком Host, не включенный в этот список, будет вызывать исключение. Django требует, чтобы вы использовали эту настройку, чтобы предотвратить использование определенного класса уязвимости безопасности.

      В квадратных скобках перечислите IP-адреса или доменные имена, связанные с вашим сервером Django. Каждый элемент должен быть указан в кавычках, отдельные записи должны быть разделены запятой. Если вы хотите включить в запрос весь домен и любые субдомены, добавьте точку перед началом записи. В следующем фрагменте кода для демонстрации в строках комментариев приведено несколько примеров:

      Примечание. Обязательно используйте localhost как одну из опций, поскольку мы будем использовать локальный экземпляр 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']
      

      Затем найдите раздел. который будет настраивать доступ к базе данных. Он будет начинаться со слова DATABASES. Конфигурация в файле предназначена для базы данных SQLite. Мы уже создали базу данных PostgreSQL для нашего проекта, и поэтому нужно изменить настройки.

      Измените настройки, указав параметры базы данных PostgreSQL. Мы укажем Django использовать адаптер psycopg2, который мы установили вместе с pip. Нам нужно указать имя базы данных, имя пользователя базы данных, пароль пользователя базы данных, и указать, что база данных расположена на локальном компьютере. Вы можете оставить для параметра PORT пустую строку:

      ~/myprojectdir/myproject/settings.py

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

      Затем перейдите в конец файла и добавьте параметр, указывающий, где следует разместить статичные файлы. Это необходимо, чтобы Nginx мог обрабатывать запросы для этих элементов. Следующая строка указывает Django, что они помещаются в каталог static в базовом каталоге проекта:

      ~/myprojectdir/myproject/settings.py

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

      Сохраните файл и закройте его после завершения.

      Завершение начальной настройки проекта

      Теперь мы можем перенести начальную схему базы данных для нашей базы данных PostgreSQL, используя скрипт управления:

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

      Создайте административного пользователя проекта с помощью следующей команды:

      • ~/myprojectdir/manage.py createsuperuser

      Вам нужно будет выбрать имя пользователя, указать адрес электронной почты, а затем задать и подтвердить пароль.

      Мы можем собрать весь статичный контент в заданном каталоге с помощью следующей команды:

      • ~/myprojectdir/manage.py collectstatic

      Данную операцию нужно будет подтвердить. Статичные файлы будут помещены в каталог static в каталоге вашего проекта.

      Если вы следовали указаниям модуля по начальной настройке сервера, ваш сервер должен защищать брандмауэр UFW. Чтобы протестировать сервер разработки, необходимо разрешить доступ к порту, который мы будем использовать.

      Создайте исключение для порта 8000 с помощью следующей команды:

      Теперь вы можете протестировать ваш проект, запустив сервер разработки Django с помощью следующей команды:

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

      Откройте в браузере доменное имя или IP-адрес вашего сервера с суффиксом :8000:

      http://server_domain_or_IP:8000
      

      Вы увидите страницу индекса Django по умолчанию:

      Страница индекса Django

      Если вы добавите /admin в конце URL в панели адреса, вам будет предложено ввести имя пользователя и пароль администратора, созданные с помощью команды createsuperuser:

      Вход в панель администратора Django

      После аутентификации вы получите доступ к интерфейсу администрирования Django по умолчанию:

      Интерфейс администрирования Django

      Завершив изучение, нажмите CTRL+C в окне терминала, чтобы завершить работу сервера разработки.

      Тестирование способности Gunicorn обслуживать проект

      Перед выходом из виртуальной среды нужно протестировать способность Gunicorn обслуживать приложение. Для этого нам нужно войти в каталог нашего проекта и использовать gunicorn для загрузки модуля WSGI проекта:

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

      Gunicorn будет запущен на том же интерфейсе, на котором работал сервер разработки Django. Теперь вы можете вернуться и снова протестировать приложение.

      Примечание. В интерфейсе администратора не будут применяться в стили, поскольку Gunicorn неизвестно, как находить требуемый статичный контент CSS.

      Мы передали модуль в Gunicorn, указав относительный путь к файлу Django wsgi.py, который представляет собой точку входа в наше приложение. Для этого мы использовали синтаксис модуля Python. В этом файле определена функция application, которая используется для взаимодействия с приложением. Дополнительную информацию о спецификации WSGI можно найти здесь.

      После завершения тестирования нажмите CTRL+C в окне терминала, чтобы остановить работу Gunicorn.

      Мы завершили настройку нашего приложения Django. Теперь мы можем выйти из виртуальной среды с помощью следующей команды:

      Индикатор виртуальной среды будет убран из командной строки.

      Создание файлов сокета и служебных файлов systemd для Gunicorn

      Мы убедились, что Gunicorn может взаимодействовать с нашим приложением Django, но теперь нам нужно реализовать более надежный способ запуска и остановки сервера приложений. Для этого мы создадим служебные файлы и файлы сокета systemd.

      Сокет Gunicorn создается при загрузке и прослушивает подключения. При подключении systemd автоматически запускает процесс Gunicorn для обработки подключения.

      Создайте и откройте файл сокета systemd для Gunicorn с привилегиями sudo:

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

      В этом файле мы создадим раздел [Unit] для описания сокета, раздел [Socket] для определения расположения сокета и раздел [Install], чтобы обеспечить установку сокета в нужное время:

      /etc/systemd/system/gunicorn.socket

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

      Сохраните файл и закройте его после завершения.

      Теперь создайте и откройте служебный файл systemd для Gunicorn в текстовом редакторе с привилегиями sudo. Имя файла службы должно соответствовать имени файла сокета за исключением расширения:

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

      Начните с раздела [Unit], предназначенного для указания метаданных и зависимостей. Здесь мы разместим описание службы и предпишем системе инициализации запускать ее только после достижения сетевой цели: Поскольку наша служба использует сокет из файла сокета, нам потребуется директива Requires, чтобы задать это отношение:

      /etc/systemd/system/gunicorn.service

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

      Теперь откроем раздел [Service]. Здесь указываются пользователь и группа, от имени которых мы хотим запустить данный процесс. Мы сделаем владельцем процесса учетную запись обычного пользователя, поскольку этот пользователь является владельцем всех соответствующих файлов. Групповым владельцем мы сделаем группу www-data, чтобы Nginx мог легко взаимодействовать с Gunicorn.

      Затем мы составим карту рабочего каталога и зададим команду для запуска службы. В данном случае мы укажем полный путь к исполняемому файлу Gunicorn, установленному в нашей виртуальной среде. Мы привяжем процесс к сокету Unix, созданному в каталоге /run, чтобы процесс мог взаимодействовать с Nginx. Мы будем регистрировать все данные на стандартном выводе, чтобы процесс journald мог собирать журналы Gunicorn. Также здесь можно указать любые необязательные настройки Gunicorn. Например, в данном случае мы задали 3 рабочих процесса:

      /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]. Это покажет systemd, куда привязывать эту службу, если мы активируем ее запуск при загрузке. Нам нужно, чтобы эта служба запускалась во время работы обычной многопользовательской системы:

      /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
      

      Теперь служебный файл systemd готов. Сохраните и закройте его.

      Теперь мы можем запустить и активировать сокет Gunicorn. Файл сокета /run/gunicorn.sock будет создан сейчас и будет создаваться при загрузке. При подключении к этому сокету systemd автоматически запустит gunicorn.service для его обработки:

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

      Успешность операции можно подтвердить, проверив файл сокета.

      Проверка файла сокета Gunicorn

      Проверьте состояние процесса, чтобы узнать, удалось ли его запустить:

      • sudo systemctl status gunicorn.socket

      Затем проверьте наличие файла gunicorn.sock в каталоге /run:

      Output

      /run/gunicorn.sock: socket

      Если команда systemctl status указывает на ошибку, или если в каталоге отсутствует файл gunicorn.sock, это означает, что сокет Gunicorn не удалось создать. Проверьте журналы сокета Gunicorn с помощью следующей команды:

      • sudo journalctl -u gunicorn.socket

      Еще раз проверьте файл /etc/systemd/system/gunicorn.socket и устраните любые обнаруженные проблемы, прежде чем продолжить.

      Тестирование активации сокета

      Если вы запустили только gunicorn.socket, служба gunicorn.service не будет активна в связи с отсутствием подключений к совету. Для проверки можно ввести следующую команду:

      • sudo systemctl status gunicorn

      Output

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

      Чтобы протестировать механизм активации сокета, установим соединение с сокетом через curl с помощью следующей команды:

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

      Выводимые данные приложения должны отобразиться в терминале в формате HTML. Это показывает, что Gunicorn запущен и может обслуживать ваше приложение Django. Вы можете убедиться, что служба Gunicorn работает, с помощью следующей команды:

      • sudo systemctl status gunicorn

      Output

      ● gunicorn.service - gunicorn daemon Loaded: loaded (/etc/systemd/system/gunicorn.service; disabled; vendor preset: enabled) Active: active (running) since Mon 2018-07-09 20:00:40 UTC; 4s ago Main PID: 1157 (gunicorn) Tasks: 4 (limit: 1153) CGroup: /system.slice/gunicorn.service ├─1157 /home/sammy/myprojectdir/myprojectenv/bin/python3 /home/sammy/myprojectdir/myprojectenv/bin/gunicorn --access-logfile - --workers 3 --bind unix:/run/gunicorn.sock myproject.wsgi:application ├─1178 /home/sammy/myprojectdir/myprojectenv/bin/python3 /home/sammy/myprojectdir/myprojectenv/bin/gunicorn --access-logfile - --workers 3 --bind unix:/run/gunicorn.sock myproject.wsgi:application ├─1180 /home/sammy/myprojectdir/myprojectenv/bin/python3 /home/sammy/myprojectdir/myprojectenv/bin/gunicorn --access-logfile - --workers 3 --bind unix:/run/gunicorn.sock myproject.wsgi:application └─1181 /home/sammy/myprojectdir/myprojectenv/bin/python3 /home/sammy/myprojectdir/myprojectenv/bin/gunicorn --access-logfile - --workers 3 --bind unix:/run/gunicorn.sock myproject.wsgi:application Jul 09 20:00:40 django1 systemd[1]: Started gunicorn daemon. Jul 09 20:00:40 django1 gunicorn[1157]: [2018-07-09 20:00:40 +0000] [1157] [INFO] Starting gunicorn 19.9.0 Jul 09 20:00:40 django1 gunicorn[1157]: [2018-07-09 20:00:40 +0000] [1157] [INFO] Listening at: unix:/run/gunicorn.sock (1157) Jul 09 20:00:40 django1 gunicorn[1157]: [2018-07-09 20:00:40 +0000] [1157] [INFO] Using worker: sync Jul 09 20:00:40 django1 gunicorn[1157]: [2018-07-09 20:00:40 +0000] [1178] [INFO] Booting worker with pid: 1178 Jul 09 20:00:40 django1 gunicorn[1157]: [2018-07-09 20:00:40 +0000] [1180] [INFO] Booting worker with pid: 1180 Jul 09 20:00:40 django1 gunicorn[1157]: [2018-07-09 20:00:40 +0000] [1181] [INFO] Booting worker with pid: 1181 Jul 09 20:00:41 django1 gunicorn[1157]: - - [09/Jul/2018:20:00:41 +0000] "GET / HTTP/1.1" 200 16348 "-" "curl/7.58.0"

      Если результат вывода curl или systemctl status указывают на наличие проблемы, поищите в журналах более подробные данные:

      • sudo journalctl -u gunicorn

      Проверьте файл /etc/systemd/system/gunicorn.service на наличие проблем. Если вы внесли изменения в файл /etc/systemd/system/gunicorn.service, перезагрузите демона, чтобы заново считать определение службы, и перезапустите процесс Gunicorn с помощью следующей команды:

      • sudo systemctl daemon-reload
      • sudo systemctl restart gunicorn

      Обязательно устраните вышеперечисленные проблемы, прежде чем продолжить.

      Настройка Nginx как прокси для Gunicorn

      Мы настроили Gunicorn, и теперь нам нужно настроить Nginx для передачи трафика в процесс.

      Для начала нужно создать и открыть новый серверный блок в каталоге Nginx sites-available:

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

      Откройте внутри него новый серверный блок. Вначале мы укажем, что этот блок должен прослушивать обычный порт 80, и что он должен отвечать на доменное имя или IP-адрес нашего сервера:

      /etc/nginx/sites-available/myproject

      server {
          listen 80;
          server_name server_domain_or_IP;
      }
      

      Затем мы укажем Nginx игнорировать любые проблемы при поиске favicon. Также мы укажем, где можно найти статичные ресурсы, собранные нами в каталоге ~/myprojectdir/static. Все эти строки имеют стандартный префикс URI «/static», так что мы можем создать блок location для соответствия этим запросам:

      /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 / {} для соответствия всем другим запросам. В этот блок мы включим стандартный файл proxy_params, входящий в комплект установки Nginx, и тогда трафик будет передаваться напрямую на сокет 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;
          }
      }
      

      Сохраните файл и закройте его после завершения. Теперь мы можем активировать файл, привязав его к каталогу sites-enabled:

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

      Протестируйте конфигурацию Nginx на ошибки синтаксиса:

      Если ошибок не будет найдено, перезапустите Nginx с помощью следующей команды:

      • sudo systemctl restart nginx

      Нам нужна возможность открыть брандмауэр для обычного трафика через порт 80. Поскольку нам больше не потребуется доступ к серверу разработки, мы можем удалить правило и открыть порт 8000:

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

      Теперь у вас должна быть возможность перейти к домену или IP-адресу вашего сервера для просмотра вашего приложения.

      Примечание. После настройки Nginx необходимо защитить трафик на сервер с помощью SSL/TLS. Это важно, поскольку в противном случае вся информация, включая пароли, будет отправляться через сеть в простом текстовом формате.

      Если у вас имеется доменное имя, проще всего будет использовать Let’s Encrypt для получения сертификата SSL для защиты вашего трафика. Следуйте указаниям этого руководства, чтобы настроить Let’s Encrypt с Nginx в Ubuntu 18.04. Следуйте процедуре, используя серверный блок Nginx, созданный нами в этом обучающем модуле.

      Если у вас нет доменного имени, вы можете защитить свой сайт для тестирования и обучения с помощью сертификата SSL с собственной подписью. Следуйте процедуре, используя серверный блок Nginx, созданный нами в этом обучающем модуле.

      Диагностика и устранение неисправностей Nginx и Gunicorn

      Если на последнем шаге не будет показано ваше приложение, вам нужно будет провести диагностику и устранение неисправностей установки.

      Nginx показывает страницу по умолчанию, а не приложение Django

      Если Nginx показывает страницу по умолчанию, а не выводит ваше приложение через прокси, это обычно означает, что вам нужно изменить параметр server_name в файле /etc/nginx/sites-available/myproject, чтобы он указывал на IP-адрес или доменное имя вашего сервера.

      Nginx использует server_name, чтобы определять, какой серверный блок использовать для ответа на запросы. Если вы увидите страницу Nginx по умолчанию, это будет означать, что Nginx не может найти явное соответствие запросу в серверном блоке и выводит блок по умолчанию, заданный в /etc/nginx/sites-available/default.

      Параметр server_name в серверном блоке вашего проекта должен быть более конкретным, чем содержащийся в серверном блоке, выбираемом по умолчанию.

      Nginx выводит ошибку 502 Bad Gateway вместо приложения Django

      Ошибка 502 означает, что Nginx не может выступать в качестве прокси для запроса. Ошибка 502 может сигнализировать о разнообразных проблемах конфигурации, поэтому для диагностики и устранения неисправности потребуется больше информации.

      В первую очередь эту информацию следует искать в журналах ошибок Nginx. Обычно это указывает, какие условия вызвали проблемы во время прокси-обработки. Изучите журналы ошибок Nginx с помощью следующей команды:

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

      Теперь выполните в браузере еще один запрос, чтобы получить свежее сообщение об ошибке (попробуйте обновить страницу). В журнал будет записано свежее сообщение об ошибке. Если вы изучите его, это поможет идентифицировать проблему.

      Возможно вы увидите сообщение следующего вида:

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

      Это означает, что Nginx не удалось найти файл gunicorn.sock в указанном месте. Вы должны сравнить расположение proxy_pass, определенное в файле etc/nginx/sites-available/myproject, с фактическим расположением файла gunicorn.sock, сгенерированным блоком systemd gunicorn.socket.

      Если вы не можете найти файл gunicorn.sock в каталоге /run, это означает, что файл сокета systemd не смог его создать. Вернитесь к разделу проверки файла сокета Gunicorn и выполните процедуру диагностики и устранения неисправностей Gunicorn.

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

      Это означает, что Nginx не удалось подключиться к сокету Gunicorn из-за проблем с правами доступа. Это может произойти, если процедуру выполнять с привилегиями root, а не с привилегиями sudo. Хотя systemd может создать файл сокета Gunicorn, Nginx не может получить к нему доступ.

      Это может произойти из-за ограничения прав доступа в любом месте между корневым каталогом (/) и файлом gunicorn.sock. Чтобы увидеть права доступа и владельцев файла сокета и всех его родительских каталогов, нужно ввести абсолютный путь файла сокета как параметр команды 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

      Команда выведет права доступа всех компонентов каталога. Изучив права доступа (первый столбец), владельца (второй столбец) и группового владельца (третий столбец), мы можем определить, какой тип доступа разрешен для файла сокета.

      В приведенном выше примере для файла сокета и каждого из каталогов пути к файлу сокета установлены всеобщие права доступа на чтение и исполнение (запись в столбце разрешений каталогов заканчивается на r-x, а не на ---). Процесс Nginx должен успешно получить доступ к сокету.

      Если для любого из каталогов, ведущих к сокету, отсутствуют глобальные разрешения на чтение и исполнение, Nginx не сможет получить доступ к сокету без включения таких разрешений или без передачи группового владения группе, в которую входит Nginx.

      Django выводит ошибку: «could not connect to server: Connection refused»

      При попытке доступа к частям приложения через браузер Django может вывести сообщение следующего вида:

      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?
      

      Это означает, что Django не может подключиться к базе данных Postgres. Убедиться в нормальной работе экземпляра Postgres с помощью следующей команды:

      • sudo systemctl status postgresql

      Если он работает некорректно, вы можете запустить его и включить автоматический запуск при загрузке (если эта настройка еще не задана) с помощью следующей команды:

      • sudo systemctl start postgresql
      • sudo systemctl enable postgresql

      Если проблемы не исчезнут, проверьте правильность настроек базы данных, заданных в файле ~/myprojectdir/myproject/settings.py.

      Дополнительная диагностика и устранение неисправностей

      В случае обнаружения дополнительных проблем журналы могут помочь в поиске первопричин. Проверяйте их по очереди и ищите сообщения, указывающие на проблемные места.

      Следующие журналы могут быть полезными:

      • Проверьте журналы процессов Nginx с помощью команды: sudo journalctl -u nginx
      • Проверьте журналы доступа Nginx с помощью команды: sudo less /var/log/nginx/access.log
      • Проверьте журналы ошибок Nginx с помощью команды: sudo less /var/log/nginx/error.log
      • Проверьте журналы приложения Gunicorn с помощью команды: sudo journalctl -u gunicorn
      • Проверьте журналы сокета Gunicorn с помощью команды: sudo journalctl -u gunicorn.socket

      При обновлении конфигурации или приложения вам может понадобиться перезапустить процессы для адаптации к изменениям.

      Если вы обновите свое приложение Django, вы можете перезапустить процесс Gunicorn для адаптации к изменениям с помощью следующей команды:

      • sudo systemctl restart gunicorn

      Если вы измените файл сокета или служебные файлы Gunicorn, перезагрузите демона и перезапустите процесс с помощью следующей команды:

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

      Если вы измените конфигурацию серверного блока Nginx, протестируйте конфигурацию и Nginx с помощью следующей команды:

      • sudo nginx -t && sudo systemctl restart nginx

      Эти команды помогают адаптироваться к изменениям в случае изменения конфигурации.

      Заключение

      В этом руководстве мы создали и настроили проект Django в его собственной виртуальной среде. Мы настроили Gunicorn для трансляции запросов клиентов, чтобы Django мог их обрабатывать. Затем мы настроили Nginx в качестве обратного прокси-сервера для обработки клиентских соединений и вывода проектов, соответствующих запросам клиентов.

      Django упрощает создание проектов и приложений, предоставляя множество стандартных элементов и позволяя сосредоточиться на уникальных. Используя описанную в этой статье процедуру, вы сможете легко обслуживать создаваемые приложения на одном сервере.



      Source link