Как обслуживать приложения Flask с помощью uWSGI и Nginx в Ubuntu 18.04
Введение
В этом руководстве вы создадите приложение Python с использованием микрофреймворка Flask в Ubuntu 18.04. Основная часть этой статьи будет посвящена тому, как настроить Nginx для работы в качестве внешнего обратного прокси-сервера.
Предпосылки
Для выполнения этого урока вам понадобятся:
- Сервер с установленной Ubuntu 18.04 и пользователем без полномочий root с привилегиями sudo и включенным брандмауэром. Следуйте нашему руководству по первоначальной настройке сервера.
- Nginx установлен, следуя шагам 1 и 2 инструкции по установке Nginx в Ubuntu 18.04.
- Доменное имя, настроенное так, чтобы оно указывало на ваш сервер. Вы можете приобрести его в документации по доменам и DNS. Обязательно создайте следующие записи DNS:
- Запись A с
your_domain
, указывающая на общедоступный IP-адрес вашего сервера. - Запись A с
www.your_domain
, указывающая на общедоступный IP-адрес вашего сервера.
Знакомство с uWSGI, нашим сервером приложений и спецификацией WSGI. В этом обсуждении определений и понятий подробно рассматривается и то, и другое.
Шаг 1 — Установка компонентов из репозиториев Ubuntu
Первый шаг — установить все необходимые компоненты из репозиториев Ubuntu. Вы установите
pip
, менеджер пакетов Python, для управления компонентами Python. Вы также получите файлы разработки Python, необходимые для сборки uWSGI.Сначала обновите локальный индекс пакета:
- sudo apt update
Затем установите пакеты, которые позволят вам создать среду Python. Они будут включать
python3-pip
, а также еще несколько пакетов и инструментов разработки, необходимых для надежной среды программирования:- 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 и uWSGI и приступить к разработке своего приложения.
Сначала установите
wheel
с локальным экземпляромpip
, чтобы убедиться, что ваши пакеты будут установлены, даже если в них отсутствуют архивы колес:- pip install wheel
Примечание. Независимо от используемой версии Python при активации виртуальной среды следует использовать команду
pip
(неpip3
).Затем установите Flask и uWSGI:
- pip install uwsgi flask
После завершения установки вы можете начать использовать Flask.
Создание примера приложения
Теперь, когда у вас есть Flask, вы можете создать простое приложение. Как вы, возможно, помните, Flask — это микрофреймворк, в котором нет многих инструментов, которые могли бы быть в более полнофункциональных фреймворках. Flask существует в основном как модуль, который вы можете импортировать в свои проекты, чтобы помочь вам в инициализации веб-приложения.
Хотя ваше приложение может быть более сложным, вы создадите приложение Flask в одном файле. Вы можете создать файл с помощью вашего любимого текстового редактора. В этом примере мы будем использовать
nano
и назовем егоmyproject.py
:- nano ~/myproject/myproject.py
Код приложения будет жить в этом файле. Он импортирует Flask и создаст экземпляр объекта Flask. Вы можете использовать это для определения функций, которые должны запускаться при запросе определенного маршрута:
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')
Это определяет, какой контент будет отображаться при доступе к корневому домену. Сохраните и закройте файл, когда закончите. Если вы используете
nano
, вы можете сделать это, нажавCTRL + X
, затемY
иENTER
.Если вы следовали руководству по первоначальной настройке сервера, у вас должен быть включен брандмауэр 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
Вы должны увидеть что-то вроде следующего:
Когда вы закончите, нажмите
CTRL + C
в окне терминала, чтобы остановить сервер разработки Flask.Создание точки входа WSGI
Далее вы создадите файл, который будет служить точкой входа для вашего приложения. Это сообщит вашему серверу uWSGI, как с ним взаимодействовать.
Сначала создайте и назовите файл
wsgi.py
:- nano ~/myproject/wsgi.py
В этом файле импортируйте экземпляр Flask из вашего приложения, а затем запустите его:
from myproject import app if __name__ == "__main__": app.run()
Сохраните и закройте файл, когда закончите.
Шаг 4 — Настройка uWSGI
Теперь ваше приложение написано с установленной точкой входа. Теперь вы можете перейти к настройке uWSGI.
Тестирование обслуживания uWSGI
Прежде чем вносить дополнительные изменения, может быть полезно проверить, может ли uWSGI обслуживать ваше приложение.
Вы можете сделать это, передав имя вашей точки входа в 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
Вы должны снова получить вывод вашего приложения:
Убедившись, что он работает правильно, нажмите
CTRL + C
в окне терминала.Теперь, когда вы закончили работу с виртуальной средой, вы можете деактивировать ее:
- deactivate
Любые команды Python теперь снова будут использовать системную среду Python.
Создание файла конфигурации uWSGI
Вы протестировали и подтвердили, что uWSGI может обслуживать ваше приложение, но в конечном итоге вам понадобится что-то более надежное для длительного использования. Вы можете создать файл конфигурации uWSGI с соответствующими параметрами для этого.
Поместите этот файл в каталог вашего проекта и назовите его
myproject.ini
:- nano ~/myproject/myproject.ini
Внутри вы начнете с заголовка
[uwsgi]
, чтобы uWSGI знал, как применить настройки. Вы укажете две вещи: сам модуль, ссылаясь на файлwsgi.py
без расширения, и вызываемое в файлеapp
:[uwsgi] module = wsgi:app
Затем скажите uWSGI запуститься в режиме мастера и создать пять рабочих процессов для обслуживания фактических запросов:
[uwsgi] module = wsgi:app master = true processes = 5
Во время тестирования вы выставили uWSGI на сетевой порт. Однако вы будете использовать Nginx для обработки реальных клиентских подключений, которые затем будут передавать запросы в uWSGI. Поскольку эти компоненты работают на одном компьютере, сокет Unix предпочтительнее, поскольку он быстрее и безопаснее. Вызовите сокет
myproject.sock
и поместите его в этот каталог.Также измените разрешения на сокете. Это дает группе Nginx право собственности на процесс uWSGI позже, поэтому убедитесь, что владелец группы сокета может читать информацию из него и записывать в него. Кроме того, очистите сокет, когда процесс остановится, добавив параметр
vacuum
:[uwsgi] module = wsgi:app master = true processes = 5 socket = myproject.sock chmod-socket = 660 vacuum = true
Последнее, что вам нужно сделать, это установить параметр
умереть на срок
. Это может помочь гарантировать, что система инициализации и uWSGI имеют одинаковые предположения о том, что означает каждый сигнал процесса. Установка этого параметра выравнивает два системных компонента, реализуя ожидаемое поведение:[uwsgi] module = wsgi:app master = true processes = 5 socket = myproject.sock chmod-socket = 660 vacuum = true die-on-term = true
Вы могли заметить, что не указали протокол, как в командной строке. Это связано с тем, что по умолчанию uWSGI использует протокол
uwsgi
, быстрый двоичный протокол, предназначенный для связи с другими серверами. Nginx может говорить по этому протоколу нативно, поэтому лучше использовать его, чем навязывать связь по HTTP.Когда вы закончите, сохраните и закройте файл.
Шаг 5 — Создание файла модуля systemd
Затем создайте файл сервисной единицы systemd. Создание файла модуля systemd позволит системе инициализации Ubuntu автоматически запускать uWSGI и обслуживать приложение Flask при каждой загрузке сервера.
Создайте юнит-файл, оканчивающийся на
.service
, в каталоге/etc/systemd/system
, чтобы начать:- sudo nano /etc/systemd/system/myproject.service
Внутри файла начните с раздела
[Unit]
, который используется для указания метаданных и зависимостей. Опишите свою службу здесь и скажите системе инициализации, чтобы она запускалась только после достижения цели сети:[Unit] Description=uWSGI instance to serve myproject After=network.target
Затем откройте раздел
[Service]
. Это укажет пользователя и группу, под которой вы хотите запустить процесс. Дайте вашей обычной учетной записи пользователя право собственности на процесс, поскольку она владеет всеми соответствующими файлами. Также передайте групповое владение группеwww-data
, чтобы Nginx мог легко взаимодействовать с процессами uWSGI. Не забудьте заменить имя пользователя здесь своим именем пользователя:[Unit] Description=uWSGI instance to serve myproject After=network.target [Service] User=sammy Group=www-data
Затем наметьте рабочий каталог и установите переменную окружения
PATH
, чтобы система инициализации знала, что исполняемые файлы процесса находятся в вашей виртуальной среде. Также укажите команду для запуска службы. Systemd требует, чтобы вы указали полный путь к исполняемому файлу uWSGI, который установлен в вашей виртуальной среде. Вы передадите имя файла конфигурации.ini
, который вы создали в каталоге вашего проекта.Не забудьте заменить имя пользователя и пути проекта своей информацией:
[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, с чем связать эту службу, если вы включите ее запуск при загрузке. Вы хотите, чтобы эта служба запускалась, когда обычная многопользовательская система запущена и работает:[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 Active: active (running) since Mon 2021-10-25 22:34:52 UTC; 14s ago Main PID: 9391 (uwsgi) Tasks: 6 (limit: 1151) CGroup: /system.slice/myproject.service ├─9391 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.i ├─9410 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.i ├─9411 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.i ├─9412 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.i ├─9413 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.i └─9414 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.iЕсли вы получаете какие-либо ошибки, обязательно устраните их, прежде чем продолжить обучение.
Шаг 6 — Настройка Nginx для прокси-запросов
Теперь ваш сервер приложений uWSGI должен быть запущен и работать, ожидая запросов к файлу сокета в каталоге проекта. Теперь вы можете настроить Nginx для передачи веб-запросов в этот сокет с использованием протокола
uwsgi
.Начните с создания нового файла конфигурации блока сервера в каталоге Nginx
sites-available
. Назовите егоmyproject
, чтобы соответствовать остальной части руководства:- sudo nano /etc/nginx/sites-available/myproject
Откройте блок сервера и скажите Nginx прослушивать порт по умолчанию
80
. Также скажите ему использовать этот блок для запросов доменного имени вашего сервера:server { listen 80; server_name your_domain www.your_domain; }
Затем добавьте блок местоположения, соответствующий каждому запросу. В этот блок вы включите файл
uwsgi_params
, в котором указаны некоторые общие параметры uWSGI, которые необходимо установить. Затем вы будете передавать запросы в сокет, который вы определили с помощью директивыuwsgi_pass
: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
, поэтому вы можете удалить это правило:- sudo ufw delete allow 5000
После этого вы разрешите доступ к серверу Nginx:
- sudo ufw allow 'Nginx Full'
Теперь вы должны иметь возможность перейти к доменному имени вашего сервера в веб-браузере:
http://your_domain
Вы должны увидеть вывод вашего приложения:
Если вы столкнулись с какими-либо ошибками, попробуйте проверить следующее:
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.
Шаг 7 — Защита приложения
Чтобы трафик на ваш сервер оставался безопасным, вы должны получить SSL-сертификат для своего домена. Есть несколько способов сделать это, в том числе получить бесплатный сертификат от Как защитить Nginx с помощью Let’s Encrypt в 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 2022-01-24. 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’s Encrypt.
Flask — чрезвычайно гибкий фреймворк, предназначенный для предоставления вашим приложениям функциональности, не слишком ограничивая структуру и дизайн. Вы можете использовать общий стек, описанный в этом руководстве, для обслуживания приложений flask, которые вы хотите разработать.
- Запись A с