Как обслуживать приложения Flask с помощью Gunicorn и 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-адрес вашего сервера.
Знакомство со спецификацией WSGI, которую сервер Gunicorn будет использовать для связи с вашим приложением Flask. В этом обсуждении WSGI рассматривается более подробно.
Шаг 1 — Установка компонентов из репозиториев Ubuntu
Первый шаг — установить все необходимые пакеты из стандартных репозиториев Ubuntu. Это включает в себя
pip
, менеджер пакетов Python, который будет управлять вашими компонентами Python. Вы также получите файлы разработки Python, необходимые для создания некоторых компонентов Gunicorn.Сначала обновите локальный пакет:
- 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)\ssammy@host:~/myproject$
Шаг 3 — Настройка приложения Flask
Теперь, когда вы находитесь в виртуальной среде, вы можете установить Flask и Gunicorn и приступить к разработке своего приложения.
Сначала установите
wheel
с локальным экземпляромpip
, чтобы убедиться, что ваши пакеты будут установлены, даже если в них отсутствуют архивы колес:- pip install wheel
Примечание. Независимо от используемой версии Python при активации виртуальной среды следует использовать команду
pip
(неpip3
).Затем установите Flask и Gunicorn:
- pip install gunicorn flask
Теперь, когда у вас есть Flask, вы можете создать базовое приложение на следующем шаге.
Создание примера приложения
Поскольку Flask — это микрофреймворк, он не включает многие инструменты, которые могут быть в более полнофункциональных фреймворках. Flask в основном существует как модуль, который вы можете импортировать в свои проекты, чтобы помочь в инициализации веб-приложения.
Хотя ваше приложение может быть более сложным, мы создадим наше приложение Flask в одном файле с именем
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
иENTER
.Если вы следовали руководству по первоначальной настройке сервера в предварительных требованиях, у вас должен быть включен брандмауэр UFW. Для тестирования приложения сначала необходимо разрешить доступ к порту
5000
:- sudo ufw allow 5000
Затем вы можете протестировать свое приложение Flask, выполнив следующее:
- python myproject.py
Вы получите вывод, подобный следующему, включая полезное предупреждение, напоминающее вам не использовать эту настройку сервера в рабочей среде:
Output* Serving Flask app 'myproject' (lazy loading) * Environment: production WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. * Debug mode: off * Running on all addresses. WARNING: This is a development server. Do not use it in a production deployment. * Running on http://your_server_ip:5000/ (Press CTRL+C to quit)Посетите IP-адрес вашего сервера, а затем
:5000
в веб-браузере:http://your_server_ip:5000
Вы должны получить что-то вроде следующего:
Когда вы закончите, нажмите
CTRL + C
в окне терминала, чтобы остановить сервер разработки Flask.Создание точки входа WSGI
Затем создайте файл, который будет служить точкой входа для вашего приложения. Это сообщит вашему серверу Gunicorn, как взаимодействовать с приложением.
Создайте новый файл с помощью предпочитаемого вами текстового редактора и назовите его. Здесь мы назовем файл
wsgi.py
:- nano ~/myproject/wsgi.py
В этом файле импортируйте экземпляр Flask из вашего приложения, а затем запустите его:
from myproject import app if __name__ == "__main__": app.run()
Сохраните и закройте файл, когда закончите.
Шаг 4 — Настройка Gunicorn
Теперь ваше приложение написано с установленной точкой входа, и вы можете приступить к настройке Gunicorn.
Но сначала перейдите в соответствующий каталог:
- cd ~/myproject
Затем вы можете проверить, может ли Gunicorn правильно обслуживать приложение, передав ему имя вашей точки входа. Он создается как имя модуля (минус расширение
.py
) плюс имя вызываемого объекта в приложении. В нашем случае это записывается какwsgi:app
.Вы также укажете интерфейс и порт для привязки, чтобы приложение запускалось на общедоступном интерфейсе:
- gunicorn --bind 0.0.0.0:5000 wsgi:app
Вы получите следующий вывод:
Output[2021-11-19 23:07:57 +0000] [8760] [INFO] Starting gunicorn 20.1.0 [2021-11-19 23:07:57 +0000] [8760] [INFO] Listening at: http://0.0.0.0:5000 (8760) [2021-11-19 23:07:57 +0000] [8760] [INFO] Using worker: sync [2021-11-19 23:07:57 +0000] [8763] [INFO] Booting worker with pid: 8763 [2021-11-19 23:08:11 +0000] [8760] [INFO] Handling signal: int [2021-11-19 23:08:11 +0000] [8760] [INFO] Shutting down: MasterПосетите IP-адрес вашего сервера с
:5000
, добавленным в конце, в веб-браузере еще раз:http://your_server_ip:5000
Вывод вашего приложения будет генерировать следующее:
Убедившись, что он работает правильно, нажмите
CTRL + C
в окне терминала.Поскольку вы закончили работу с виртуальной средой, деактивируйте ее:
- deactivate
Любые команды Python теперь снова будут использовать системную среду Python.
Затем создайте файл сервисной единицы systemd. Создание файла модуля systemd позволит системе инициализации Ubuntu автоматически запускать Gunicorn и обслуживать приложение Flask при каждой загрузке сервера.
Создайте юнит-файл, оканчивающийся на
.service
, в каталоге/etc/systemd/system
, чтобы начать:- sudo nano /etc/systemd/system/myproject.service
Внутри начните с раздела
[Unit]
, который используется для указания метаданных и зависимостей. Добавьте здесь описание вашей службы и сообщите системе инициализации, чтобы она запускалась только после достижения цели сети:[Unit] Description=Gunicorn instance to serve myproject After=network.target
Затем создайте раздел
[Service]
. Это укажет пользователя и группу, под которой вы хотите запустить процесс. Предоставьте право собственности на процесс своей обычной учетной записи пользователя, поскольку он владеет всеми соответствующими файлами. Кроме того, передайте групповое владение группе www-data, чтобы Nginx мог взаимодействовать с процессами Gunicorn. Не забудьте заменить имя пользователя здесь своим именем пользователя:[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, установленному в вашей виртуальной среде.
Не забудьте заменить имя пользователя и пути проекта своей информацией:
[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, с чем связать эту службу, если вы включите ее запуск при загрузке. Вы хотите, чтобы эта служба запускалась, когда обычная многопользовательская система запущена и работает:[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 Active: active (running) since Fri 2021-11-19 23:08:44 UTC; 6s ago Main PID: 8770 (gunicorn) Tasks: 4 (limit: 1151) CGroup: /system.slice/myproject.service ├─9291 /home/sammy/myproject/myprojectenv/bin/python3.6 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app ├─9309 /home/sammy/myproject/myprojectenv/bin/python3.6 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app ├─9310 /home/sammy/myproject/myprojectenv/bin/python3.6 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app └─9311 /home/sammy/myproject/myprojectenv/bin/python3.6 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app …Если вы получаете какие-либо ошибки, обязательно устраните их, прежде чем продолжить обучение.
Шаг 5 — Настройка Nginx для прокси-запросов
Теперь ваш сервер приложений Gunicorn должен быть запущен и работать, ожидая запросов к файлу сокета в каталоге проекта. Затем настройте Nginx для передачи веб-запросов в этот сокет, внеся небольшие дополнения в его файл конфигурации.
Начните с создания нового файла конфигурации блока сервера в каталоге Nginx
sites-available
. Мы назовем этоmyproject
, чтобы не противоречить остальной части руководства:- sudo nano /etc/nginx/sites-available/myproject
Откройте блок сервера и скажите Nginx прослушивать порт по умолчанию
80
. Кроме того, скажите ему использовать этот блок для запросов доменного имени вашего сервера:server { listen 80; server_name your_domain www.your_domain; }
Затем добавьте блок местоположения, соответствующий каждому запросу. В этот блок включите файл
proxy_params
, в котором указаны некоторые общие параметры проксирования, которые необходимо установить. Затем передайте запросы в сокет, который вы определили с помощью директивыproxy_pass
: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
. Вы можете сделать это, выполнив командуln
и флаг-s
, чтобы создать символическую или мягкую ссылку, а не жесткая ссылка:- 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
: проверяет журналы Gunicorn вашего приложения Flask.
Шаг 6 — Защита приложения
Чтобы трафик на ваш сервер оставался безопасным, вы должны получить SSL-сертификат для своего домена. Есть несколько способов сделать это, в том числе получить бесплатный сертификат из Как создать самозаверяющий SSL-сертификат для Nginx в Ubuntu 18.04. Мы пойдем с вариантом один ради целесообразности.
Сначала установите Certbot с помощью
snap
:- sudo snap install --classic certbot
В выводе будет отображаться текущая версия Certbot и указание на успешную установку:
Outputcertbot 1.21.0 from Certbot Project (certbot-eff✓) installedЗатем создайте символическую ссылку на только что установленный исполняемый файл
/snap/bin/certbot
из каталога/usr/bin/
. Это обеспечит правильную работу командыcertbot
на вашем сервере:- sudo ln -s /snap/bin/certbot /usr/bin/certbot
Certbot предоставляет различные способы получения SSL-сертификатов с помощью подключаемых модулей. Плагин Nginx позаботится о перенастройке Nginx и перезагрузке конфигурации при необходимости. Чтобы использовать этот плагин, введите следующее:
- sudo certbot --nginx -d your_domain -d www.your_domain
Это запускает
certbot
с плагином--nginx
, используя-d
, чтобы указать имена, для которых вы хотите, чтобы сертификат был действительным.Если вы впервые запускаете
certbot
, вам будет предложено ввести адрес электронной почты и принять условия обслуживания. После этогоcertbot
свяжется с сервером Let’s Encrypt, чтобы запросить сертификат для вашего домена. В случае успеха вы получите следующий вывод:OutputSuccessfully received certificate. Certificate is saved at: /etc/letsencrypt/live/jeanellehorcasitasphd.com/fullchain.pem Key is saved at: /etc/letsencrypt/live/jeanellehorcasitasphd.com/privkey.pem This certificate expires on 2022-03-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 foryour_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://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 мог взаимодействовать с ней, а затем настроили сервер приложений Gunicorn для обеспечения этой функции. После этого вы создали служебный файл systemd для автоматического запуска сервера приложений при загрузке. Вы также создали серверный блок Nginx, который передает трафик веб-клиента на сервер приложений для ретрансляции внешних запросов и защищенного трафика на ваш сервер с помощью Let’s Encrypt.
Flask — чрезвычайно гибкий фреймворк, предназначенный для предоставления вашим приложениям функциональности, не слишком ограничивая структуру и дизайн. Вы можете использовать общий стек, описанный в этом руководстве, для обслуживания приложений flask, которые вы разрабатываете.
- Запись A с