Как обслуживать колбу с помощью Gunicorn и Nginx в Ubuntu 18.04

Вступление

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

Предпосылки

Прежде чем начать это руководство, вы должны иметь:

  • Сервер с установленной Ubuntu 18.04 и пользователем без полномочий root с привилегиями sudo. Следуйте нашимinitial server setup guide за руководством.

  • Nginx установлен в соответствии с шагами 1 и 2How To Install Nginx on Ubuntu 18.04.

  • Доменное имя настроено так, чтобы оно указывало на ваш сервер. Вы можете приобрести один наNamecheap или получить бесплатно наFreenom. Вы можете узнать, как указать домены на DigitalOcean, следуя соответствующимdocumentation on domains and DNS. Обязательно создайте следующие записи DNS:

    • Запись A сyour_domain, указывающая на общедоступный IP-адрес вашего сервера.

    • Запись A сwww.your_domain, указывающая на общедоступный IP-адрес вашего сервера.

  • Знакомство со спецификацией WSGI, которую сервер Gunicorn будет использовать для связи с вашим приложением Flask. This discussion более подробно описывает WSGI.

[[step-1 -—- install-the-components-from-the-ubuntu-repositories]] == Шаг 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

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

[[step-2 -—- created-a-python-virtual-environment]] == Шаг 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$.

[[step-3 -—- setting-up-a-flask-application]] == Шаг 3 - Настройка приложения Flask

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

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

pip install wheel

Note

[.note] # Независимо от того, какую версию Python вы используете, когда виртуальная среда активирована, вы должны использовать командуpip (неpip3).
#

Далее давайте установим Flask и Gunicorn:

pip install gunicorn 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 "

Hello There!

" if __name__ == "__main__": app.run(host='0.0.0.0')

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

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

sudo ufw allow 5000

Теперь вы можете проверить свое приложение Flask, набрав:

python myproject.py

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

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 sample app

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

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

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

Назовем файлwsgi.py:

nano ~/myproject/wsgi.py

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

~/myproject/wsgi.py

from myproject import app

if __name__ == "__main__":
    app.run()

Сохраните и закройте файл, когда вы закончите.

[[step-4 -—- configuring-gunicorn]] == Шаг 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 sample app

Убедившись, что он работает правильно, нажмитеCTRL-C в окне терминала.

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

deactivate

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

Далее, давайте создадим файл модуля службы 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 рабочих процесса (хотя вы должны настроить это по мере необходимости)

  • Создайте файл сокета Unixmyproject.sock и выполните привязку к нему в каталоге нашего проекта. Мы установим значение umask007, чтобы файл сокета был создан, предоставляя доступ владельцу и группе, ограничивая при этом другой доступ.

  • Укажите имя файла точки входа 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

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

[[step-5 -—- configuring-nginx-to-proxy-requests]] == Шаг 5 - Настройка Nginx для запросов прокси

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

Начните с создания нового файла конфигурации серверного блока в каталоге Nginxsites-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

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

sudo nginx -t

Если это возвращается без указания каких-либо проблем, перезапустите процесс Nginx, чтобы прочитать новую конфигурацию:

sudo systemctl restart nginx

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

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

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

http://your_domain

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

Flask sample app

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

  • 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-приложения.

[[step-6 -—-security-the-application]] == Шаг 6 - Защита приложения

Чтобы обеспечить безопасность трафика на вашем сервере, давайте получим SSL-сертификат для вашего домена. Есть несколько способов сделать это, в том числе получить бесплатный сертификат отLet’s Encrypt,generating a self-signed certificate илиbuying one from another provider и настроить Nginx для его использования, выполнив шаги со 2 по 6 изHow to Create a Self-signed SSL Certificate for Nginx in 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, чтобы указать имена, для которых мы хотим, чтобы сертификат был действительным.

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

В случае успехаcertbot спросит, как вы хотите настроить параметры HTTPS:

OutputPlease 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 завершится сообщением о том, что процесс прошел успешно и где хранятся ваши сертификаты:

OutputIMPORTANT 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 Encrypt.

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

Related