Как обслуживать приложения Flask с помощью uWSGI и Nginx в Ubuntu 22.04
Введение
В этом руководстве вы создадите приложение Python, используя Nginx в качестве внешнего обратного прокси-сервера.
Предпосылки
Прежде чем приступить к этому руководству, у вас должно быть:
- Сервер с установленной Ubuntu 22.04 и пользователем без полномочий root с привилегиями sudo. Следуйте нашему руководству по первоначальной настройке сервера.
- Nginx установлен, выполнив шаги с 1 по 3 инструкции Как установить Nginx в Ubuntu 22.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
Виртуальная среда Python — это автономный каталог проекта, который содержит определенные версии Python и модули Python, необходимые для данного проекта. Это полезно для изоляции одного приложения от других в той же системе путем отдельного управления зависимостями каждого из них. На этом шаге вы настроите виртуальную среду Python, из которой вы будете запускать приложение Flask.
Начните с установки пакета
python3-venv
, который установит модульvenv
:- sudo apt install python3-venv
Затем создайте родительский каталог для вашего проекта Flask:
- mkdir ~/myproject
Перейдите в каталог после его создания:
- cd ~/myproject
Создайте виртуальную среду для хранения требований Python вашего проекта Flask, набрав:
- python3.10 -m venv myprojectenv
Это установит локальную копию Python и
pip
в каталог с именемmyprojectenv
в каталоге вашего проекта.Перед установкой приложений в виртуальной среде ее необходимо активировать. Сделайте это, набрав:
- source myprojectenv/bin/activate
Ваше приглашение изменится, чтобы показать, что вы сейчас работаете в виртуальной среде. Это будет выглядеть примерно так:
(myprojectenv)user@хост:~/myproject$
.Шаг 3 — Настройка приложения Flask
Теперь, когда вы находитесь в виртуальной среде, вы можете установить Flask и uWSGI, а затем приступить к разработке своего приложения.
Сначала установите
wheel
с локальным экземпляромpip
, чтобы убедиться, что ваши пакеты будут установлены, даже если в них отсутствуют архивы колес:- pip install wheel
Примечание. Независимо от используемой версии Python при активации виртуальной среды следует использовать команду
pip
(неpip3
).Затем установите Flask и uWSGI:
- pip install uwsgi flask
Создание примера приложения
Теперь, когда у вас есть Flask, вы можете создать образец приложения. Flask — это микрофреймворк. Он не включает многие из инструментов, которые могут быть в более полнофункциональных фреймворках, и существует в основном как модуль, который вы можете импортировать в свои проекты, чтобы помочь вам в инициализации веб-приложения.
Хотя ваше приложение может быть более сложным, в этом примере вы создадите приложение Flask в одном файле с именем
myproject.py
. Откройтеmyproject.py
с помощьюnano
или вашего любимого текстового редактора:- 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
, а затемВВОД
.Если вы следовали руководству по первоначальной настройке сервера, у вас должен быть включен брандмауэр UFW. Для тестирования приложения необходимо разрешить доступ к порту
5000
:- sudo ufw allow 5000
Теперь вы можете протестировать свое приложение Flask, набрав:
- python myproject.py
Вы увидите вывод, подобный следующему, включая полезное предупреждение, напоминающее вам не использовать эту настройку сервера в рабочей среде:
OutputWARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. * Serving Flask app 'myproject' * Debug mode: off * Running on all addresses (0.0.0.0) WARNING: This is a development server. Do not use it in a production deployment. * Running on http://127.0.0.1:5000 * Running on http://your_server: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 правильно обслуживать ваше приложение, передав ему имя вашей точки входа. Он состоит из имени модуля (минус расширение
.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
и установите для него значение true; это очистит сокет, когда процесс остановится:[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.Когда вы закончите, сохраните и закройте файл.
При этом uWSGI настроен в вашей системе. Чтобы дать вам больше гибкости в том, как вы управляете своим приложением Flask, теперь вы можете настроить его для работы в качестве службы systemd.
Шаг 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 (это группа, с которой Nginx работает по умолчанию в Ubuntu). Не забудьте заменить имя пользователя здесь своим именем пользователя:[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 вам необходимо изменить права доступа, поскольку пользователь Nginx
www-data
не сможет по умолчанию читать файлы в вашем домашнем каталоге в Ubuntu 22.04 и новее. Это может помешать вам обслуживать веб-приложения из вашего домашнего каталога. Быстрое решение — изменить группу, связанную с вашим домашним каталогом, с помощьюchgrp
:- sudo chgrp www-data /home/sammy
Это позволит Nginx увидеть содержимое вашего домашнего каталога, которое ему необходимо для доступа к файлу сокета. Ни один из файлов в вашем домашнем каталоге не будет доступен в Интернете.
Теперь вы можете запустить созданную вами службу 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: ena> Active: active (running) since Fri 2022-08-05 17:22:05 UTC; 6s ago Main PID: 4953 (uwsgi) Tasks: 6 (limit: 2327) Memory: 20.9M CPU: 241ms CGroup: /system.slice/myproject.service ├─4953 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.ini ├─4954 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.ini ├─4955 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.ini ├─4956 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.ini ├─4957 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.ini └─4958 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.iniЕсли вы видите какие-либо ошибки, обязательно устраните их, прежде чем продолжить обучение. В противном случае вы можете перейти к настройке установки Nginx для передачи запросов в сокет
myproject.sock
.Шаг 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
Когда вы устанавливаете Nginx, процесс автоматически настраивает файл конфигурации блока сервера с именем
default
в каталогеsites-available
, а затем создает символическую ссылку между этим файлом иsites-enabled
каталог. Если вы оставите эту символическую ссылку на месте, конфигурацияпо умолчанию
заблокирует загрузку вашего сайта. Вы можете удалить ссылку с помощью следующей команды:- sudo unlink /etc/nginx/sites-enabled/default
После этого вы можете проверить наличие синтаксических ошибок, набрав:
- sudo nginx -t
Если это возвращается без каких-либо проблем, перезапустите процесс Nginx, чтобы прочитать новую конфигурацию:
- sudo systemctl restart nginx
Наконец, настройте брандмауэр еще раз. Вам больше не нужен доступ через порт
5000
, поэтому вы можете удалить это правило. Затем вы можете разрешить доступ к серверу Nginx:- sudo ufw delete allow 5000
- 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-сертификат для своего домена. Это можно сделать несколькими способами, в том числе получить бесплатный сертификат от Let’s Encrypt, создать самозаверяющий сертификат или купить его у коммерческого поставщика. Для удобства в этом руководстве объясняется, как получить бесплатный сертификат от Let’s Encrypt.
Сначала установите Certbot и его подключаемый модуль Nginx с помощью
apt
:- sudo apt install certbot python3-certbot-nginx
Certbot предоставляет различные способы получения SSL-сертификатов с помощью подключаемых модулей. Плагин Nginx позаботится о перенастройке Nginx и перезагрузке конфигурации при необходимости. Чтобы использовать этот плагин, введите следующее:
- sudo certbot --nginx -d your_domain -d www.your_domain
Это запускает
certbot
с плагином--nginx
, используя-d
, чтобы указать имена, для которых вы хотите, чтобы сертификат был действительным.Если вы впервые запускаете
certbot
на этом сервере, вам будет предложено ввести адрес электронной почты и принять условия обслуживания. После этогоcertbot
свяжется с сервером Let’s Encrypt, а затем запустит вызов, чтобы убедиться, что вы контролируете домен, для которого запрашиваете сертификат.Конфигурация будет обновлена, и Nginx перезагрузится, чтобы принять новые настройки.
certbot
завершится сообщением о том, что процесс прошел успешно и где хранятся ваши сертификаты:OutputSuccessfully received certificate. Certificate is saved at: /etc/letsencrypt/live/your_domain/fullchain.pem Key is saved at: /etc/letsencrypt/live/your_domain/privkey.pem This certificate expires on 2022-11-03. These files will be updated when the certificate renews. Certbot has set up a scheduled task to automatically renew this certificate in the background. Deploying certificate Successfully deployed certificate for your_domain to /etc/nginx/sites-enabled/myproject Successfully deployed certificate for your_domain to /etc/nginx/sites-enabled/myproject Congratulations! You have successfully enabled HTTPS on https://your_domain and https://www.your_domain - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 с