Как обслуживать приложения Flask с помощью uWSGI и Nginx в Ubuntu 18.04

Вступление

В этом руководстве вы создадите приложение Python с использованием микросхемы Flask в Ubuntu 18.04. Основная часть этой статьи будет посвящена настройкеuWSGI 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-адрес вашего сервера.

  • Знакомство с uWSGI, нашим сервером приложений и спецификацией WSGI. This discussion определений и концепций подробно рассматривает оба аспекта.

[[step-1 -—- install-the-components-from-the-ubuntu-repositories]] == Шаг 1. Установка компонентов из репозиториев Ubuntu

Нашим первым шагом будет установка всех необходимых нам частей из репозиториев Ubuntu. Мы установимpip, менеджер пакетов Python, для управления нашими компонентами Python. Мы также получим файлы для разработки на Python, необходимые для сборки uWSGI.

Во-первых, давайте обновим локальный индекс пакетов и установим пакеты, которые позволят нам построить нашу среду 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 и uWSGI и приступить к разработке вашего приложения.

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

pip install wheel

Note

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

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

pip install uwsgi 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

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

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

nano ~/myproject/wsgi.py

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

~/myproject/wsgi.py

from myproject import app

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

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

[[step-4 -—- configuring-uwsgi]] == Шаг 4. Настройка uWSGI

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

Тестирование uWSGI Serving

Давайте проверим, чтобы uWSGI мог обслуживать наше приложение.

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

Давайте также укажем сокет, чтобы он запускался на общедоступном интерфейсе, а также протокол, чтобы он использовал HTTP вместо двоичного протоколаuwsgi. Мы будем использовать тот же номер порта,5000, который мы открыли ранее:

uwsgi --socket 0.0.0.0:5000 --protocol=http -w wsgi:app

Посетите IP-адрес вашего сервера, добавив:5000 в конец в вашем браузере еще раз:

http://your_server_ip:5000

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

Flask sample app

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

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

deactivate

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

Создание файла конфигурации uWSGI

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

Поместим этот файл в каталог нашего проекта и назовем егоmyproject.ini:

nano ~/myproject/myproject.ini

Внутри мы начнем с заголовка[uwsgi], чтобы uWSGI знал, как применить настройки. Мы укажем две вещи: сам модуль, ссылаясь на файлwsgi.py без расширения, и вызываемый объект в файлеapp:

~/myproject/myproject.ini

[uwsgi]
module = wsgi:app

Далее мы скажем uWSGI запустить в режиме master и запустить пять рабочих процессов для обслуживания текущих запросов:

~/myproject/myproject.ini

[uwsgi]
module = wsgi:app

master = true
processes = 5

Когда вы тестировали, вы выставили uWSGI на сетевой порт. Однако вы будете использовать Nginx для обработки реальных клиентских подключений, которые затем будут передавать запросы в uWSGI. Поскольку эти компоненты работают на одном компьютере, предпочтительнее использовать сокет Unix, поскольку он быстрее и безопаснее. Назовем сокетmyproject.sock и поместим его в этот каталог.

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

~/myproject/myproject.ini

[uwsgi]
module = wsgi:app

master = true
processes = 5

socket = myproject.sock
chmod-socket = 660
vacuum = true

Последнее, что мы сделаем, это установим параметрdie-on-term. Это может помочь гарантировать, что система инициализации и uWSGI имеют одинаковые предположения о том, что означает каждый сигнал процесса. Установка этого выравнивает два системных компонента, реализуя ожидаемое поведение:

~/myproject/myproject.ini

[uwsgi]
module = wsgi:app

master = true
processes = 5

socket = myproject.sock
chmod-socket = 660
vacuum = true

die-on-term = true

Возможно, вы заметили, что мы не указали протокол, как мы это сделали из командной строки. Это потому, что по умолчанию uWSGI использует протоколuwsgi, быстрый двоичный протокол, предназначенный для связи с другими серверами. Nginx может говорить по этому протоколу изначально, поэтому лучше использовать его, чем форсировать связь по HTTP.

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

[[step-5 -—- created-a-systemd-unit-file]] == Шаг 5. Создание файла модуля systemd

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

Для начала создайте файл модуля, заканчивающийся на.service, в каталоге/etc/systemd/system:

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

Внутри мы начнем с раздела[Unit], который используется для указания метаданных и зависимостей. Давайте разместим здесь описание нашего сервиса и скажем системе инициализации запускать его только после достижения сетевой цели:

/etc/systemd/system/myproject.service

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

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

/etc/systemd/system/myproject.service

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

[Service]
User=sammy
Group=www-data

Затем давайте наметим рабочий каталог и установим переменную средыPATH, чтобы система инициализации знала, что исполняемые файлы для процесса находятся в нашей виртуальной среде. Давайте также укажем команду для запуска службы. Systemd требует, чтобы мы указали полный путь к исполняемому файлу uWSGI, который установлен в нашей виртуальной среде. Мы передадим имя файла конфигурации.ini, который мы создали в каталоге нашего проекта.

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

/etc/systemd/system/myproject.service

[Unit]
Description=uWSGI 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/uwsgi --ini myproject.ini

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

/etc/systemd/system/myproject.service

[Unit]
Description=uWSGI 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/uwsgi --ini myproject.ini

[Install]
WantedBy=multi-user.target

На этом наш сервисный файл systemd завершен. Сохраните и закройте его сейчас.

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

sudo systemctl start myproject
sudo systemctl enable myproject

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

sudo systemctl status myproject

Вы должны увидеть результат примерно так:

Output● myproject.service - uWSGI 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: 30360 (uwsgi)
    Tasks: 6 (limit: 1153)
   CGroup: /system.slice/myproject.service
           ├─30360 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.ini
           ├─30378 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.ini
           ├─30379 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.ini
           ├─30380 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.ini
           ├─30381 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.ini
           └─30382 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.ini

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

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

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

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

Далее, давайте добавим блок местоположения, который соответствует каждому запросу. В этот блок мы включим файлuwsgi_params, который определяет некоторые общие параметры uWSGI, которые необходимо установить. Затем мы передадим запросы в сокет, который мы определили с помощью директивыuwsgi_pass:

/etc/nginx/sites-available/myproject

server {
    listen 80;
    server_name your_domain www.your_domain;

    location / {
        include uwsgi_params;
        uwsgi_pass 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: проверяет журналы uWSGI вашего приложения Flask.

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

Чтобы обеспечить безопасность трафика на вашем сервере, давайте получим 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 мог взаимодействовать с ней, а затем настроили сервер приложений uWSGI для предоставления этой функции. После этого вы создали файл службы systemd для автоматического запуска сервера приложений при загрузке. Вы также создали серверный блок Nginx, который передает трафик веб-клиента на сервер приложений, ретранслирует внешние запросы и защищенный трафик на ваш сервер с помощью Let Encrypt.

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

Related